From 24571b961e239076ed5b62a0a307b47a07d046d7 Mon Sep 17 00:00:00 2001 From: Japhet Date: Mon, 4 Sep 2023 17:40:33 +0200 Subject: [PATCH 01/30] feat: compose view skeleton --- android/build.gradle | 40 ++++++++++- .../com/smileidentity/react/SmileIDView.kt | 69 +++++++++++++++++++ .../com/smileidentity/react/SmileIdModule.kt | 9 ++- .../com/smileidentity/react/SmileIdPackage.kt | 5 ++ .../smileidentity/react/SmileViewManager.kt | 23 +++++++ android/src/oldarch/SmileIdSpec.kt | 3 +- example/android/app/build.gradle | 14 ++++ .../react/sample/MainApplication.kt | 6 +- example/android/build.gradle | 4 +- example/src/App.tsx | 10 ++- src/index.tsx | 11 ++- 11 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 android/src/main/java/com/smileidentity/react/SmileIDView.kt create mode 100644 android/src/main/java/com/smileidentity/react/SmileViewManager.kt diff --git a/android/build.gradle b/android/build.gradle index f33f679..dd40826 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,6 +6,7 @@ buildscript { repositories { google() mavenCentral() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } } dependencies { @@ -76,15 +77,24 @@ android { buildFeatures { buildConfig = true + compose = true + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() } lintOptions { disable "GradleCompatible" } + composeOptions { + kotlinCompilerExtensionVersion '1.4.0' + } + compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } sourceSets { @@ -105,6 +115,7 @@ android { repositories { mavenCentral() google() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } } def kotlin_version = getExtOrDefault("kotlinVersion") @@ -116,7 +127,32 @@ dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core" implementation "com.smileidentity:android-sdk:$smile_id_sdk_version" + implementation "com.jakewharton.timber:timber" + + implementation 'androidx.core:core-ktx:1.10.1' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.9.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' + implementation 'androidx.activity:activity-compose:1.5.1' + implementation platform('androidx.compose:compose-bom:2022.10.00') + implementation 'androidx.compose.ui:ui' + implementation 'androidx.compose.ui:ui-graphics' + implementation 'androidx.compose.ui:ui-tooling-preview' + implementation 'androidx.compose.material3:material3' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00') + androidTestImplementation 'androidx.compose.ui:ui-test-junit4' + + + androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00') + androidTestImplementation 'androidx.compose.ui:ui-test-junit4' + + debugImplementation 'androidx.compose.ui:ui-tooling' + debugImplementation 'androidx.compose.ui:ui-test-manifest' } if (isNewArchitectureEnabled()) { diff --git a/android/src/main/java/com/smileidentity/react/SmileIDView.kt b/android/src/main/java/com/smileidentity/react/SmileIDView.kt new file mode 100644 index 0000000..af33f47 --- /dev/null +++ b/android/src/main/java/com/smileidentity/react/SmileIDView.kt @@ -0,0 +1,69 @@ +package com.smileidentity.react + +import android.widget.LinearLayout +import android.Manifest +import android.content.Context +import android.util.Log +import android.view.Choreographer +import android.view.ViewGroup +import androidx.compose.ui.platform.ComposeView +import com.smileidentity.SmileID +import com.smileidentity.compose.SmartSelfieEnrollment + +class SmileIDView (context: Context) : LinearLayout(context) { + private val composeView: ComposeView = ComposeView(context) + + init { + val layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + setLayoutParams(layoutParams) + orientation = VERTICAL + + composeView.setContent { + SmileID.SmartSelfieEnrollment( + userId = "userId1", + jobId = "userId1", + allowAgentMode = true, + showInstructions = true, + ) { result -> + //TODO: handle result + } + } + composeView.layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + addView(composeView) + + setupLayoutHack() + manuallyLayoutChildren() + } + + private fun setupLayoutHack() { + Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback { + override fun doFrame(frameTimeNanos: Long) { + manuallyLayoutChildren() + viewTreeObserver.dispatchOnGlobalLayout() + Choreographer.getInstance().postFrameCallback(this) + } + }) + } + + private fun manuallyLayoutChildren() { + try { + for (i in 0 until childCount) { + val child = getChildAt(i) + child.measure( + MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY) + ) + child.layout(0, 0, child.measuredWidth, child.measuredHeight) + } + } catch (e: Exception) { + Log.d("Started", "$e.message") + } + + } +} diff --git a/android/src/main/java/com/smileidentity/react/SmileIdModule.kt b/android/src/main/java/com/smileidentity/react/SmileIdModule.kt index a936a22..fdeaa0f 100644 --- a/android/src/main/java/com/smileidentity/react/SmileIdModule.kt +++ b/android/src/main/java/com/smileidentity/react/SmileIdModule.kt @@ -1,9 +1,13 @@ package com.smileidentity.react +import androidx.compose.runtime.Composable import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReadableMap +import com.smileidentity.SmileID import com.smileidentity.SmileIdSpec +import com.smileidentity.compose.SmartSelfieEnrollment class SmileIdModule internal constructor(context: ReactApplicationContext) : SmileIdSpec(context) { @@ -15,8 +19,9 @@ class SmileIdModule internal constructor(context: ReactApplicationContext) : // Example method // See https://reactnative.dev/docs/native-modules-android @ReactMethod - override fun multiply(a: Double, b: Double, promise: Promise) { - promise.resolve(a * b) + override fun initialize(promise: Promise) { + SmileID.initialize(reactApplicationContext) + promise.resolve(null) } companion object { diff --git a/android/src/main/java/com/smileidentity/react/SmileIdPackage.kt b/android/src/main/java/com/smileidentity/react/SmileIdPackage.kt index f17748b..2904796 100644 --- a/android/src/main/java/com/smileidentity/react/SmileIdPackage.kt +++ b/android/src/main/java/com/smileidentity/react/SmileIdPackage.kt @@ -5,10 +5,15 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.NativeModule import com.facebook.react.module.model.ReactModuleInfoProvider import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.uimanager.ViewManager import com.smileidentity.react.BuildConfig +import java.util.Collections import java.util.HashMap class SmileIdPackage : TurboReactPackage() { + override fun createViewManagers(reactContext: ReactApplicationContext): List> = + Collections.singletonList(SmileViewManager(reactContext)) + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { return if (name == SmileIdModule.NAME) { SmileIdModule(reactContext) diff --git a/android/src/main/java/com/smileidentity/react/SmileViewManager.kt b/android/src/main/java/com/smileidentity/react/SmileViewManager.kt new file mode 100644 index 0000000..4a0a735 --- /dev/null +++ b/android/src/main/java/com/smileidentity/react/SmileViewManager.kt @@ -0,0 +1,23 @@ +package com.smileidentity.react + +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext + +@ReactModule(name = SmileViewManager.NAME) +class SmileViewManager(private val mCallerContext: ReactApplicationContext) : + SimpleViewManager() { + override fun getName(): String { + return NAME + } + + override fun createViewInstance(p0: ThemedReactContext): SmileIDView { + return SmileIDView(mCallerContext.currentActivity!!) + } + + companion object { + const val NAME = "SmileIDView" + } + +} diff --git a/android/src/oldarch/SmileIdSpec.kt b/android/src/oldarch/SmileIdSpec.kt index 3f9dc5e..122bf47 100644 --- a/android/src/oldarch/SmileIdSpec.kt +++ b/android/src/oldarch/SmileIdSpec.kt @@ -3,9 +3,10 @@ package com.smileidentity import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReadableMap abstract class SmileIdSpec internal constructor(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { - abstract fun multiply(a: Double, b: Double, promise: Promise) + abstract fun initialize(promise: Promise) } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index a89e2e8..b8a6f9c 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,5 +1,6 @@ apply plugin: "com.android.application" apply plugin: "com.facebook.react" +apply plugin: "kotlin-android" /** * This is the configuration block to customize your React Native Android app. @@ -92,6 +93,19 @@ android { buildFeatures { buildConfig = true } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } } dependencies { diff --git a/example/android/app/src/main/java/com/smileidentity/react/sample/MainApplication.kt b/example/android/app/src/main/java/com/smileidentity/react/sample/MainApplication.kt index a5a4354..5decfda 100644 --- a/example/android/app/src/main/java/com/smileidentity/react/sample/MainApplication.kt +++ b/example/android/app/src/main/java/com/smileidentity/react/sample/MainApplication.kt @@ -8,7 +8,7 @@ import com.facebook.react.ReactPackage import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.soloader.SoLoader -import com.smileidentity.BuildConfig +import com.smileidentity.react.sample.BuildConfig class MainApplication : Application(), ReactApplication { private val mReactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) { @@ -27,9 +27,9 @@ class MainApplication : Application(), ReactApplication { } override val isNewArchEnabled: Boolean - protected get() = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + get() = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED override val isHermesEnabled: Boolean - protected get() = BuildConfig.IS_HERMES_ENABLED + get() = BuildConfig.IS_HERMES_ENABLED } override fun getReactNativeHost(): ReactNativeHost { diff --git a/example/android/build.gradle b/example/android/build.gradle index cbfa4d9..35b4205 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -6,9 +6,10 @@ buildscript { minSdkVersion = 21 compileSdkVersion = 34 targetSdkVersion = 34 + kotlinVersion = "1.8.0" // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. - ndkVersion = "23.1.7779620" + ndkVersion = "21.3.6528147" } repositories { maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } @@ -18,5 +19,6 @@ buildscript { dependencies { classpath "com.android.tools.build:gradle:8.1.0" classpath("com.facebook.react:react-native-gradle-plugin") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } diff --git a/example/src/App.tsx b/example/src/App.tsx index 4f69368..ca6de6a 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { StyleSheet, View, Text } from 'react-native'; import { SmileID } from 'react-native-smile-id'; +import SmileIDView from 'react-native-smile-id'; export default function App() { const [result, setResult] = React.useState(); @@ -12,7 +13,7 @@ export default function App() { return ( - Result: {result} + ); } @@ -23,6 +24,13 @@ const styles = StyleSheet.create({ alignItems: 'center', justifyContent: 'center', }, + smileView: { + width: "100%", + height: "100%", + alignItems: 'center', + backgroundColor: 'red', + justifyContent: 'center', + }, box: { width: 60, height: 60, diff --git a/src/index.tsx b/src/index.tsx index 344837c..a3e5b4a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,5 @@ -import { NativeModules, Platform } from 'react-native'; +import { HostComponent, NativeModules, Platform, ViewProps } from 'react-native'; +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; const LINKING_ERROR = `The package 'react-native-smile-id' doesn't seem to be linked. Make sure: \n\n` + @@ -24,6 +25,14 @@ const _SmileID = SmileIdModule } ); + +export interface NativeProps extends ViewProps { +} + +export default codegenNativeComponent( + 'SmileIDView', +) as HostComponent; + export const SmileID = { initialize: () => _SmileID.initialize(), }; From 5938d213a32a13f79a8df9b0da3e022eabb842aa Mon Sep 17 00:00:00 2001 From: Japhet Date: Wed, 6 Sep 2023 17:34:51 +0200 Subject: [PATCH 02/30] feat: props to native android for product,user id, job type, job id testing --- android/build.gradle | 6 +- .../com/smileidentity/react/SmileIDView.kt | 60 +++++++++++++++---- .../smileidentity/react/SmileIDViewManager.kt | 45 ++++++++++++++ .../com/smileidentity/react/SmileIdPackage.kt | 9 ++- .../smileidentity/react/SmileViewManager.kt | 23 ------- example/src/App.tsx | 10 +++- src/index.tsx | 1 + 7 files changed, 108 insertions(+), 46 deletions(-) create mode 100644 android/src/main/java/com/smileidentity/react/SmileIDViewManager.kt delete mode 100644 android/src/main/java/com/smileidentity/react/SmileViewManager.kt diff --git a/android/build.gradle b/android/build.gradle index dd40826..add6ab3 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -134,13 +134,15 @@ dependencies { implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' - implementation 'androidx.activity:activity-compose:1.5.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' + implementation 'androidx.activity:activity-compose:1.7.2' + implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.6.1' implementation platform('androidx.compose:compose-bom:2022.10.00') implementation 'androidx.compose.ui:ui' implementation 'androidx.compose.ui:ui-graphics' implementation 'androidx.compose.ui:ui-tooling-preview' implementation 'androidx.compose.material3:material3' + implementation("androidx.navigation:navigation-compose:2.7.1") testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/android/src/main/java/com/smileidentity/react/SmileIDView.kt b/android/src/main/java/com/smileidentity/react/SmileIDView.kt index af33f47..edd8a2c 100644 --- a/android/src/main/java/com/smileidentity/react/SmileIDView.kt +++ b/android/src/main/java/com/smileidentity/react/SmileIDView.kt @@ -1,17 +1,26 @@ package com.smileidentity.react -import android.widget.LinearLayout -import android.Manifest import android.content.Context -import android.util.Log import android.view.Choreographer import android.view.ViewGroup +import android.widget.LinearLayout +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.platform.ComposeView +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import com.smileidentity.SmileID +import com.smileidentity.compose.SmartSelfieAuthentication import com.smileidentity.compose.SmartSelfieEnrollment +import com.smileidentity.util.randomJobId +import com.smileidentity.util.randomUserId +import timber.log.Timber -class SmileIDView (context: Context) : LinearLayout(context) { +class SmileIDView(context: Context) : LinearLayout(context) { private val composeView: ComposeView = ComposeView(context) + lateinit var userId: String + lateinit var jobId: String + lateinit var jobType: String init { val layoutParams = ViewGroup.LayoutParams( @@ -22,15 +31,41 @@ class SmileIDView (context: Context) : LinearLayout(context) { orientation = VERTICAL composeView.setContent { - SmileID.SmartSelfieEnrollment( - userId = "userId1", - jobId = "userId1", - allowAgentMode = true, - showInstructions = true, - ) { result -> - //TODO: handle result + val navController = rememberNavController() + NavHost( + navController, + if (jobType == "1") "smart_selfie_enrollment" else "smart_selfie_authentication" + ) { + composable("smart_selfie_enrollment") { + val userId = rememberSaveable { randomUserId() } + val jobId = rememberSaveable { randomJobId() } + SmileID.SmartSelfieEnrollment( + userId = userId, + jobId = jobId, + allowAgentMode = true, + showInstructions = true + ) { result -> + //TODO: Handle result + Timber.d("Result: $result") + navController.popBackStack() + } + } + composable("smart_selfie_authentication") { + val userId = rememberSaveable { randomJobId( )} + val jobId = rememberSaveable { randomJobId() } + SmileID.SmartSelfieAuthentication( + userId = userId, + jobId = jobId, + allowAgentMode = true, + ) { result -> + //TODO: Handle result + Timber.d("Result: $result") + navController.popBackStack() + } + } } } + composeView.layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT @@ -61,8 +96,7 @@ class SmileIDView (context: Context) : LinearLayout(context) { ) child.layout(0, 0, child.measuredWidth, child.measuredHeight) } - } catch (e: Exception) { - Log.d("Started", "$e.message") + } catch (_: Exception) { } } diff --git a/android/src/main/java/com/smileidentity/react/SmileIDViewManager.kt b/android/src/main/java/com/smileidentity/react/SmileIDViewManager.kt new file mode 100644 index 0000000..43860df --- /dev/null +++ b/android/src/main/java/com/smileidentity/react/SmileIDViewManager.kt @@ -0,0 +1,45 @@ +package com.smileidentity.react + +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.annotations.ReactProp + +@ReactModule(name = SmileIDViewManager.NAME) +class SmileIDViewManager(private val mCallerContext: ReactApplicationContext) : + SimpleViewManager() { + override fun getName(): String { + return NAME + } + + @ReactProp(name = "userId") + fun setUserId(view: SmileIDView, userId: String?) { + userId?.let { + view.userId = it + } + } + + @ReactProp(name = "jobId") + fun setJobId(view: SmileIDView, jobId: String?) { + jobId?.let { + view.jobId = it + } + } + + @ReactProp(name = "jobType") + fun setJobType(view: SmileIDView, jobType: String?) { + jobType?.let { + view.jobType = it + } + } + + override fun createViewInstance(p0: ThemedReactContext): SmileIDView { + return SmileIDView(mCallerContext.currentActivity!!) + } + + companion object { + const val NAME = "SmileIDView" + } + +} diff --git a/android/src/main/java/com/smileidentity/react/SmileIdPackage.kt b/android/src/main/java/com/smileidentity/react/SmileIdPackage.kt index 2904796..b7b2d79 100644 --- a/android/src/main/java/com/smileidentity/react/SmileIdPackage.kt +++ b/android/src/main/java/com/smileidentity/react/SmileIdPackage.kt @@ -1,18 +1,17 @@ package com.smileidentity.react import com.facebook.react.TurboReactPackage -import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.NativeModule -import com.facebook.react.module.model.ReactModuleInfoProvider +import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider import com.facebook.react.uimanager.ViewManager -import com.smileidentity.react.BuildConfig import java.util.Collections -import java.util.HashMap class SmileIdPackage : TurboReactPackage() { + override fun createViewManagers(reactContext: ReactApplicationContext): List> = - Collections.singletonList(SmileViewManager(reactContext)) + Collections.singletonList(SmileIDViewManager(reactContext)) override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { return if (name == SmileIdModule.NAME) { diff --git a/android/src/main/java/com/smileidentity/react/SmileViewManager.kt b/android/src/main/java/com/smileidentity/react/SmileViewManager.kt deleted file mode 100644 index 4a0a735..0000000 --- a/android/src/main/java/com/smileidentity/react/SmileViewManager.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.smileidentity.react - -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.module.annotations.ReactModule -import com.facebook.react.uimanager.SimpleViewManager -import com.facebook.react.uimanager.ThemedReactContext - -@ReactModule(name = SmileViewManager.NAME) -class SmileViewManager(private val mCallerContext: ReactApplicationContext) : - SimpleViewManager() { - override fun getName(): String { - return NAME - } - - override fun createViewInstance(p0: ThemedReactContext): SmileIDView { - return SmileIDView(mCallerContext.currentActivity!!) - } - - companion object { - const val NAME = "SmileIDView" - } - -} diff --git a/example/src/App.tsx b/example/src/App.tsx index ca6de6a..d43237e 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -13,7 +13,11 @@ export default function App() { return ( - + ); } @@ -25,8 +29,8 @@ const styles = StyleSheet.create({ justifyContent: 'center', }, smileView: { - width: "100%", - height: "100%", + width: '100%', + height: '100%', alignItems: 'center', backgroundColor: 'red', justifyContent: 'center', diff --git a/src/index.tsx b/src/index.tsx index a3e5b4a..c83345a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -27,6 +27,7 @@ const _SmileID = SmileIdModule export interface NativeProps extends ViewProps { + product?: { userId: string; jobId: string; jobType: string }; } export default codegenNativeComponent( From 4c36c144ba587cfdee7458982df194d12f30d96a Mon Sep 17 00:00:00 2001 From: Japhet Date: Wed, 6 Sep 2023 17:36:50 +0200 Subject: [PATCH 03/30] feat: props to native android for product,user id, job type, job id testing --- src/index.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index c83345a..926ccd0 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -25,9 +25,11 @@ const _SmileID = SmileIdModule } ); - +//todo:rename jobtupe to product and make it enum export interface NativeProps extends ViewProps { - product?: { userId: string; jobId: string; jobType: string }; + userId?: string; + jobId?: string; + jobType: string } export default codegenNativeComponent( From 4ae08abd51abfff2d8b61261c14548d06c18451a Mon Sep 17 00:00:00 2001 From: Japhet Date: Mon, 25 Sep 2023 16:30:03 +0200 Subject: [PATCH 04/30] feat: stack navigation in progress for the sample app --- android/build.gradle | 9 +- android/gradle.properties | 4 +- .../com/smileidentity/react/ReactUtils.kt | 41 +++++ .../com/smileidentity/react/SmileIDView.kt | 116 ++++++++++++-- .../smileidentity/react/SmileIDViewManager.kt | 12 +- .../com/smileidentity/react/SmileIdModule.kt | 63 +++++++- android/src/oldarch/SmileIdSpec.kt | 5 +- example/android/app/build.gradle | 151 +++++++++--------- .../react/sample/MainActivity.kt | 42 ++--- example/android/build.gradle | 6 +- example/ios/Podfile.lock | 13 ++ example/package.json | 12 +- example/src/App.tsx | 29 ++-- example/src/HomeScreen.tsx | 36 +++++ example/src/SmileIDCaptureScreen.tsx | 39 +++++ example/yarn.lock | 117 +++++++++++++- src/NativeSmileId.ts | 4 +- src/index.tsx | 51 +++++- 18 files changed, 605 insertions(+), 145 deletions(-) create mode 100644 android/src/main/java/com/smileidentity/react/ReactUtils.kt create mode 100644 example/src/HomeScreen.tsx create mode 100644 example/src/SmileIDCaptureScreen.tsx diff --git a/android/build.gradle b/android/build.gradle index add6ab3..6d778db 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -10,7 +10,7 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:8.1.0" + classpath "com.android.tools.build:gradle:8.1.1" // noinspection DifferentKotlinGradleVersion classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } @@ -22,6 +22,7 @@ def isNewArchitectureEnabled() { apply plugin: "com.android.library" apply plugin: "kotlin-android" +apply plugin: 'kotlin-kapt' def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } @@ -76,7 +77,7 @@ android { } buildFeatures { - buildConfig = true + buildConfig true compose = true } @@ -89,7 +90,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion '1.4.0' + kotlinCompilerExtensionVersion '1.5.3' } compileOptions { @@ -143,6 +144,8 @@ dependencies { implementation 'androidx.compose.ui:ui-tooling-preview' implementation 'androidx.compose.material3:material3' implementation("androidx.navigation:navigation-compose:2.7.1") + implementation("com.squareup.moshi:moshi:1.14.0") + kapt("com.squareup.moshi:moshi-kotlin-codegen:1.14.0") testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/android/gradle.properties b/android/gradle.properties index caf1b50..f2bff03 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,6 +1,6 @@ -SmileId_kotlinVersion=1.9.0 +SmileId_kotlinVersion=1.9.10 SmileId_minSdkVersion=21 SmileId_targetSdkVersion=34 SmileId_compileSdkVersion=34 SmileId_ndkversion=21.4.7075529 -SmileId_androidVersion=10.0.0-beta05 +SmileId_androidVersion=10.0.0-beta07 diff --git a/android/src/main/java/com/smileidentity/react/ReactUtils.kt b/android/src/main/java/com/smileidentity/react/ReactUtils.kt new file mode 100644 index 0000000..1fdd1f5 --- /dev/null +++ b/android/src/main/java/com/smileidentity/react/ReactUtils.kt @@ -0,0 +1,41 @@ +package com.smileidentity.react + +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.bridge.ReadableType + +fun ReadableMap.toMap(): Map { + val map = mutableMapOf() + val iterator = keySetIterator() + while (iterator.hasNextKey()) { + val key = iterator.nextKey() + val value: String = when (getType(key)) { + ReadableType.Null -> null.toString() + ReadableType.Boolean -> getBoolean(key).toString() + ReadableType.Number -> getDouble(key).toString() + ReadableType.String -> getString(key)!! + ReadableType.Map -> getMap(key)?.toMap().toString() + ReadableType.Array -> getArray(key).toString() + } + map[key] = value + } + return map +} + +fun ReadableMap.toArray(): Array { + val array = mutableListOf() + val keysIterator = keySetIterator() + + while (keysIterator.hasNextKey()) { + val key = keysIterator.nextKey() + val value: Any? = when (getType(key)) { + ReadableType.Null -> null + ReadableType.Boolean -> getBoolean(key) + ReadableType.Number -> getDouble(key) + ReadableType.String -> getString(key) + ReadableType.Map -> getMap(key)?.toArray() + ReadableType.Array -> getArray(key) + } + array.add(value) + } + return array.toTypedArray() +} diff --git a/android/src/main/java/com/smileidentity/react/SmileIDView.kt b/android/src/main/java/com/smileidentity/react/SmileIDView.kt index edd8a2c..4d0796f 100644 --- a/android/src/main/java/com/smileidentity/react/SmileIDView.kt +++ b/android/src/main/java/com/smileidentity/react/SmileIDView.kt @@ -1,32 +1,44 @@ package com.smileidentity.react -import android.content.Context import android.view.Choreographer import android.view.ViewGroup import android.widget.LinearLayout +import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.platform.ComposeView import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.RCTEventEmitter import com.smileidentity.SmileID +import com.smileidentity.compose.DocumentVerification import com.smileidentity.compose.SmartSelfieAuthentication import com.smileidentity.compose.SmartSelfieEnrollment +import com.smileidentity.models.Document +import com.smileidentity.results.DocumentVerificationResult +import com.smileidentity.results.SmartSelfieResult +import com.smileidentity.results.SmileIDResult import com.smileidentity.util.randomJobId import com.smileidentity.util.randomUserId -import timber.log.Timber -class SmileIDView(context: Context) : LinearLayout(context) { - private val composeView: ComposeView = ComposeView(context) +class SmileIDView(context: ReactApplicationContext) : LinearLayout(context) { + private val composeView: ComposeView = ComposeView(context.currentActivity!!) lateinit var userId: String lateinit var jobId: String lateinit var jobType: String + lateinit var eventEmitter: RCTEventEmitter + init { val layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT ) + eventEmitter = (context as ReactContext).getJSModule(RCTEventEmitter::class.java); setLayoutParams(layoutParams) orientation = VERTICAL @@ -44,23 +56,82 @@ class SmileIDView(context: Context) : LinearLayout(context) { jobId = jobId, allowAgentMode = true, showInstructions = true - ) { result -> - //TODO: Handle result - Timber.d("Result: $result") - navController.popBackStack() + ) { + when (it) { + is SmileIDResult.Success -> { + val json = try { + SmileID.moshi + .adapter(SmartSelfieResult::class.java) + .toJson(it.data) + } catch (e: Exception) { + "null" + } + emitSuccess(json) + } + is SmileIDResult.Error -> { + it.throwable.printStackTrace() + emitFailure(it.throwable) + } + } } } composable("smart_selfie_authentication") { - val userId = rememberSaveable { randomJobId( )} + val userId = rememberSaveable { randomJobId() } val jobId = rememberSaveable { randomJobId() } SmileID.SmartSelfieAuthentication( userId = userId, jobId = jobId, - allowAgentMode = true, - ) { result -> - //TODO: Handle result - Timber.d("Result: $result") - navController.popBackStack() + allowAgentMode = true){ + when (it) { + is SmileIDResult.Success -> { + val json = try { + SmileID.moshi + .adapter(SmartSelfieResult::class.java) + .toJson(it.data) + } catch (e: Exception) { + "null" + } + emitSuccess(json) + } + is SmileIDResult.Error -> { + it.throwable.printStackTrace() + emitFailure(it.throwable) + } + } + } + } + composable("document_verification") { + val userId = rememberSaveable { randomUserId() } + val jobId = rememberSaveable { randomJobId() } + val documentType = remember(it) { + Document( + it.arguments?.getString("countryCode")!!, + it.arguments?.getString("idType")!!, + ) + } + SmileID.DocumentVerification( + userId = userId, + jobId = jobId, + idType = documentType, + showInstructions = true, + allowGalleryUpload = true, + captureBothSides = true){result -> + when (result) { + is SmileIDResult.Success -> { + val json = try { + SmileID.moshi + .adapter(DocumentVerificationResult::class.java) + .toJson(result.data) + } catch (e: Exception) { + "null" + } + emitSuccess(json) + } + is SmileIDResult.Error -> { + result.throwable.printStackTrace() + emitFailure(result.throwable) + } + } } } } @@ -76,6 +147,22 @@ class SmileIDView(context: Context) : LinearLayout(context) { manuallyLayoutChildren() } + private fun emitSuccess(result: String) { + val map = Arguments.createMap() + map.putString("result", result) + sendEvent(map) + } + + private fun sendEvent(map: WritableMap){ + eventEmitter.receiveEvent(id, "onSmileResult", map) + } + + private fun emitFailure(error: Throwable) { + val map = Arguments.createMap() + map.putString("error", error.message) + sendEvent(map) + } + private fun setupLayoutHack() { Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback { override fun doFrame(frameTimeNanos: Long) { @@ -98,6 +185,5 @@ class SmileIDView(context: Context) : LinearLayout(context) { } } catch (_: Exception) { } - } } diff --git a/android/src/main/java/com/smileidentity/react/SmileIDViewManager.kt b/android/src/main/java/com/smileidentity/react/SmileIDViewManager.kt index 43860df..7fcce8a 100644 --- a/android/src/main/java/com/smileidentity/react/SmileIDViewManager.kt +++ b/android/src/main/java/com/smileidentity/react/SmileIDViewManager.kt @@ -13,6 +13,16 @@ class SmileIDViewManager(private val mCallerContext: ReactApplicationContext) : return NAME } + override fun getExportedCustomBubblingEventTypeConstants(): Map { + return mapOf( + "onSmileResult" to mapOf( + "phasedRegistrationNames" to mapOf( + "bubbled" to "onResult" + ) + ) + ) + } + @ReactProp(name = "userId") fun setUserId(view: SmileIDView, userId: String?) { userId?.let { @@ -35,7 +45,7 @@ class SmileIDViewManager(private val mCallerContext: ReactApplicationContext) : } override fun createViewInstance(p0: ThemedReactContext): SmileIDView { - return SmileIDView(mCallerContext.currentActivity!!) + return SmileIDView(mCallerContext) } companion object { diff --git a/android/src/main/java/com/smileidentity/react/SmileIdModule.kt b/android/src/main/java/com/smileidentity/react/SmileIdModule.kt index fdeaa0f..e03a2c0 100644 --- a/android/src/main/java/com/smileidentity/react/SmileIdModule.kt +++ b/android/src/main/java/com/smileidentity/react/SmileIdModule.kt @@ -1,13 +1,19 @@ package com.smileidentity.react -import androidx.compose.runtime.Composable +import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactMethod -import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReadableMap import com.smileidentity.SmileID import com.smileidentity.SmileIdSpec -import com.smileidentity.compose.SmartSelfieEnrollment +import com.smileidentity.models.EnhancedKycRequest +import com.smileidentity.models.JobType +import com.smileidentity.models.PartnerParams +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + class SmileIdModule internal constructor(context: ReactApplicationContext) : SmileIdSpec(context) { @@ -16,14 +22,57 @@ class SmileIdModule internal constructor(context: ReactApplicationContext) : return NAME } - // Example method - // See https://reactnative.dev/docs/native-modules-android @ReactMethod - override fun initialize(promise: Promise) { - SmileID.initialize(reactApplicationContext) + override fun initialize(enableCrashReporting: Boolean, promise: Promise) { + SmileID.initialize(reactApplicationContext, enableCrashReporting = enableCrashReporting) promise.resolve(null) } + @ReactMethod + override fun doEnhancedKycAsync(request: ReadableMap, promise: Promise) = launch( + work = { + val partnerParams = request.getMap("partnerParams")!! + SmileID.api.doEnhancedKycAsync( + EnhancedKycRequest( + country = request.getString("country")!!, + idType = request.getString("idType")!!, + idNumber = request.getString("idNumber")!!, + firstName = request.getString("firstName"), + middleName = request.getString("middleName"), + lastName = request.getString("lastName"), + dob = request.getString("dob"), + phoneNumber = request.getString("phoneNumber"), + bankCode = request.getString("bankCode"), + callbackUrl = request.getString("callbackUrl"), + partnerParams = PartnerParams( + jobType = JobType.fromValue(partnerParams.getInt("jobType")), + jobId = partnerParams.getString("jobId")!!, + userId = partnerParams.getString("userId")!!, + extras = partnerParams.getMap("extras")?.toMap() ?: emptyMap() + ), + sourceSdk = "android (react-native)", + timestamp = partnerParams.getString("timestamp")!!, + signature = partnerParams.getString("signature")!!, + ) + ) + }, + promise = promise + ) + + + private fun launch( + work: suspend () -> T, + promise: Promise, + scope: CoroutineScope = CoroutineScope(Dispatchers.IO) + ) { + val handler = CoroutineExceptionHandler { _, throwable -> + promise.reject(throwable.message) + } + scope.launch(handler) { + promise.resolve(Result.success(work())) + } + } + companion object { const val NAME = "SmileId" } diff --git a/android/src/oldarch/SmileIdSpec.kt b/android/src/oldarch/SmileIdSpec.kt index 122bf47..e8df5d4 100644 --- a/android/src/oldarch/SmileIdSpec.kt +++ b/android/src/oldarch/SmileIdSpec.kt @@ -1,12 +1,13 @@ package com.smileidentity +import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule -import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReadableMap abstract class SmileIdSpec internal constructor(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { - abstract fun initialize(promise: Promise) + abstract fun initialize(enableCrashReporting: Boolean,promise: Promise) + abstract fun doEnhancedKycAsync(request: ReadableMap, promise: Promise) } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index b8a6f9c..e011c45 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,54 +1,53 @@ apply plugin: "com.android.application" apply plugin: "com.facebook.react" apply plugin: "kotlin-android" - /** * This is the configuration block to customize your React Native Android app. * By default you don't need to apply any configuration, just uncomment the lines you need. */ react { - /* Folders */ - // The root of your project, i.e. where "package.json" lives. Default is '..' - // root = file("../") - // The folder where the react-native NPM package is. Default is ../node_modules/react-native - // reactNativeDir = file("../node_modules/react-native") - // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen - // codegenDir = file("../node_modules/@react-native/codegen") - // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js - // cliFile = file("../node_modules/react-native/cli.js") - - /* Variants */ - // The list of variants to that are debuggable. For those we're going to - // skip the bundling of the JS bundle and the assets. By default is just 'debug'. - // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. - // debuggableVariants = ["liteDebug", "prodDebug"] - - /* Bundling */ - // A list containing the node command and its flags. Default is just 'node'. - // nodeExecutableAndArgs = ["node"] - // - // The command to run when bundling. By default is 'bundle' - // bundleCommand = "ram-bundle" - // - // The path to the CLI configuration file. Default is empty. - // bundleConfig = file(../rn-cli.config.js) - // - // The name of the generated asset file containing your JS bundle - // bundleAssetName = "MyApplication.android.bundle" - // - // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' - // entryFile = file("../js/MyApplication.android.js") - // - // A list of extra flags to pass to the 'bundle' commands. - // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle - // extraPackagerArgs = [] - - /* Hermes Commands */ - // The hermes compiler command to run. By default it is 'hermesc' - // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" - // - // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" - // hermesFlags = ["-O", "-output-source-map"] + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + // root = file("../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + // reactNativeDir = file("../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen + // codegenDir = file("../node_modules/@react-native/codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js + // cliFile = file("../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] } /** @@ -70,29 +69,32 @@ def enableProguardInReleaseBuilds = false def jscFlavor = 'org.webkit:android-jsc:+' android { - ndkVersion rootProject.ext.ndkVersion + ndkVersion rootProject.ext.ndkVersion - compileSdkVersion rootProject.ext.compileSdkVersion + compileSdkVersion rootProject.ext.compileSdkVersion - namespace "com.smileidentity.react.sample" - defaultConfig { - applicationId "com.smileidentity.react.sample" - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - signingConfig signingConfigs.debug - minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - } - } + namespace "com.smileidentity.react.sample" + + defaultConfig { + applicationId "com.smileidentity.react.sample" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + multiDexEnabled true + versionCode 1 + versionName "1.0" + } - buildFeatures { - buildConfig = true + buildTypes { + release { + signingConfig signingConfigs.debug + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } + } + + buildFeatures { + buildConfig = true + } compileOptions { sourceCompatibility JavaVersion.VERSION_17 @@ -109,20 +111,21 @@ android { } dependencies { - // The version of react-native is set by the React Native Gradle Plugin - implementation("com.facebook.react:react-android") + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") + implementation 'com.android.support:multidex:2.0.1' - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") - debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { - exclude group:'com.squareup.okhttp3', module:'okhttp' - } + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") + debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { + exclude group: 'com.squareup.okhttp3', module: 'okhttp' + } - debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") - if (hermesEnabled.toBoolean()) { - implementation("com.facebook.react:hermes-android") - } else { - implementation jscFlavor - } + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") + } else { + implementation jscFlavor + } } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/example/android/app/src/main/java/com/smileidentity/react/sample/MainActivity.kt b/example/android/app/src/main/java/com/smileidentity/react/sample/MainActivity.kt index 5d42aff..c45a465 100644 --- a/example/android/app/src/main/java/com/smileidentity/react/sample/MainActivity.kt +++ b/example/android/app/src/main/java/com/smileidentity/react/sample/MainActivity.kt @@ -1,28 +1,34 @@ package com.smileidentity.react.sample +import android.os.Bundle import com.facebook.react.ReactActivity import com.facebook.react.ReactActivityDelegate import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled import com.facebook.react.defaults.DefaultReactActivityDelegate + class MainActivity : ReactActivity() { - /** - * Returns the name of the main component registered from JavaScript. This is used to schedule - * rendering of the component. - */ - override fun getMainComponentName(): String? { - return "SmileIdExample" - } + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String? { + return "SmileIdExample" + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(null) + } - /** - * Returns the instance of the [ReactActivityDelegate]. Here we use a util class [ ] which allows you to easily enable Fabric and Concurrent React - * (aka React 18) with two boolean flags. - */ - override fun createReactActivityDelegate(): ReactActivityDelegate { - return DefaultReactActivityDelegate( - this, - mainComponentName!!, // If you opted-in for the New Architecture, we enable the Fabric Renderer. - fabricEnabled - ) - } + /** + * Returns the instance of the [ReactActivityDelegate]. Here we use a util class [ ] which allows you to easily enable Fabric and Concurrent React + * (aka React 18) with two boolean flags. + */ + override fun createReactActivityDelegate(): ReactActivityDelegate { + return DefaultReactActivityDelegate( + this, + mainComponentName!!, // If you opted-in for the New Architecture, we enable the Fabric Renderer. + fabricEnabled + ) + } } diff --git a/example/android/build.gradle b/example/android/build.gradle index 35b4205..8f23ada 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -6,10 +6,10 @@ buildscript { minSdkVersion = 21 compileSdkVersion = 34 targetSdkVersion = 34 - kotlinVersion = "1.8.0" + kotlinVersion = "1.9.10" // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. - ndkVersion = "21.3.6528147" + ndkVersion = "23.1.7779620" } repositories { maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } @@ -17,7 +17,7 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:8.1.0" + classpath "com.android.tools.build:gradle" classpath("com.facebook.react:react-native-gradle-plugin") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 7a9cbcf..838af6c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -375,6 +375,8 @@ PODS: - React-jsinspector (0.72.4) - React-logger (0.72.4): - glog + - react-native-safe-area-context (4.7.2): + - React-Core - react-native-smile-id (0.1.0): - RCT-Folly (= 2021.07.22.00) - React-Core @@ -489,6 +491,9 @@ PODS: - React-jsi (= 0.72.4) - React-logger (= 0.72.4) - React-perflogger (= 0.72.4) + - RNScreens (3.25.0): + - React-Core + - React-RCTImage - SmileID (10.0.0-beta06): - Zip (~> 2.1.0) - SocketRocket (0.6.1) @@ -543,6 +548,7 @@ DEPENDENCIES: - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - react-native-smile-id (from `../..`) - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) @@ -561,6 +567,7 @@ DEPENDENCIES: - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - RNScreens (from `../node_modules/react-native-screens`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: @@ -626,6 +633,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/jsinspector" React-logger: :path: "../node_modules/react-native/ReactCommon/logger" + react-native-safe-area-context: + :path: "../node_modules/react-native-safe-area-context" react-native-smile-id: :path: "../.." React-NativeModulesApple: @@ -662,6 +671,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/react/utils" ReactCommon: :path: "../node_modules/react-native/ReactCommon" + RNScreens: + :path: "../node_modules/react-native-screens" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" @@ -699,6 +710,7 @@ SPEC CHECKSUMS: React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594 React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77 + react-native-safe-area-context: 7aa8e6d9d0f3100a820efb1a98af68aa747f9284 react-native-smile-id: 6f7c0dd5cc4c5fb7a0d1af5361a078b629dc07d4 React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f React-perflogger: 496a1a3dc6737f964107cb3ddae7f9e265ddda58 @@ -717,6 +729,7 @@ SPEC CHECKSUMS: React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d + RNScreens: 85d3880b52d34db7b8eeebe2f1a0e807c05e69fa SmileID: b102f1f2e2ab35601d89ea618ef26c27b4489421 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 diff --git a/example/package.json b/example/package.json index cf698f6..4b82ac8 100644 --- a/example/package.json +++ b/example/package.json @@ -9,8 +9,12 @@ "pods": "pod-install --quiet" }, "dependencies": { + "@react-navigation/native": "^6.1.7", + "@react-navigation/native-stack": "^6.9.14", "react": "18.2.0", - "react-native": "0.72.4" + "react-native": "0.72.4", + "react-native-safe-area-context": "^4.7.2", + "react-native-screens": "^3.25.0" }, "devDependencies": { "@babel/core": "^7.20.0", @@ -18,10 +22,10 @@ "@babel/runtime": "^7.20.0", "@react-native/eslint-config": "^0.72.2", "@react-native/metro-config": "^0.72.11", - "metro-react-native-babel-preset": "0.76.8", - "babel-plugin-module-resolver": "^5.0.0" + "babel-plugin-module-resolver": "^5.0.0", + "metro-react-native-babel-preset": "0.76.8" }, "engines": { "node": ">=16" } -} \ No newline at end of file +} diff --git a/example/src/App.tsx b/example/src/App.tsx index d43237e..4d337f8 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,24 +1,31 @@ import * as React from 'react'; -import { StyleSheet, View, Text } from 'react-native'; +import { StyleSheet} from 'react-native'; import { SmileID } from 'react-native-smile-id'; -import SmileIDView from 'react-native-smile-id'; +import { NavigationContainer } from '@react-navigation/native'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { HomeScreen } from './HomeScreen'; +import { SmileIDCaptureScreen } from './SmileIDCaptureScreen'; + +const Stack = createNativeStackNavigator(); export default function App() { - const [result, setResult] = React.useState(); React.useEffect(() => { - SmileID.initialize().then(() => setResult('Initialized')); + SmileID.initialize(false); }, []); return ( - - - + + + + + + ); } diff --git a/example/src/HomeScreen.tsx b/example/src/HomeScreen.tsx new file mode 100644 index 0000000..2d2fee9 --- /dev/null +++ b/example/src/HomeScreen.tsx @@ -0,0 +1,36 @@ +import * as React from 'react'; + +import { Button, StyleSheet, View } from 'react-native'; + +export const HomeScreen = ({navigation}) => { + return ( + +