Como integrar o Authcube SDK no seu projeto React Native

Este tutorial explica como configurar o Authcube SDK em um aplicativo React Native usando Native Modules:

Você pode pular para o final deste tutorial para ver os exemplos em JavaScript e TypeScript.

Android

Authcube SDK

Adicione o arquivo Authcube SDK .aar ou .jar dentro do diretório android/app/libs.

Dentro do arquivo android/app/build.gradle, importe a dependência do authcube sdk e adicione os serviços de localização do Google Play:

dependencies {
    // The version of react-native is set by the React Native Gradle Plugin
    implementation("com.facebook.react:react-android")
    implementation(files("libs/sdk-release.aar"))
    implementation("com.google.android.gms:play-services-location:20.0.0")

    if (hermesEnabled.toBoolean()) {
        implementation("com.facebook.react:hermes-android")
    } else {
        implementation jscFlavor
    }
}

O código a seguir fornece métodos encapsulados que permitem que você utilize a funcionalidade do SDK a partir do seu código JavaScript. Essas funções demonstram alguns recursos básicos do SDK, como a coleta do DNA de um dispositivo ou geração de um code challenge para o fluxo PKCE da OpenID. Funções adicionais podem ser adicionadas conforme necessário.

Siga o tutorial baseado na linguagem utiliza no seu projeto React Native: Java ou Kotlin.

Java (React Native versão < 0.71)

Classe Wrapper

Crie um arquivo chamado AuthcubeSdkWrapper.java dentro de android/app/src/main/java/com/project:

  package com.project;

  import androidx.fragment.app.FragmentActivity;
  import com.facebook.react.bridge.ReactApplicationContext;
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
  import com.facebook.react.bridge.ReactMethod;
  import com.facebook.react.bridge.Callback;

  import br.com.sec4you.authcube.sdk.AuthcubeSdk;


  public class AuthcubeSdkWrapper extends ReactContextBaseJavaModule {
      private static ReactApplicationContext reactContext;
      private static final String secret_key = "1234567890123456";
      public AuthcubeSdk authcubeSdk;

      public AuthcubeSdkWrapper(ReactApplicationContext context) {
          super(context);
          this.reactContext = context;
          this.authcubeSdk = new AuthcubeSdk(getReactApplicationContext(), secret_key);
      }

      @Override
      public String getName() { // Use this name to import using: NativeModules.AuthcubeSdkWrapper;
          return "AuthcubeSdkWrapper";
      }

      @ReactMethod
      public void getDeviceInfo(Callback successCallback, Callback errorCallback) {
          try {
              System.out.println("Device Info: ");
              String dna = this.authcubeSdk.getDeviceInfo();
              successCallback.invoke(dna);
          } catch (Exception e) {
              errorCallback.invoke(e.getMessage());
          }
      }

      @ReactMethod
      public void getCodeVerifier(final Promise promise) {
          try {
              System.out.println("Code verifier: ");
              String code = this.authcubeSdk.getCodeVerifier();
              promise.resolve(code);
          } catch (Exception e) {
              promise.reject("Code verifier error: ", e);
          }
      }

      @ReactMethod
      public void getCodeChallenge(String codeVerifier, final Promise promise) {
          try {
              System.out.println("Code challenge: ");
              String challenge = this.authcubeSdk.getCodeChallenge(codeVerifier);
              promise.resolve(challenge);
          } catch (Exception e) {
              promise.reject("Code challenge error: ", e);
          }
      }
  }

Classe Package

Dentro do mesmo diretório, crie um arquivo chamado AuthcubeSdkPackage.java. O código abaixo expõe o módulo AuthcubeSdkWrapper para o React Native:

  package com.project;

  import com.facebook.react.ReactPackage;
  import com.facebook.react.bridge.NativeModule;
  import com.facebook.react.bridge.ReactApplicationContext;
  import com.facebook.react.uimanager.ViewManager;
  import com.project.AuthcubeSdkWrapper;

  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;

  public class AuthcubeSdkPackage implements ReactPackage {

      @Override
      public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
          return Collections.emptyList();
      }

      @Override
      public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
          List<NativeModule> modules = new ArrayList<>();
          //this is where you register the module
          modules.add(new AuthcubeSdkWrapper(reactContext));
          return modules;
      }
  }

Main Application

Para adicionar o pacote ao objeto host do seu React Native, você precisará incluí-lo no array de pacotes dentro do arquivo MainApplication.java:

  @Override
  protected List<ReactPackage> getPackages() {
    @SuppressWarnings("UnnecessaryLocalVariable")
    List<ReactPackage> packages = new PackageList(this).getPackages();
    packages.add(new AuthcubeSdkPackage());
    return packages;
  }

Kotlin (React Native versão >= 0.71)

Classe Wrapper

Crie um arquivo chamado AuthcubeSdkWrapper.kt dentro de android/app/src/main/java/com/project:

package com.project

import android.util.Log
import com.facebook.react.bridge.*
import br.com.sec4you.authcube.sdk.AuthcubeSdk


class AuthcubeSdkWrapper(private val reactContext: ReactApplicationContext) :
    ReactContextBaseJavaModule(reactContext) {

    companion object {
        private const val SECRET_KEY = "1234567890123456"
    }

    private val authcubeSdk: AuthcubeSdk

    init {
        authcubeSdk = AuthcubeSdk(
            reactContext,
            SECRET_KEY
        )
    }

    override fun getName() = "AuthcubeSdkWrapper"

    @ReactMethod
    fun getDeviceInfo(successCallback: Callback, errorCallback: Callback) {
        try {
            Log.d("AuthcubeSdkWrapper", "Fetching Device Info")
            val dna = authcubeSdk.deviceInfo
            successCallback.invoke(dna)
        } catch (e: Exception) {
            Log.e("AuthcubeSdkWrapper", "Error fetching Device Info", e)
            errorCallback.invoke(e.message)
        }
    }

    @ReactMethod
    fun getCodeVerifier(promise: Promise) {
        try {
            Log.d("AuthcubeSdkWrapper", "Fetching Code Verifier")
            val code = authcubeSdk.codeVerifier
            promise.resolve(code)
        } catch (e: Exception) {
            Log.e("AuthcubeSdkWrapper", "Error fetching Code Verifier", e)
            promise.reject("Code verifier error", e)
        }
    }

    @ReactMethod
    fun getCodeChallenge(codeVerifier: String, promise: Promise) {
        try {
            Log.d("AuthcubeSdkWrapper", "Fetching Code Challenge")
            val challenge = authcubeSdk.getCodeChallenge(codeVerifier)
            promise.resolve(challenge)
        } catch (e: Exception) {
            Log.e("AuthcubeSdkWrapper", "Error fetching Code Challenge", e)
            promise.reject("Code challenge error", e)
        }
    }
}

Classe Package

Dentro do mesmo diretório, crie um arquivo chamado AuthcubeSdkPackage.kt. O código abaixo expõe o módulo AuthcubeSdkWrapper para o React Native:

package com.project

import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
import com.project.AuthcubeSdkWrapper

class AuthcubeSdkPackage : ReactPackage {

    override fun createViewManagers(
        reactContext: ReactApplicationContext
    ): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()

    override fun createNativeModules(
        reactContext: ReactApplicationContext
    ): MutableList<NativeModule> = listOf(AuthcubeSdkWrapper(reactContext)).toMutableList()
}

Main Application

Para adicionar este pacote ao objeto host do seu React Native, você precisará incluí-lo no array de pacotes dentro do arquivo MainApplication.kt:

package com.project

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.soloader.SoLoader
import com.project.AuthcubeSdkPackage

class MainApplication : Application(), ReactApplication {

  override val reactNativeHost: ReactNativeHost =
      object : DefaultReactNativeHost(this) {
        override fun getPackages(): List<ReactPackage> =
            PackageList(this).packages.apply {
              // Packages that cannot be autolinked yet can be added manually here, for example:
              add(AuthcubeSdkPackage())
            }

        override fun getJSMainModuleName(): String = "index"

        override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

        override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
        override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
      }

  override val reactHost: ReactHost
    get() = getDefaultReactHost(applicationContext, reactNativeHost)

  override fun onCreate() {
    super.onCreate()
    SoLoader.init(this, false)
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      load()
    }
  }
}

iOS

Authcube SDK

Dentro do seu .xcodeproj, selecione o Target do projeto -> General -> Frameworks, Libraries, and Embedded Content e adicione o arquivo authcube sdk.xcframework com a opção Embed & Sign:

framework_example

Bridging-Header

Para permitir a comunicação entre classes Swift e Objective-C, você precisará criar um bridging header. Para isso, crie um arquivo Swift chamado AuthcubeSdkWrapper.swift no Xcode. Você será solicitado a criar um bridging header também. Um exemplo de bridging header pode ser assim:

#ifndef project_Bridging_Header_h
#define project_Bridging_Header_h

#import <React/RCTBridgeModule.h>

#endif /* project_Bridging_Header_h */

Certifique-se de que a localização do arquivo de bridging header na configuração Swift Compiler das Build Settings dentro do Target esteja corretamente definida:

xcode_build_settings

Classe Wrapper

O código a seguir fornece métodos encapsulados que permitem que você utilize a funcionalidade do SDK a partir do seu código JavaScript:

class AuthcubeSdkWrapper: NSObject {
  private var sdk: AuthcubeSdk;

  override init() {
    self.sdk = AuthcubeSdk();
    super.init();
  }

  @objc func getDeviceInfo(_ successCallback: RCTResponseSenderBlock, error errorCallback: RCTResponseSenderBlock) -> Void {
    let info = self.sdk.getDeviceInfo();
    if (info == "") {
      errorCallback(["Error collecting device info"]);
    } else {
      successCallback([info]);
    }
  }

  @objc func getCodeVerifier(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
    let code = self.sdk.getCodeVerifier();
    if (code == "") {
      reject("AuthcubeSdk error", "Code verifier", nil);
    } else {
      resolve(code);
    }
  }

  @objc func getCodeChallenge(_ code: NSString, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
    let challenge = self.sdk.getCodeChallenge(codeVerifier: code as String);
    if (challenge == "") {
      reject("AuthcubeSdk error", "Code challenge", nil);
    } else {
      resolve(challenge);
    }
  }
}

Módulo Objective-C

Em seguida, crie um arquivo Objective-C chamado AuthcubeSdkWrapperBridge.m:

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(AuthcubeSdkWrapper, NSObject)

+ (BOOL) requiresMainQueueSetup {
  return FALSE;
}

RCT_EXTERN_METHOD(getDeviceInfo:
                  (RCTResponseSenderBlock)successCallback
                  error:(RCTResponseSenderBlock)errorCallback)

RCT_EXTERN_METHOD(getCodeVerifier:
                  (RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(getCodeChallenge:(NSString)code
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)

@end

AuthcubeSdkWrapper.m atua como uma camada de abstração, expondo apenas os métodos correspondentes a AuthcubeSdkWrapper.swift para os Módulos Nativos no React Native.

O RCT_EXTERN_MODULE expõe o Authcube SDK para os Módulos Nativos e o RCT_EXTERN_METHOD expõe um método específico do SDK.

RCTResponseSenderBlock é um tipo de callback usado para passar dados do Objective-C para o JavaScript para métodos assíncronos. Ele só aceita um array de parâmetros como argumento.

Os métodos RCTPromiseResolveBlock e RCTPromiseRejectBlock retornarão e cumprirão um objeto JS Promise.

React Native

Aqui estão alguns exemplos em JavaScript e TypeScript de como importar e usar os métodos do Authcube SDK no seu aplicativo React Native:

JavaScript

import React from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  Button,
  Alert,
  useColorScheme,
  View,
  NativeModules,
} from 'react-native';

import {
  Colors,
  Header,
} from 'react-native/Libraries/NewAppScreen';

const AuthcubeSdk = NativeModules.AuthcubeSdkWrapper;

function App() {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  const fetchDeviceInfo = () => {
    /**
     *  Method exposed using Callback 
     */

    AuthcubeSdk.getDeviceInfo(
      (res) => {
        console.log('Device info:', res);
      },
      (error) => {
        console.error('Error getting device info:', error);
        Alert.alert('Error', 'Failed to fetch device info');
      }
    );
  };

  const getPKCECodeChallenge = async () => {
    /**
     * Methods exposed using Promises.
     * When using await, a try/catch block is required to handle errors on promise.
     */

    try {
      const codeVerifier = await AuthcubeSdk.getCodeVerifier();
      console.log('PKCE code verifier:', codeVerifier);

      AuthcubeSdk.getCodeChallenge(codeVerifier)
        .then((challenge) => console.log('PKCE code challenge:', challenge))
        .catch((error) =>
          console.error('Error getting code challenge. Detail:', error)
        );
    } catch (err) {
      console.error('Error getting code verifier. Detail:', err);
    }
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar
        barStyle={isDarkMode ? 'light-content' : 'dark-content'}
        backgroundColor={backgroundStyle.backgroundColor}
      />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        <Header />
        <View
          style={{
            backgroundColor: isDarkMode ? Colors.black : Colors.white,
          }}>
          <Button title="Fetch Device Info" onPress={fetchDeviceInfo} />
          <Button title="Get PKCE Code Challenge" onPress={getPKCECodeChallenge} />
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}

export default App;

TypeScript

import React from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  Button, 
  Alert,
  useColorScheme,
  View,
  NativeModules, 
} from 'react-native';

import {
  Colors,
  Header
} from 'react-native/Libraries/NewAppScreen';

const { AuthcubeSdkWrapper: AuthcubeSdk } = NativeModules;


function App(): React.JSX.Element {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  const fetchDeviceInfo = () => {
    /**
     *  Method exposed using Callback 
     */

    AuthcubeSdk.getDeviceInfo(
      (res: string) => {
        console.log('Device info:', res);
      },
      (error: string) => {
        console.error('Error getting device info:', error);
        Alert.alert('Error', 'Failed to fetch device info');
      }
    );
  };

  const getPKCECodeChallenge = async () => {
    /**
     * Methods exposed using Promises.
     * When using await, a try/catch block is required to handle errors on promise.
     */

    try {
      const codeVerifier: string = await AuthcubeSdk.getCodeVerifier();
      console.log("PKCE code verifier: ", codeVerifier);

      AuthcubeSdk.getCodeChallenge(codeVerifier)
        .then((challenge: string) => console.log("PKCE code challenge:", challenge))
        .catch((error: unknown) =>
          console.error("Error getting code challenge. Detail: ", error)
        );
    } catch (err: unknown) {
      console.error("Error getting code verifier. Detail: ", err);
    }
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar
        barStyle={isDarkMode ? 'light-content' : 'dark-content'}
        backgroundColor={backgroundStyle.backgroundColor}
      />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        <Header />
        <View
          style={{
            backgroundColor: isDarkMode ? Colors.black : Colors.white,
          }}>
          <Button title="Fetch Device Info" onPress={fetchDeviceInfo} />
          <Button title="Get PKCE Code Challenge" onPress={getPKCECodeChallenge} />
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}


export default App;

results matching ""

    No results matching ""