npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

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 and password 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 is false.

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:

  1. The GDPR consent, which is a legal consent that is required to process personal data.
  2. 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 is Accurat.ConsentType.GDPR
  • consentState is one of Accurat.ConsentState.ACCEPTED or Accurat.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 is Accurat.ConsentType.GDPR or Accurat.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 is Accurat.ConsentType.LOCATION
  • consentState is one of Accurat.ConsentState.ACCEPTED or Accurat.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 of Accurat.Language.NL, Accurat.Language.FR or Accurat.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].