accurat-sdk-react-native
v0.1.0
Published
React Native wrapper for Accurat SDK
Downloads
2
Readme
Accurat React Native SDK
This README contains instructions on how to integrate the React Native wrapper for the Accurat iOS and Android SDK into your React Native project.
Contents
Installation
$ npm install accurat-sdk-react-native --save
# or
$ yarn add accurat-sdk-react-native
Native Android Set-up
Requirements
- Android minSdkVersion 19+ (KitKat)
- Android targetSdkVersion 29+ (Q)
Optional requirements
- Android targetSdkVersion 30+: Targeting API 30 or higher will prevent an additional system pop-up when asking background location.
Add repository to project
Add the following to your Android project's build.gradle
file:
allprojects {
repositories {
maven {
url 'https://maven.accurat.ai/maven2/'
}
}
}
Add a permission handler
Pass along the permission request results to the Accurat module, so we can show permission dialogs and handle them.
Add the following code to your MainActivity.java
:
import com.accuratsdkreactnative.AccuratSdkReactNativeModule;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
boolean handled = AccuratSdkReactNativeModule.Companion.handlePermissionResult(requestCode, permissions, grantResults, this);
if (!handled) {
// Let your own app handle any other permissions
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
Native iOS Set-up
Configure project
In your project settings, go to Capabilities > Background Modes and turn on Background fetch.
Then, add appropriate location usage descriptions to the Info.plist
of your application. These strings will be displayed when prompting the user for location permissions.
For Xcode 14:
<key>NSLocationAlwaysUsageDescription</key>
<string>This makes it possible to send you notifications with relevant info, even when you are not using the app.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>That way, we can personalize the content and ads in the app based on your preferences.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This makes it possible to send you notifications with relevant info, even when you are not using the app.</string>
In order to support multiple languages, create a InfoPlist.strings
file in the <language>.lproj
directories for each language you want to support.
Example languages:
en.lproj
NSLocationAlwaysUsageDescription = "This makes it possible to send you notifications with relevant info, even when you are not using the app.";
NSLocationWhenInUseUsageDescription = "That way, we can personalize the content and ads in the app based on your preferences.";
NSLocationAlwaysAndWhenInUseUsageDescription = "This makes it possible to send you notifications with relevant info, even when you are not using the app.";
nl.lproj
NSLocationAlwaysUsageDescription = "Zo is het mogelijk om u notificaties te versturen met gepersonaliseerde inhoud, ook wanneer u de app niet gebruikt.";
NSLocationWhenInUseUsageDescription = "Zo kunnen we in de app de inhoud en advertenties personaliseren op maat van jouw voorkeuren.";
NSLocationAlwaysAndWhenInUseUsageDescription = "Zo is het mogelijk om u notificaties te versturen met gepersonaliseerde inhoud, ook wanneer u de app niet gebruikt.";
fr.lproj
NSLocationAlwaysUsageDescription = "Il est donc possible de vous envoyer des notifications avec un contenu personnalisé, même lorsque vous n'utilisez pas l'application.";
NSLocationWhenInUseUsageDescription = "Comme ça, nous pouvons personnaliser le contenu et les publicités dans l'app en fonction de vos préférences.";
NSLocationAlwaysAndWhenInUseUsageDescription = "Il est donc possible de vous envoyer des notifications avec un contenu personnalisé, même lorsque vous n'utilisez pas l'application.";
Manually add these files to the project bundle. This can be achieved via right-clicking the project name in Xcode and choosing the Add files to X option, then selecting the files.
Add SDK
Add the following to your Podfile:
target '<Your Target Name>' do
pod 'Accurat', :git => 'https://gitlab.com/accuratai/pod-ios'
end
Next install pods to run following command from the iOS folder:
$ pod install
Fetch location in the background (required)
Implement the following method in your AppDelegate
:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
Accurat.shared.performBackgroundFetchWithCompletionHandler(completionHandler)
}
Usage
Import the SDK
import Accurat from 'accurat-sdk-react-native';
Initialize SDK (required)
Initialize the SDK by calling the Accurat.initialize
-method and providing it with a config object:
type Accurat.Config = {
username: string;
password: string;
appVersion: string;
features?: Accurat.Feature[];
debugLogs?: boolean;
};
Accurat.initialize(config: Accurat.Config): Promise<boolean>
Where:
username
andpassword
are strings containing your Accurat username and password.appVersion
is your app version.features
is an optional array which indicates the consents that will be asked by the SDK (see Consent Flow section). Features that are left out, should be handled by your own app code.debugLogs
is an optional boolean which indicates if debug logs should be shown in Android Studio or XCode. The default isfalse
.
This method returns a promise which resolves in true
if Accurat initialized succesfully. And rejects when the configuration is invalid.
Start Tracking (required)
Call Accurat's startTracking-method to start tracking. If features
were added during initialization, this will also trigger the consent flow (see Consent Flow section).
Accurat.startTracking(): Promise<boolean>
This method returns a promise of a boolean which lets you know whether the tracking could be started or not. Possible reasons for Accurat not being able to start are: No internet connection or the user refused one or more consents. This method has to be called each time the app opens (when you want to track the user).
Consent Flow (required)
Before the SDK starts tracking the users' coordinates, two consents have to be given by the user:
- The GDPR consent, which is a legal consent that is required to process personal data.
- The location consent, which is a technical consent that is required to be able to collect location data of the user.
Asking the consents can be implemented by the SDK (recommended) or by the app developer.
Implemented by SDK
When the Accurat.Feature.GDPR_CONSENT
and Accurat.Feature.LOCATION_PERMISSION
features are given to the features
-array during the initialization, a flow which ask these consents is automatically started when the startTracking
-method is called.
First, the user is asked for the GDPR consent through a pop-up screen. Second, if the user agrees to the GDPR consent, pop-up dialogs are shown to ask their permission to retrieve their locations. If the user gives GDPR consent and location permission, the tracking is started.
There is some functionality added to increase the conversion rate (users giving their gdpr and location consent):
- If the user does not give their consent, the user is asked for the consent again with a delay of at least 48 hours. The consent is asked 3 times at most.
- Before showing the pop-up which asks the location permission, we explain why the user should give their permission.
The texts shown in the popup-screens and the number of retries (default 3) can be changed through our backend.
This entire flow can be implemented by adding this code to your App
component:
import Accurat from 'accurat-sdk-react-native';
React.useEffect(() => {
const config: Accurat.Config = {
username: ACCURAT_USERNAME,
password: ACCURAT_PASSWORD,
appVersion: APP_VERSION,
features: [
Accurat.Feature.GDPR_CONSENT,
Accurat.Feature.LOCATION_PERMISSION,
],
};
Accurat.initialize(config).then(() => {
Accurat.startTracking().then((started) => {
// Your code for reacting to the SDK started event
});
});
}, []);
Manually implemented by App Developer
The consents can also be asked by the app developer in the existing flow of your app. Note that the tracking will only work if the SDK receives an accepted gdpr and location consent.
GDPR Consent
The GDPR consent state can be updated by calling the updateConsent()
-method and provide a consent type and consent state:
Accurat.updateConsent(
consentType: Accurat.ConsentType,
consentState: Accurat.ConsentState,
): Promise<boolean>
Where:
consentType
isAccurat.ConsentType.GDPR
consentState
is one ofAccurat.ConsentState.ACCEPTED
orAccurat.ConsentState.REFUSED
This method returns a promise of a boolean which lets you know whether the update was successful or not.
If you want to get the state of the GDPR consent, call the getConsentState()
-method and provide a consent type:
Accurat.getConsentState(
consentType: Accurat.ConsentType,
): Promise<Accurat.ConsentState>
Where:
consentType
isAccurat.ConsentType.GDPR
orAccurat.ConsentType.LOCATION
This method returns a promise of enum Accurat.ConsentState
which is one of Accurat.ConsentState.ACCEPTED
or Accurat.ConsentState.REFUSED
.
Location Permission
The location permission can be updated by calling the updateConsent()
-method and providing a consent type and consent state:
Accurat.updateConsent(
consentType: Accurat.ConsentType,
consentState: Accurat.ConsentState,
): Promise<boolean>
Where:
consentType
isAccurat.ConsentType.LOCATION
consentState
is one ofAccurat.ConsentState.ACCEPTED
orAccurat.ConsentState.REFUSED
This method returns a promise of a boolean which lets you know whether the update was successful or not.
Note that the SDK will still check if the location system permission is granted by the user before actually starting the tracking. It won't however ask for location permissions itself in this case.
Finalizing
Finally call startTracking()
to start the tracking. Note that startTracking()
has to be called on each app start, even when no consent states are changed.
This entire manual flow can be implemented by adding this example code to your App
component
import Accurat from 'accurat-sdk-react-native';
React.useEffect(() => {
const config: Accurat.Config = {
username: ACCURAT_USERNAME,
password: ACCURAT_PASSWORD,
appVersion: APP_VERSION
}
Accurat.initialize(config).then(async () => {
const isTrackingStarted = await Accurat.isTrackingStarted();
if (isTrackingStarted) {
// Tracking has already been started in a previous app launch, so just call startTracking()
// here to continue the tracking
Accurat.startTracking().then((started) => {
// Your code for reacting to the SDK started event
});
return;
}
if (userOpensTheAppForTheFirstTime) {
// Own GDPR consent handling
const hasAcceptedGdprConsent = await askCustomGdprConsent();
const updateGdprConsentSuccess = await Accurat.updateConsent(
Accurat.ConsentType.GDPR,
hasAcceptedGdprConsent
? Accurat.ConsentState.ACCEPTED
: Accurat.ConsentState.REFUSED
);
if (!updateGdprConsentSuccess) {
return;
}
// Own location permission handling
const hasAcceptedLocationPermission = await askCustomLocationPermission();
const updateLocationPermissionSuccess = await Accurat.updateConsent(
Accurat.ConsentType.LOCATION,
hasAcceptedLocationPermission
? Accurat.ConsentState.ACCEPTED
: Accurat.ConsentState.REFUSED
);
if (!updateLocationPermissionSuccess) {
return;
}
}
// Start tracking
Accurat.startTracking().then((started) => {
// Your code for reacting to the SDK started event
});
});
}, []);
The consent flow can also partially be implemented by the SDK and partially by the app developer. For instance, by only passing Accurat.Feature.LOCATION_PERMISSION
in the config, the GDPR consent has to be handled by the app developer, but the location permissions will be handled by the SDK.
Stop Tracking (optional)
To stop the location tracking, simply call the stopTracking
-method:
Accurat.stopTracking(): void
Is tracking started? (optional)
If you want to know if the tracking is started or not, call the isTrackingStarted()
-method.
Accurat.isTrackingStarted(): Promise<boolean>
Receive location updates (optional)
The Accurat SDK can share received location updates with your app. To do this, add a listener:
Accurat.addLocationUpdateListener(
callback: (locations: Array<Accurat.Location>) => void,
): EmitterSubscription
Example implementation:
useEffect(() => {
let listener = Accurat.addLocationUpdateListener((locations) => {
// Do something with the locations
});
// Removes the listener once unmounted
return Accurat.removeLocationUpdateListener;
}, []);
Type Accurat.Location
contains the following fields:
| Field | Type | Info | |:----------------------|:---------|:-------------| | longitude | number | | | latitude | number | | | altitude | number | | | provider | string | android only | | bearing | number | | | bearingAccuracy | number | | | speed | number | | | speedAccuracy | number | | | timestamp | number | | | horizontalAccuracy | number | | | verticalAccuracy | number | | | hasHorizontalAccuracy | boolean | | | hasVerticalAccuracy | boolean | | | hasBearing | boolean | | | hasBearingAccuracy | boolean | | | hasSpeed | boolean | | | hasSpeedAccuracy | boolean | |
Notifications (optional)
The Accurat SDK can trigger notifications based on geofences, when enabled in our back-end.
iOS Geofence Notifications Setup (optional)
In order to receive geofence notifications in your React Native code, some native set-up is required.
Step 1. Intercept the notification and dispatch it to the AccuratReactNativeSDK
In order to handle geofence notifications, additional setup is required in your iOS project.
To receive geofence notifications (which are Local Push Notifications), the first step is to extend our AppDelegate. This can be accomplished by conforming to the UNUserNotificationCenterDelegate.
Swift
Assign the UNUserNotificationCenter
delegate to your AppDelegate
-class and request notification permissions. This can be added in your application didFinishLaunchWithOptions
method:
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ...
// Set the delegate of UNUserNotificationCenter
UNUserNotificationCenter.current().delegate = self
// (OPTIONAL) Request Notfication Permission (can be requested in a later phase using RN-packages)
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
print("Notification permission granted")
} else {
print("Notification permission denied")
}
}
// ...
}
Objective C
In Objective-C, add the UNUserNotificationCenterDelegate
to your AppDelegate's header file (AppDelegate.h
):
// ... other imports
#import <UserNotifications/UserNotifications.h>
@interface AppDelegate : RCTAppDelegate<UNUserNotificationCenterDelegate>
// ...
@end
Assign the UNUserNotificationCenter
delegate to your AppDelegate
-class and request notification permissions. This is done in the AppDelegate.m
-file:
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
// Set the delegate of UNUserNotificationCenter
UNUserNotificationCenter.current().delegate = self
// Request permission to display notifications
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
print("Notification permission granted")
} else {
print("Notification permission denied")
}
}
//...
}
Step 2. Dispatch notification to React Native Bridge
Our Accurat wrapper facilitates communication between iOS and React Native through the bridge. To instruct the wrapper to dispatch the notification through the bridge, we make use of NotificationCenter.
Start by adding this function, which notifies our wrapper, to your AppDelegate:
Swift
func dispatchNotificationPayloadToRNBridge(notification: UNNotification) {
NotificationCenter.default.post(
name: Notification.Name("AccuratRNNotification"),
object: nil,
userInfo: notification.request.content.userInfo
)
}
Objective-C
- (void)dispatchNotificationPayloadToRNBridge:(UNNotification *)notification {
[[NSNotificationCenter defaultCenter]
postNotificationName:@"AccuratRNNotification"
object:nil
userInfo:notification.request.content.userInfo
];
}
Next, extend your delegate method for incoming notifications. You should only dispatch the notifications if the identifier starts with Accurat_
:
Swift
extension AppDelegate: UNUserNotificationCenterDelegate {
// This method is called when a notification is about to be delivered to the user.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// Dispatch Accurat notifications to React Native
if notification.request.identifier.starts(with: "Accurat_") {
self.dispatchNotificationPayloadToRNBridge(notification: notification)
}
completionHandler([.alert, .sound])
}
}
Objective-C
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
if ([notification.request.identifier hasPrefix:@"Accurat_"]) {
[self dispatchNotificationPayloadToRNBridgeWithNotification:notification];
}
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);
}
Step 3. Listen to incoming notifications in React Native
Lastly, don't forget to add a listener in React Native to catch incoming push notifications:
React.useEffect(() => {
const listener = Accurat.addNotificationListener((info: any) => {
// Handle the notification, for example with a snackbar
Snackbar.show({
text: `New Notification: ${info.id} | ${info.data}`,
duration: Snackbar.LENGTH_LONG,
});
});
return Accurat.removeNotificationListener;
}, []);
Notification permissions
We need to ask the user for permissions to send notifications. This could, for example, be done by using react-native-permissions. Follow the README.md to integrate the package into your project.
After the consent flow, ask the user for permissions by using the following function:
requestNotifications(options: NotificationOption[]): Promise<{
status: PermissionStatus;
settings: NotificationSettings;
}>;
Notification data
When your app is opened from a geofence notification, a notification identifier will be passed to the App
-component as a prop which you can extract with the Accurat.GEOFENCE_NOTIFICATION_ID_KEY
constant.
Any extra data set in the Accurat web-interface will be passed as a stringyfied JSON Object (or null) can extract with the Accurat.GEOFENCE_NOTIFICATION_DATA_KEY
constant.
export default function App(props: any) {
const id = props[Accurat.GEOFENCE_NOTIFICATION_ID_KEY] as string | undefined;
const data = props[Accurat.GEOFENCE_NOTIFICATION_DATA_KEY] as string | undefined;
}
Custom icon (Android only)
You also have the option to set a custom icon for geofence notifications with the Accurat.setNotificationIcon
-method.
Accurat.setNotificationIcon(icon: string): void
Where the icon parameter is the name of the image. This image has to be placed inside android/app/src/main/res/drawable
folder.
The background of the notification icon needs to be transparent or it will be replaced by a blank square on Android Marshmallow and higher.
Additional features
Set language (optional)
If you want to change the language of the user, you can update the language. This language will be used in the consent popups and geofence notifications. When no language is set, the device language is used, or English if the device language is not supported.
Accurat.setLanguage(language: Accurat.Language | string): void
Where:
language
is one ofAccurat.Language.NL
,Accurat.Language.FR
orAccurat.Language.EN
Alternatively, you are able to use the language code and Accurat will translate this to a matching Accurat.Language
enum value.
Interact (optional)
Add an interaction for consumer, based on a given brand, campaign and touch point. If the brand, campaign and/or touch point does not exist, they will be created.
type Accurat.CampaignInteraction = {
group: string;
campaign: string;
touchPoint: string;
id: string;
startsAt: Date;
endsAt: Date;
};
Accurat.interact(interaction: Accurat.CampaignInteraction): Promise<boolean>
This method returns a promise of a boolean which lets you know whether the interaction was registered successfully or not.
Get segments (optional)
Fetch the segments the current consumer belongs to.
Accurat.getSegments(): Promise<Array<string>>
This method returns a promise of an array with segments. If the consumer does not exist, the array is empty.
Get metadata (optional)
Fetch a consumer's metadata.
Accurat.getMeta(): Promise<{ [key: string]: string }>
This method returns a promise of an object containing the metadata. If the consumer does not exist, the object is empty.
Set meta data (optional)
Add or update a consumer's metadata. If the consumer doesn't exist or hasn't allowed tracking, no change in metadata will be persisted.
Accurat.setMeta(key: string, value: string): void
Contact
Do you have any questions? Email us at [email protected].