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:
- https://reactnative.dev/docs/legacy/native-modules-ios
- https://reactnative.dev/docs/legacy/native-modules-android
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
:
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:
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;