Plugins
App Maker creates a mobile development environment with some dependencies that have proven stable. You may wish to add required modules or third-party services (Analytics, push notification, recommendations, etc.) to this environment. This is where plugins come into play. They allow you to add the modules you need to the environment and write integrations.
When installing native modules to the Environment, some modules are installed automatically. Some require more complex setup processes. For example, a module may require you to add some permissions to AndroidManifest.xml and Info.plist files during installation, or even to add a code block to your application's native files. In order to make complex installations like this, you need to write scripts where you can edit native files.
Plugins have two stages: installation and integration. During the installation stage, required actions are taken for the installation process. The integration phase includes the integration required for the installed module to work with the application's javascript. To develop a plugin with a template that includes these steps, continue reading the next section “Creating a plugin”.
Creating a Plugin
In order to install the environment in which you will develop the plugin, you need to run the following command in the main directory of the project.
appmaker plugin create
Plugin names should be unique and adhere to the formatting akinon-react-native-camera.
Plugin Structure
After running the command appmaker plugin create, a plugin will be created, with the name you specified, in the .plugins directory in your project's main directory. This plugin should look like this.
Installation
In this directory, index.js exports the installation scripts and the npm dependencies that need to be installed as objects.
There should be installation scripts specific to these platforms in the android and ios directories.
android&ios / install.js should contain the installation processes needed by the npm package to be installed. For instance, when you wish to install the package Getting Started | VisionCamera, you should write scripts that will add the necessary permissions for android to AndroidManifest.xml.
The scripts written in the file android&ios / post-install.js run after the npm package is installed in the project. For instance, if you need to do something about the package installed in the ios/Pods directory, it should be done in this file.
You can run these scripts with the command appmaker plugin run ios.
Integration
In this directory, index.js should export a class. If this class has a function called init, this function will be run automatically at the start of the application. You can use the init function to subscribe to Framework services (Analytics, Deeplink).
akinon.plugin.js
This exports installation scripts.
config.json
The plugin may have client-specific configs (API_KEY, CLIENT_ID, etc). Such configs are defined in this file.
Using Plugin in Project
A plugin created with the command appmaker plugin create is automatically set up to be used in your project. The plugin you created in Akinon.json > plugins config should look like this.
{
"plugins": {
"akinon-react-native-camera": {
"name": "akinon-react-native-camera",
"moduleName": "AkinonReactNativeCamera",
"config": {}
}
}
}
name (string)
The name of the plugin is specified in this field. The value written in this field and the folder name of the plugin must be identical.
moduleName (string)
When you wish to use the plugin in a project, the name you need to import is specified in this field.
import Plugins from '_dependencies/plugins';
const { AkinonReactNativeCamera } = Plugins;
config (object)
This field is used to specify the project-specific configs required by the plugin.
Developing a Plugin
When you create the plugin with the command appmaker plugin create, the plugin is ready for development.
When developing the installation scripts of the plugin, you need to edit the files in the project using the Modifiers services. These modifiers may be inaccurate or incomplete during development. It would be costly to restore project files after configuring them incorrectly or incompletely. To avoid this, it is recommended to run the appmaker's command plugin preview while developing installation scripts.
appmaker plugin preview android
You need to add the —post-install parameter to run the post-install scripts of the plugin.
This command shows the changes to be made by the installation scripts you have developed to the project files. It does not edit project files.
After making sure that the installation scripts are working correctly, you can now edit project files. In order to do this, you have to run the command plugin run.
appmaker plugin run android
This command writes the changes seem in the preview command to project files, and the project is ready to be built.
You may wish to develop a plugin without using the command appmaker plugin create. For instance, you may wish to include a plugin written for a different project. You need to clone the plugin you wish to include to the .plugins directory in the main directory of the project and run the command plugin add.
appmaker plugin add name
This command will edit akinon.json for you, enabling you to use the plugin in your project.
You may also wish to develop the plugin you use in a project. When you install a project with the command appmaker project install, the project is set up ready for build. However, you do not wish the plugin you will develop to be installed in the project. In this case, after installing the project, the plugin you wish to develop is cloned to the .plugins directory and this command is run in the project directory.
appmaker project install --exclude-plugins
This command will re-configure the project without the plugin that is cloned under .plugins and defined in the plugins config in akinon.json and will install it ready for build.
After the development is finished, you can run the command plugin run.
appmaker plugin run android
Third Parties
Third-party plugins are a bit more complex than installing other react native plugins. You may also need to use features such as Analytics, and DeepLink for third-party plugins. For such features, Analytics and DeepLink services are available in the framework. You can complete the integration using these services. Check out Example Firebase for a sample case.
Modifiers
Modifying Xcode
You need to use XcodeModifier to edit the project with Xcode. See this document for detailed information.
const { Modifiers, Paths } = require('akinon-plugin-adapter');
const { XcodeModifier } = Modifiers;
class Install {
async modifyXcode() {
const { getPBXProjectPaths } = Paths.ios;
const xcode = new XcodeModifier(getPBXProjectPaths());
xcode.parse();
xcode.updateBuildSettings('IPHONEOS_DEPLOYMENT_TARGET', '12.0', "akinon");
return xcode.writeAsync();
}
async start() {
await this.modifyXcode();
}
}
You can try the following steps to make it easier to write scripts for Xcode.
- Open a project with Xcode.
- Make the related changes with Xcode and run the command appmaker project diff ios. This command will show the Xcode changes. You can write scripts based on these changes.
- Run the command appmaker project reset ios to undo Xcode changes. This command will reset the ios changes.
Modifying Info.plist
You need to use PlistModifier to edit the Info.plist files. See this document for detailed information.
const { Modifiers, Paths } = require('akinon-plugin-adapter');
const { PlistModifier } = Modifiers;
class Install {
async modifyPlist() {
const { getInfoPlist } = Paths.ios;
const infoPlist = new PlistModifier(getInfoPlist());
const parsedPlist = await infoPlist.readAsync();
parsedPlist["NSCameraUsageDescription"] = "This app requires access to the camera."
return infoPlist.writeAsync(parsedPlist);
}
async start() {
await this.modifyPlist();
}
}
Modifying Podfile
You need to use PodModifier to edit the Podfile file. See this document for detailed information.
const { Modifiers, Paths } = require('akinon-plugin-adapter');
const { PodModifier } = Modifiers;
class Install {
async modifyPodfile() {
const { getPodFile } = Paths.ios;
const podFile = new PodModifier(getPodfile());
podFile.addToTarget("akinon", "Pod 'Yoga' ");
return podFile.writeAsync();
}
async start() {
await this.modifyPodfile();
}
}
Modifying AppDelegate
You need to use AppDelegateModifier to edit the AppDelegate.h and AppDelegate.m files. See this document for detailed information.
const { Modifiers, Paths } = require('akinon-plugin-adapter');
const { AppDelegateModifier } = Modifiers;
class Install {
async modifyAppDelegate() {
const { getAppDelegate } = Paths.ios;
const appDelegate = new AppDelegateModifier(getAppDelegate());
appDelegate.addImports(['#import "AppDelegate.h"']);
return appDelegate.writeAsync();
}
async start() {
await this.modifyAppDelegate();
}
}
Modifying AndroidManifest.xml
You need to use XMLModifier to edit AndroidManifest and other xml files. See this document for detailed information.
const { Modifiers, Paths } = require('akinon-plugin-adapter');
const { XMLModifier } = Modifiers;
class Install {
async modifyManifest() {
const { getManifest } = Paths.android;
const manifest = new XMLModifier(getManifest());
const xml = await manifest.parseAsync();
xml.manifest['uses-permission'].push({
$: {
'android:name': "android.permission.ACCESS_FINE_LOCATION"
}
})
return manifest.writeAsync(xml);
}
async start() {
await this.modifyManifest();
}
}
Modifying Gradle
You need to use GradleModifier to edit the Build.gradle file. See this document for detailed information.
const { Modifiers, Paths } = require('akinon-plugin-adapter');
const { GradleModifier } = Modifiers;
class Install {
async modifyGradle() {
const { getBuildGradle } = Paths.android;
const gradle = new GradleModifier(getBuildGradle());
gradle.addDependencies(` maven {url 'http://developer.huawei.com/repo/'}`);
return gradle.writeAsync();
}
async start() {
await this.modifyGradle();
}
}
Modifying MainApplication.java
You need to use JavaModifier to edit the MainApplication.java file. See this document for detailed information.
const { Modifiers, Paths } = require('akinon-plugin-adapter');
const { JavaModifier } = Modifiers;
class Install {
async modifyMainApplication() {
const { getMainApplication } = Paths.android;
const mainApplication = new JavaModifier(getMainApplication());
mainApplication.addImports("java.util.List", "java.util.Arrays");
return mainApplication.writeAsync();
}
async start() {
await this.modifyMainApplication();
}
}
Modifying Other Files
You have to use FileModifier to change different file types. You can also use the features of this modifier in other defined Modifier services. Occasionally, the modifier you use may not fully meet your needs. In such cases, you can use custom Regex patterns with FileModifier methods.
As an example, you can refer to AppDelegateModifier's applyPatch method below.
const { Modifiers, Paths } = require('akinon-plugin-adapter');
const { AppDelegateModifier } = Modifiers;
class Install {
async modifyAppDelegateHeader() {
const { getAppDelegate } = Paths.ios;
const appDelegate = new AppDelegateModifier(getAppDelegateHeader());
appDelegate.addImports(['#import UserNotifications/UNUserNotificationCenter.h']);
appDelegate.applyPatch({
pattern: /(@interface AppDelegate(.*))+(?=>)/,
patch: ', UNUserNotificationCenterDelegate'
});
return appDelegate.writeAsync();
}
async start() {
await this.modifyAppDelegateHeader();
}
}
Regex patterns may no be compatible with the plugins you’ve developed or the changes incoming with the new environment version.
Example React Native Camera
Let's assume we are developing a plugin for the react-native-camera
dependency.
Installation
During installation, setup processes for third-party libraries are completed. This includes adding dependencies to package.json
and modifying native files.
1. Create Plugin
Run the following command to create a new plugin:
→ app-maker plugin create
You will be prompted to provide a name for the plugin. Enter the plugin name:
→ akinon-react-native-vision-camera
This command will generate a plugin under the directory: .plugins/akinon-react-native-vision-camera
.
2. Install npm Package
npm packages should be added to the project's package.json
file. To do this, define the names and versions of the required npm packages in the specified directory.
// .plugins/akinon-react-native-vision-camera/installation/index.js
module.exports = {
dependencies: {
"react-native-vision-camera": "2.15.4",
},
...
};
3. Android Installation
The akinon-plugin-adapters
package simplifies the process with services like Modifiers
and Paths
. Refer to the documentation for more details.
Add the required permissions (android.permission.CAMERA
and android.permission.RECORD_AUDIO
) to the android/app/src/main/AndroidManifest.xml
file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.akinon.shop"
android:versionCode="1" android:versionName="1.0.0">
// other permissions
<uses-permission android:name="android.permission.CAMERA" /> // Add me --- /\
<!-- optionally, if you want to record audio: -->
<uses-permission android:name="android.permission.RECORD_AUDIO" /> // Add me --- /\
</manifest>
Automate this modification with the following script:
// .plugins/akinon-react-native-vision-camera/installation/android/install.js
const { Paths, Modifiers } = require('akinon-plugin-adapter');
const { XMLModifier } = Modifiers;
class Install {
constructor(plugin) {}
addPermissions(xml, permissions) {
permissions.forEach((permission) =>
xml.manifest['uses-permission'].push({ $: { 'android:name': permission } })
);
}
async modifyAndroidManifest() {
const mod = new XMLModifier(Paths.android.getManifest());
let xml = await mod.parseAsync();
this.addPermissions(xml, [
'android.permission.CAMERA',
'android.permission.RECORD_AUDIO'
]);
return mod.writeAsync(xml);
}
async start() {
await this.modifyAndroidManifest();
}
}
exports.default = Install;
4. iOS Installation
Add the permissions (NSCameraUsageDescription
and NSMicrophoneUsageDescription
) to ios/akinon/Info.plist
:
// ios/akinon/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
// ...
// Add me --- \/
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) needs access to your Camera.</string>
<!-- optionally, if you want to record audio: -->
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) needs access to your Microphone.</string>
// Add me --- /\
</dict>
</plist>
Automate this modification with the following script:
// .plugins/akinon-react-native-vision-camera/installation/ios/install.js
const { Paths, Modifiers } = require('akinon-plugin-adapter');
const { PlistModifier } = Modifiers;
class Install {
constructor(plugin) {}
async modifyInfoPlist() {
const mod = new PlistModifier(Paths.ios.getInfoPlist());
const plist = await mod.readAsync();
plist.NSCameraUsageDescription = '$(PRODUCT_NAME) needs access to your Camera.';
plist.NSMicrophoneUsageDescription = '$(PRODUCT_NAME) needs access to your Microphone.';
return mod.writeAsync(plist);
}
async start() {
await this.modifyInfoPlist();
}
}
exports.default = Install;
Preview and Run Installation
Preview installation scripts without making changes to files:
app-maker plugin preview ios && app-maker plugin preview android
Run the installation scripts:
app-maker plugin run ios && app-maker plugin run android
Integration
After completing the installation phase, you need to write a JavaScript integration to utilize third-party libraries in your application.
Camera Component
The Camera component you want to use in the application should be developed in the integration layer.
First, create the index.js
file under .plugins/akinon-react-native-vision-camera/integration/camera
to utilize the react-native-vision-camera
dependency
:
//`.plugins/akinon-react-native-vision-camera/integration/camera/index.js`
import { Camera as NativeCamera, useCameraDevices } from 'react-native-vision-camera';
import { ReactNative, React } from '_dependencies';
const { StyleSheet, TouchableOpacity, Text } = ReactNative;
const { useEffect, useState } = React;
const Camera = () => {
const devices = useCameraDevices();
const [permissions, setPermissions] = useState({
camera: "denied",
microphone: "denied",
});
const requestPermissions = async () => {
const newCameraPermission = await NativeCamera.requestCameraPermission();
const newMicrophonePermission = await NativeCamera.requestMicrophonePermission();
setPermissions({
camera: newCameraPermission,
microphone: newMicrophonePermission,
});
};
const checkPermissions = async () => {
const cameraPermission = await NativeCamera.getCameraPermissionStatus();
const microphonePermission = await NativeCamera.getMicrophonePermissionStatus();
setPermissions({
camera: cameraPermission,
microphone: microphonePermission,
});
};
useEffect(() => {
checkPermissions();
}, []);
const device = devices.back;
if (device == null) return <Text>Loading</Text>;
if (permissions.camera === 'denied')
return (
<TouchableOpacity onPress={requestPermissions}>
<Text>Request Permissions</Text>
</TouchableOpacity>
);
return <NativeCamera isActive={true} style={StyleSheet.absoluteFill} device={device} />;
};
export default Camera;
Export and Use the Component:
To use the component you created within the src
layer, you need to export it in the .plugins/akinon-react-native-vision-camera/integration/index.js
file.
import Camera from './camera';
export default {
Camera
};
You can use the Camera component you created in the src
layer at the desired location, as shown in the example below:
import { React, AsyncStorage, RnSafeAreaContext } from '_dependencies';
import { Container } from '@elements';
import Plugins from '_dependencies/plugins.js'; // Add me --- /\
const {Camera} = Plugins.AkinonReactNativeVisionCamera; // Add me --- /\
const HomePage = ({}) => {
return (
<Container className="homePage.gridElements.container" excludeEdges={['top']}>
<Camera /> // Add me --- /\
</Container>
);
};
export default HomePage;
Example Firebase
Let’s say we ‘re developing a plugin for Firebase.
Installation
During the installation phase, the setup processes of the third party are completed. These processes include, among others, adding dependency to package.json and modifying native files.
- Create Plugin
appmaker plugin create
Plugin name will be asked after running this command. Name of the plugin should be entered.
akinon-react-native-firebase
Running this command will create a plugin in the project’s .plugins/akinon-react-native-firebase directory.
- Install npm Package
- @react-native-firebase/app
- @react-native-firebase/analytics
- @react-native-firebase/messaging
The npm packages must be added to the project's package.json file. In order to do this, the name and versions of npm packages are defined in the specified directory.
// .plugins/akinon-react-native-firebase/installation/index.js
module.exports = {
dependencies: {
"@react-native-firebase/app": "14.11.1",
"@react-native-firebase/analytics": "14.11.1",
"@react-native-firebase/messaging": "14.11.1"
},
...
};
- Android Installation
You need to download google-services.json file from Firebase console and place it in /android/app/google-services.json directory.
In Akinon.json, you can write the path of the google-service file in the plugin config. (You can also write to a field other than Akinon.json.)
// akinon.json
{
"plugins": {
"akinon-react-native-firebase": {
...,
"config": {
"android": {
"googleServiceFile": "./src/assets/resources/google-services.json"
}
}
}
}
}
Using the config in Akinon.json, you can write the script to move the google-services.json file to the android/app directory.
// .plugins/akinon-react-native-firebase/installation/android/install.js
const { Modifiers, Paths } = require("akinon-plugin-adapter");
const { FileModifier } = Modifiers;
class Install {
constructor(plugin) {
this.config = plugin.config
}
async copyGoogleServiceFile() {
const file = new FileModifier();
const {
android: { googleServiceFile }
} = this.config;
return file.copyFile(
Paths.project.getPath(googleServiceFile),
`${Paths.android.getAndroidFolder().path}/app/google-services.json`
);
}
async start() {
await this.copyGoogleServiceFile();
}
}
exports.default = Install;
While developing plugins, the akinon-plugin-adapters package simplifies the process with services such as Modifiers, Paths . See this document for more detailed information about these services.
In the file android/build.gradle,** you need to add classpath 'com.google.gms:google-services:4.3.13' service as dependency under buildscript.**
// android/build.gradle
buildscript {
dependencies {
// ... other dependencies
classpath 'com.google.gms:google-services:4.3.13' // Add me --- /\
}
}
For this:
// .plugins/akinon-react-native-firebase/installation/android/install.js
const { Modifiers, Paths } = require("akinon-plugin-adapter");
const { FileModifier, GradleModifier } = Modifiers;
class Install {
constructor(plugin) {
this.config = plugin.config
}
async copyGoogleServiceFile() {
...
}
async modifyBuildGradle() {
const { getBuildGradle } = Paths.android
const gradle = new GradleModifier(getBuildGradle());
const dependencies = `classpath 'com.google.gms:google-services:4.3.13'`;
gradle.addDependencies(dependencies);
return gradle.writeAsync();
}
async start() {
await this.copyGoogleServiceFile();
await this.modifyBuildGradle();
}
}
exports.default = Install;
To the file android/app/build.gradle, you need to add the code apply plugin: 'com.google.gms.google-services' that will enable you to use Google services.
// android/app/build.gradle
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services' // - Add this line
For this:
// .plugins/akinon-react-native-firebase/installation/android/install.js
const { Modifiers, Paths } = require("akinon-plugin-adapter");
const { FileModifier, GradleModifier } = Modifiers;
class Install {
constructor(plugin) {
this.config = plugin.config
}
async copyGoogleServiceFile() {
...
}
async modifyBuildGradle() {
...
}
async modifyAppBuildGradle() {
const { getAppBuildGradle } = Paths.android;
const gradle = new GradleModifier(getAppBuildGradle());
const applies = `apply plugin: 'com.google.gms.google-services'`;
gradle.addApply(applies);
return gradle.writeAsync();
}
async start() {
await this.copyGoogleServiceFile();
await this.modifyBuildGradle();
await this.modifyAppBuildGradle();
}
}
exports.default = Install;
We need to add code to update the value of the com.google.firebase.messaging.default_notification_color meta data in the android/app/src/main/AndroidManifest.xml file.
// android/app/src/main/AndroidManifest.xml
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/iconBackground" /> // Modify android:resource
For this:
// .plugins/akinon-react-native-firebase/installation/android/install.js
const { Modifiers, Paths } = require("akinon-plugin-adapter");
const { FileModifier, GradleModifier, XMLModifier } = Modifiers;
class Install {
constructor(plugin) {
this.config = plugin.config
}
async copyGoogleServiceFile() {
...
}
async modifyBuildGradle() {
...
}
async modifyAppBuildGradle() {
...
}
async modifyManifest() {
const { getManifest } = Paths.android;
const manifest = new XMLModifier(getManifest());
const parsedManifest = await manifest.parseAsync();
const newMetaData = parsedManifest.manifest.application[0]["meta-data"].map((metaData) => {
if (metaData.$["android:name"] === "com.google.firebase.messaging.default_notification_color") {
metaData.$["android:resource"] = "@color/white";
};
return metaData;
});
parsedManifest.manifest.application[0]["meta-data"] = newMetaData;
return manifest.writeAsync(parsedManifest);
};
async start() {
await this.copyGoogleServiceFile();
await this.modifyBuildGradle();
await this.modifyAppBuildGradle();
await this.modifyManifest();
}
}
exports.default = Install;
- iOS Installation
You need to download GoogleService-Info.plist from Firebase console and put it in /ios/akinon/ directory
In Akinon.json, you can write the path of the google-service file in the plugin config.
// akinon.json
{
"plugins": {
"akinon-react-native-firebase": {
...,
"config": {
"ios": {
"googleServiceFile": "./src/assets/resources/GoogleService-Info.plist"
}
}
}
}
}
You can write the script that will move the GoogleService-Info.plist file to the ios/akinon directory by using the config in Akinon.json; however, this will not be enough. When you add a file to the project or change a config with Xcode, changes are made by xcode in the ios/akinon.xcodeproj/project.pbxproj file. You have to make these changes with scripts.
// .plugins/akinon-react-native-firebase/installation/ios/install.js
const { Modifiers, Paths } = require("akinon-plugin-adapter");
const { XcodeModifier } = Modifiers;
class Install {
constructor(plugin) {
this.config = plugin.config
}
async copyGoogleServiceFile() {
const {
ios: { googleServiceFile }
} = this.config;
const { getPBXProjectPaths } = Paths.ios;
const xcode = new XcodeModifier(getPBXProjectPaths());
xcode.parse();
xcode.createFile({
sourcePath: Paths.project.getPath(googleServiceFile),
destinationPath: Paths.ios.getIosFolder().path + "/akinon",
name: "GoogleService-Info.plist",
pbxFilePath: "akinon/GoogleService-Info.plist"
}, "akinon");
return xcode.writeAsync();
}
async start() {
await this.copyGoogleServiceFile();
}
}
exports.default = Install;
After adding the GoogleService-Info.plist file, you need to edit the AppDelegate.m file and initialize Firebase. The code block you want to add is as follows:
// ios/akinon/AppDelegte.mm
#import Firebase.h // Add me
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Add me --- \/
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
// Add me --- /\
...
}
In order to make these changes in the AppDelegate.m file, you need to write a script as shown below.
// .plugins/akinon-react-native-firebase/installation/ios/install.js
const { Modifiers, Paths } = require("akinon-plugin-adapter");
const { XcodeModifier, AppDelegateModifier } = Modifiers;
class Install {
constructor(plugin) {
this.config = plugin.config
}
async copyGoogleServiceFile() {
...
}
async modifyAppDelegate() {
const { getAppDelegate } = Paths.ios;
const appDelegate = new AppDelegateModifier(getAppDelegate());
const patch = `
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}`
const imports = ['#import <Firebase.h>'];
appDelegate.addImports(imports);
appDelegate.applyPatch({
pattern: /didFinishLaunchingWithOptions:.*([\n]{)/gm,
patch
});
return appDelegate.writeAsync();
}
async start() {
await this.copyGoogleServiceFile();
await this.modifyAppDelegate();
}
}
exports.default = Install;
You need to edit the Info.plist file and specify the services that will run in the background. The code block you want to add is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...
// Add me --- \/
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
// Add me --- /\
</dict>
</plist>
To make these changes in the Info.plist file, you need to write a script as shown below.
// .plugins/akinon-react-native-firebase/installation/ios/install.js
const { Modifiers, Paths } = require("akinon-plugin-adapter");
const { XcodeModifier, AppDelegateModifier, PlistModifier } = Modifiers;
class Install {
constructor(plugin) {
this.config = plugin.config
}
async copyGoogleServiceFile() {
...
}
async modifyAppDelegate() {
...
}
async modifyPlist() {
const { getInfoPlist } = Paths.ios;
const mod = new PlistModifier(getInfoPlist());
const plist = await mod.readAsync();
plist['UIBackgroundModes'] = ["fetch", "remote-notification"];
return mod.writeAsync(plist);
}
async start() {
await this.copyGoogleServiceFile();
await this.modifyAppDelegate();
await this.modifyPlist();
}
}
exports.default = Install;
After editing the Info.plist, you need to edit the akinon.entitlements file and configure the environment for Push notifications. The code block you want to add is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...
// Add me --- \/
<key>aps-environment</key>
<string>development</string>
// Add me --- /\
</dict>
</plist>
To make these changes in the akinon.entitlements file, you need to write a script as shown below.
// .plugins/akinon-react-native-firebase/installation/ios/install.js
const { Modifiers, Paths } = require("akinon-plugin-adapter");
const { XcodeModifier, AppDelegateModifier, PlistModifier } = Modifiers;
class Install {
constructor(plugin) {
this.config = plugin.config
}
async copyGoogleServiceFile() {
...
}
async modifyAppDelegate() {
...
}
async modifyPlist() {
...
}
async modifyEntitlements() {
const { getEntitlements } = Paths.ios;
const mod = new PlistModifier(getEntitlements());
const plist = await mod.readAsync();
plist['aps-environment'] = 'development';
return mod.writeAsync(plist);
}
async start() {
await this.copyGoogleServiceFile();
await this.modifyAppDelegate();
await this.modifyPlist();
await this.modifyEntitlements();
}
}
exports.default = Install;
In order to run the installation scripts:
appmaker plugin run ios && appmaker plugin run android
This command is run in the project directory and Firebase installation is completed.
Integration
After the installation phase is finalized, you need to write javascript integration to use the third party in the application.
Analytics
Let’s say we’re writing this integration for Firebase Analytics.
Analytics | React Native Firebase
Subscribe your analytics integration to Framework’s AnalyticsService.
// .plugins/akinon-react-native-firebase/integration/index.js
import AnalyticsService from '@services/analytics/service';
import Analytics from "./analytics";
class Firebase {
init() {
AnalyticsService.subscribe("FirebaseAnalytics", new Analytics());
}
}
export default new Firebase();
The init function runs before the application is rendered. This function is useful in cases such as subscribe operations and third party sdk initialize.
Initially, the init function of the integration runs when the Analytics service is ready. This function enables analytics-specific initialization operations. The remove function works when the Analytics service is unmounted from the application.
// .plugins/akinon-react-native-firebase/integration/analytics/index.js
class Analytics {
init() {
}
remove() {
}
}
export default Analytics;
If you wish to send an event to firebase when you view a product:
// .plugins/akinon-react-native-firebase/integration/analytics/index.js
import analytics from '@react-native-firebase/analytics';
class Analytics {
...
static async productImpression(nextState, prevState, payload) {
const { productDetail = {}} = nextState;
const { product = {}} = productDetail;
const item = {
item_id: product.sku,
item_name: product.name,
item_category: product.attributes.category,
item_variant: product.attributes.color,
item_brand: product.brand,
price: product.price
}
await analytics().logEvent("view_item", item);
}
}
export default Analytics;
When the Product Detail page is opened, the integrated productImpression function will run automatically. You can find all the data about the product in the nextState parameter. Click to access Analytics functions.
Deep Link
Subscribe your deeplink integration to Framework’s DeepLinkService.
// .plugins/akinon-react-native-firebase/integration/index.js
import DeepLinkService from '@services/deepLink';
import DeepLink from "./deepLink";
class Firebase {
init() {
AnalyticsService.subscribe("FirebaseAnalytics", new Analytics());
DeepLinkService.subscribe("FirebaseNotification", new DeepLink());
}
}
export default new Firebase();
Initially, the init function of the integration runs when the DeepLink service is ready. This function enables deeplink-specific initialization operations. The remove function works when the DeepLink service is unmounted from the application.
// .plugins/akinon-react-native-firebase/integration/deepLink/index.js
class DeepLink {
init() {
}
remove() {
}
}
export default DeepLink;
Let's say we’re sending a push notification to the application using Firebase messaging. With push notification, you may wish to direct users to pages such as product list and product detail. In order to do this, you can access the push notification payload by using Firebase messaging's listeners in the init function. Through the publishNotificationOpen method of DeepLinkService, you can redirect to the relevant page when the notification is opened.
// .plugins/akinon-react-native-firebase/integration/deepLink/index.js
import messaging from '@react-native-firebase/messaging';
import DeepLinkService from '@services/deepLink';
class DeepLink {
init() {
messaging().onMessage(async notificationPayload => {
DeepLinkService.publishNotificationOpen({
url: notificationPayload.data.url,
foreground: false
});
});
}
}
export default DeepLink;
Analytics Events
When you create a method with the following events for the analytics service you have developed, the created method will be triggered when the action type associated with the event is ignited.
User
Action Type | Event Name |
---|---|
FETCH_CURRENT_USER_FULFILLED_FOR_LOGIN | userLogin |
CLEAR_AUTH_STATE | userLogout |
FETCH_CURRENT_USER_FULFILLED_FOR_INDEX | currentUser |
Basket
Action Type | Event Name |
---|---|
FETCH_BASKET_FULFILLED | basketImpression |
FETCH_BASKET_FULFILLED_TO_UPDATE | cartChanges |
FETCH_BASKET_DISCOUNT | couponUsed |
BASKET_ADD_TO_FAVOURITE_FULFILLED | addToFavOnBasket |
ADDED_TO_CART_FULFILLED | addedToCart |
Orders
Action Type | Event Name |
---|---|
CANCELLATION_REQUEST | cancelOrder |
Product Detail
Action Type | Event Name |
---|---|
PD_ADD_TO_FAVOURITE_FULFILLED | addToFavOnPd |
PD_REMOVE_FROM_FAVOURITE_FULFILLED | removeFromFavOnPd |
FETCH_PRODUCT_DETAIL_FULFILLED | productImpression |
Product List
Action Type | Event Name |
---|---|
PL_ADD_TO_FAVOURITE_FULFILLED | addToFavOnPd |
FETCH_PRODUCT_LIST_FULFILLED | productsImpressions |
PL_REMOVE_FROM_FAVOURITE_FULFILLED | removeFromFavOnPl |
SET_SORTER | setSorter |
Register
Action Type | Event Name |
---|---|
REGISTER_COMPLETED | userRegister |
Search
Action Type | Event Name |
---|---|
FETCH_SEARCH_FULFILLED | searched |
Checkout Success
Action Type | Event Name |
---|---|
WEB_CHECKOUT_OPENED | checkoutImpression |
FETCH_CHECKOUT_COMPLETED_SUCCESS | measuringPurchases, measuringFirstPurchase, addShippingInfo, addPaymentInfo |
FIRST_PURCHASE_ORDERED | firstPurchaseOrdered |