QoreID React Native SDK

QoreID React Native SDK

πŸ“˜

Note

With this release (v1.2.4), customers can perform all Collection services like VeriFind (digital address verification), Passport, Driver's License and other QoreID services on Android and iOS platforms.

npm

Here is an example app RN bare example app

Installation

npm install --save  @qore-id/react-native-qoreid-sdk
yarn add @qore-id/react-native-qoreid-sdk

Using Expo?

If you are working with an Expo managed project, perform the following tasks to generate android and ios folders to continue with the QoreID SDK integration.

npx expo prebuild

Install pod dependencies

//in your project directory

cd ios
pod install

Android

Add the following to your app/build.gradle

    //before your dependencies
repositories {
  mavenCentral()
  google()
  maven {
    url "https://repo.qoreid.com/repository/maven-releases/"
  }
  maven { url 'https://jitpack.io' }
}

Add this snippet of code to your app/proguard-rules.pro

-keep class com.qoreid.sdk.** { *; }
-dontshrink
-dontobfuscate
-dontoptimize

If you do not have the file in your ~/app/ directory, create one and reference it in the ~/app/gradle.build release configuration as shown below

...
buildTypes {
        release {
            ...
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
...

Add this snippet of code to your ~/java/com.<app name>/MainActivity

import com.qoreidsdk.QoreidSdkModule;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        QoreidSdkModule.initialize(this);
    }

override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState);
        QoreidSdkModule.initialize(this);
    }

Permissions

Certain services on QoreID require device permissions to work properly. Follow the instructions here to add the required permissions to your ~/android/app/src/main/AndroidManifest.xml file.

Verifind required permissions

...
<!-- Required for Verifind --> 
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
...

iOS

Update your AppDelegate.m

QoreidSdK requires the UINavigationController to push a new ViewController to your app. To wrap your app's rootViewController in a UINavigationController, add the following code to your AppDelegate.m file.

//AppDelegate.m

// 1. Import necessary headers
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTRootView.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  ...
  
  // 2. Create an instance of UIWindow
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  
  // 3. Set up the UINavigationController with a UIViewController
  UIViewController *viewController = [UIViewController new];
  UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
  [navigationController setNavigationBarHidden:YES animated:NO];
  
  // 4. Set the RN bridge to use the UIWindow as the root view controller
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:self.moduleName
                                            initialProperties:self.initialProps];
  viewController.view = rootView;
  self.window.rootViewController = navigationController; // Use the UINavigationController as the root
  
  [self.window makeKeyAndVisible];
  
  return YES;
}

...
@end

import UIKit
import React

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, RCTBridgeDelegate {
    
    var window: UIWindow?
    var bridge: RCTBridge?
    
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // 1. Create RN bridge
        bridge = RCTBridge(delegate: self, launchOptions: launchOptions)
        
        // 2. Create RCTRootView
        guard let bridge = bridge else { return false }
        let rootView = RCTRootView(bridge: bridge, moduleName: "YourModuleName", initialProperties: nil)
        
        // 3. Create root UIViewController and assign RCTRootView
        let rootViewController = UIViewController()
        rootViewController.view = rootView
        
        // 4. Embed in UINavigationController and hide nav bar
        let navigationController = UINavigationController(rootViewController: rootViewController)
        navigationController.setNavigationBarHidden(true, animated: false)
        
        // 5. Setup window
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = navigationController
        window?.makeKeyAndVisible()
        
        return true
    }
    
  ....
}

import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?

  var reactNativeDelegate: ReactNativeDelegate?
  var reactNativeFactory: RCTReactNativeFactory?

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
  ) -> Bool {
    let delegate = ReactNativeDelegate()
    let factory = RCTReactNativeFactory(delegate: delegate)
    delegate.dependencyProvider = RCTAppDependencyProvider()

    reactNativeDelegate = delegate
    reactNativeFactory = factory

    window = UIWindow(frame: UIScreen.main.bounds)

// Remove    
//-    factory.startReactNative(
//-      withModuleName: "Your module name",
//-      in: window,
//-      launchOptions: launchOptions
//-    )
    
// Wrap the React Native Root View in a Navigation Controller    
    let rootView = reactNativeFactory!.rootViewFactory.view(withModuleName: "Your module name")
    
     let reactViewController = UIViewController()
     reactViewController.view = rootView

     let navigationController = UINavigationController(rootViewController: reactViewController)
     navigationController.setNavigationBarHidden(true, animated: false)

     window?.rootViewController = navigationController
     window?.makeKeyAndVisible()

     return true
  }
}

class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
  override func sourceURL(for bridge: RCTBridge) -> URL? {
    self.bundleURL()
  }

  override func bundleURL() -> URL? {
#if DEBUG
    RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
    Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
  }
}

Permissions

Added the following to your ~/ios/<app name>/Info.plist file

...
<key>NSCameraUsageDescription</key>
<string>We need access to your camera to take photos for profile pictures.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to allow you to select and upload images.</string>
...

For verifind_4d

Update info.plist


<key>NSMotionUsageDescription</key>
<string>We need access to your motiion usage to provide you with location-based services, even when the app is in the background.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need access to your location to provide you with location-based services, even when the app is in the background.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need access to your location while you are using the app to provide you with location-based services.</string>

Add Background Mode Capability


Usage

//verify.tsx
import React from 'react';
import { Button, View } from 'react-native';
import { useQoreIdSdk } from '@qore-id/react-native-qoreid-sdk';


function App(){

  const callback = (data: any) => {
      console.debug(data);
    };

  const { launchQoreId } = useQoreIdSdk({
    onResult: callback,
  });

  function onSubmit() {
      const formData = {
        flowId: 0, /* Required for workflow */
        clientId: "", /* Required */
        productCode: "", /* Required for collection */
        customerReference: "", /* Required */
        applicantData: {
          firstName: "",
          middleName: "",
          lastName: "",
          gender: "",
          phoneNumber: "",
          email: "",
        },
        identityData: {
          idType: "",
          idNumber: "",
        },
        addressData: {
          address: "",
          city: "",
          lga: "",
        },
        ocrAcceptedDocuments:
          ['DRIVERS_LICENSE_NGA','VOTERS_CARD_NGA','NIN_SLIP_NGA','PASSPORT_NGA'],
      };

      launchQoreId(formData);
    }


  return (
      <View>
        <Button title="Launch QoreIdSdk" onPress={onSubmit} />
      </View>
    );
}

Usage without hook

//verify.tsx
import React from 'react';
import { Button, View } from 'react-native';
import { QoreIdSdk } from '@qore-id/react-native-qoreid-sdk';

function App() {
    
  const callback = (data) => {
    console.debug(data);
  };

  function onSubmit() {
    const formData = {
      flowId: 0, /* Required for workflow */
      clientId: "", /* Required */
      productCode: "", /* Required for collection */
      customerReference: "", /* Required */
      applicantData: {
        firstName: "",
        middleName: "",
        lastName: "",
        gender: "",
        phoneNumber: "",
        email: "",
      },
      identityData: {
        idType: "",
        idNumber: "",
      },
      addressData: {
        address: "",
        city: "",
        lga: "",
      },
      ocrAcceptedDocuments:
        ['DRIVERS_LICENSE_NGA','VOTERS_CARD_NGA','NIN_SLIP_NGA','PASSPORT_NGA'],
    };

    QoreIdSdk.launch(formData);
  }

  useEffect(() => {
    const unsubscribe = QoreIdSdk.events(callback);
    return () => {
      unsubscribe();
    };
  }, []);

  return (
    <View>
      <Button title="Launch QoreIdSdk" onPress={onSubmit} />
    </View>
  );
}

Utilities

QoreId SDK exposes utilities that you can easily use


import React, {useRef} from 'react'
import { QoreIdButton, utils } from '@qore-id/react-native-qoreid-sdk';

function App() {

   // Array of string
   //For more information check -> https://docs.qoreid.com/docs/product-codes
   const productIds = utils.productCodes; 


   //An array of accepted documents in a specific country
   //For more information check -> https://docs.qoreid.com/docs/ocr-accepted-documents#accepted-documents-for-ocr-verifications
   const ocrLists = utils.acceptedDocuments["Nigeria"]
    ...
}


Release Notes

v1.2.4

  • Routine SDK updates.

v1.2.2

  • SDK patch
  • Improved DX with a hook provision.

v1.2.0

  • Migration to Android version 14 (breaking changes)
  • Requires app migration to the latest Android and react-native versions.

v1.1.1

  • Changes to Event Handling in QoreIdSdk
  • To simplify event handling and improve code readability, we have refactored QoreID event listener to use useEffect hook.

Previous Implementation:

QoreIdSdk.events(onSuccess, onError);

Updated Implementation:

useEffect(() => {
  const unsubscribe = QoreIdSdk.events(callback);
  return () => {
    unsubscribe();
  };
}, []);

v1.1.0

  • Breaking Changes
  • Removed QoreIdButton component. Use QoreIdSdk.launch instead.
  • QoreIdSdk is now available on iOS.

v1.0.9

  • We've added QoreID initialization function. You can now launch the SDK in your code implementation, offering you more control.
  • Addition of event listener QoreIdSdk.events to listen to events from the SDK.
  • The QoreIdButton component will be deprecated in the next major release. Use QoreIdSdk.launchQoreId instead.