Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native Products Integration #2

Merged
merged 30 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
24571b9
feat: compose view skeleton
JNdhlovu Sep 4, 2023
5938d21
feat: props to native android for product,user id, job type, job id t…
JNdhlovu Sep 6, 2023
4c36c14
feat: props to native android for product,user id, job type, job id t…
JNdhlovu Sep 6, 2023
4ae08ab
feat: stack navigation in progress for the sample app
JNdhlovu Sep 25, 2023
eceee59
feat: wip stack nav
JNdhlovu Sep 25, 2023
53e5288
Update android/gradle.properties
JNdhlovu Sep 25, 2023
adef4be
feat: feedback
JNdhlovu Sep 25, 2023
8d8c461
feat: react native docv,smarselfie enroll, smartselfie auth
JNdhlovu Sep 29, 2023
b97851c
feat: stable rn prep for show and tell
JNdhlovu Oct 2, 2023
6931709
feat: product and biometric
JNdhlovu Oct 3, 2023
a544903
feat: bvn consent
JNdhlovu Oct 3, 2023
cc98e1e
feat: yarn lint fixes
JNdhlovu Oct 3, 2023
cc15a70
feat: lint fixes
JNdhlovu Oct 3, 2023
18d29dc
feat: patch react native screens issue
JNdhlovu Oct 6, 2023
4a3a2b8
feat: patch react native screens issue
JNdhlovu Oct 6, 2023
0ef405a
Update android/src/main/java/com/smileidentity/react/ReactUtils.kt
JNdhlovu Oct 10, 2023
0817e2a
feat: typings
JNdhlovu Oct 10, 2023
30b9178
feat: cleanup
JNdhlovu Oct 10, 2023
653db4f
feat: android nitts
JNdhlovu Oct 10, 2023
4ea249c
feat: refactor on maps from products
JNdhlovu Oct 10, 2023
525aa08
feat: refactor on maps from products
JNdhlovu Oct 10, 2023
91f4001
Update android/src/main/java/com/smileidentity/react/ReactUtils.kt
JNdhlovu Oct 11, 2023
eea2f99
Update src/index.tsx
JNdhlovu Oct 11, 2023
cb08a10
feat: wip renaming the packege
JNdhlovu Oct 13, 2023
c5d280d
fix: lint
JNdhlovu Oct 13, 2023
b7f1a58
feat: seperate view js
JNdhlovu Oct 13, 2023
80c1f01
feat: refactor to match react native
JNdhlovu Oct 16, 2023
744a1fd
feat: capture product
JNdhlovu Oct 16, 2023
bb9429d
feat: refactr complete
JNdhlovu Oct 17, 2023
9cd9f2b
feat: correct gradle repo and bvn also update to beta9
JNdhlovu Oct 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 39 additions & 12 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import com.android.Version

buildscript {
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["SmileId_kotlinVersion"]
Expand All @@ -6,12 +8,14 @@ buildscript {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}

dependencies {
classpath "com.android.tools.build:gradle:8.1.0"
classpath "com.android.tools.build:gradle:8.1.2"
// noinspection DifferentKotlinGradleVersion
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jlleitschuh.gradle:ktlint-gradle:11.6.0"
JNdhlovu marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -21,9 +25,8 @@ def isNewArchitectureEnabled() {

apply plugin: "com.android.library"
apply plugin: "kotlin-android"


def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
apply plugin: 'kotlin-kapt'
apply plugin: "org.jlleitschuh.gradle.ktlint"

if (isNewArchitectureEnabled()) {
apply plugin: "com.facebook.react"
Expand All @@ -38,7 +41,7 @@ def getExtOrIntegerDefault(name) {
}

def supportsNamespace() {
def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
def parsed = Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
def major = parsed[0].toInteger()
def minor = parsed[1].toInteger()

Expand Down Expand Up @@ -75,16 +78,25 @@ android {
}

buildFeatures {
buildConfig = true
buildConfig true
compose = true
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}

lintOptions {
disable "GradleCompatible"
}

composeOptions {
kotlinCompilerExtensionVersion '1.5.3'
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

sourceSets {
Expand All @@ -105,18 +117,33 @@ android {
repositories {
mavenCentral()
google()
gradlePluginPortal()
}

def kotlin_version = getExtOrDefault("kotlinVersion")
def smile_id_sdk_version = getExtOrDefault("androidVersion")

dependencies {
// For < 0.71, this will be from the local maven repo
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
implementation "com.facebook.react:react-native:0.72"
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.appcompat:appcompat:1.6.1'
implementation("androidx.navigation:navigation-compose:2.7.4")
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()) {
Expand Down
4 changes: 2 additions & 2 deletions android/gradle.properties
Original file line number Diff line number Diff line change
@@ -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-beta09
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
84 changes: 78 additions & 6 deletions android/src/main/java/com/smileidentity/react/SmileIdModule.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package com.smileidentity.react

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.models.EnhancedKycRequest
import com.smileidentity.react.utils.getStringOrDefault
import com.smileidentity.react.utils.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) {
Expand All @@ -12,14 +22,76 @@ class SmileIdModule internal constructor(context: ReactApplicationContext) :
return NAME
}

// 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(enableCrashReporting: Boolean, useSandBox: Boolean, promise: Promise) {
SmileID.initialize(
reactApplicationContext,
enableCrashReporting = enableCrashReporting,
useSandbox = useSandBox
)
promise.resolve(null)
}

@ReactMethod
override fun doEnhancedKycAsync(product: ReadableMap, promise: Promise) = launch(
work = {
val partnerParams = product.partnerParams()
partnerParams ?: run {
throw IllegalArgumentException("partnerParams is required for enhanced kyc")
}
val country = product.getStringOrDefault("country",null) ?: run {
throw IllegalArgumentException("country is required for enhanced kyc")
}
val idType = product.getStringOrDefault("idType",null) ?: run {
throw IllegalArgumentException("idType is required for enhanced kyc")
}
val idNumber = product.getStringOrDefault("idNumber",null) ?: run {
throw IllegalArgumentException("idNumber is required for enhanced kyc")
}

val timestamp = partnerParams?.extras?.get("timestamp") ?: run {
throw IllegalArgumentException("partnerParams.timestamp is required for enhanced kyc")
}
val signature = partnerParams?.extras?.get("timestamp") ?: run {
throw IllegalArgumentException("partnerParams.signature is required for enhanced kyc")
}
SmileID.api.doEnhancedKycAsync(
EnhancedKycRequest(
country = country,
idType = idType,
idNumber = idNumber,
firstName = product.getString("firstName"),
middleName = product.getString("middleName"),
lastName = product.getString("lastName"),
dob = product.getString("dob"),
phoneNumber = product.getString("phoneNumber"),
bankCode = product.getString("bankCode"),
callbackUrl = product.getString("callbackUrl"),
partnerParams = partnerParams,
sourceSdk = "android (react-native)",
timestamp = timestamp,
signature = signature,
)
)
},
promise = promise
)


private fun <T> 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"
const val NAME = "SmileID"
}
}
22 changes: 18 additions & 4 deletions android/src/main/java/com/smileidentity/react/SmileIdPackage.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
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.smileidentity.react.BuildConfig
import java.util.HashMap
import com.facebook.react.module.model.ReactModuleInfoProvider
import com.facebook.react.uimanager.ViewManager
import com.smileidentity.react.viewmanagers.SmileIDBVNConsentViewManager
import com.smileidentity.react.viewmanagers.SmileIDBiometricKYCViewManager
import com.smileidentity.react.viewmanagers.SmileIDDocumentVerificationViewManager
import com.smileidentity.react.viewmanagers.SmileIDSmartSelfieAuthenticationViewManager
import com.smileidentity.react.viewmanagers.SmileIDSmartSelfieEnrollmentViewManager

class SmileIdPackage : TurboReactPackage() {

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
listOf(SmileIDSmartSelfieEnrollmentViewManager(reactContext),
SmileIDSmartSelfieAuthenticationViewManager(reactContext),
SmileIDDocumentVerificationViewManager(reactContext),
SmileIDBVNConsentViewManager(reactContext),
SmileIDBiometricKYCViewManager(reactContext),
)


override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
return if (name == SmileIdModule.NAME) {
SmileIdModule(reactContext)
Expand Down
91 changes: 91 additions & 0 deletions android/src/main/java/com/smileidentity/react/utils/ReactUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.smileidentity.react.utils

import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.ReadableType
import com.smileidentity.models.IdInfo
import com.smileidentity.models.JobType
import com.smileidentity.models.PartnerParams
import com.smileidentity.util.randomUserId
import timber.log.Timber

fun ReadableMap.toMap(): Map<String, String> {
val map = mutableMapOf<String, String>()
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.idInfo(): IdInfo? {
val idInfoMap = getMapOrDefault("idInfo", null)
val country = idInfoMap?.getStringOrDefault("country", null) ?: run {
Timber.e("idInfo.country is required")
return null
}
return IdInfo(
country = country,
idType = idInfoMap.getStringOrDefault("idType", null),
idNumber = idInfoMap.getStringOrDefault("idNumber", null),
firstName = idInfoMap.getStringOrDefault("firstName", null),
middleName = idInfoMap.getStringOrDefault("middleName", null),
lastName = idInfoMap.getStringOrDefault("lastName", null),
dob = idInfoMap.getStringOrDefault("dob", null),
bankCode = idInfoMap.getStringOrDefault("bankCode", null),
entered = idInfoMap.getBoolOrDefault("entered", false),
)
}


fun ReadableMap.partnerParams(): PartnerParams? {
val partnerParams = getMapOrDefault("partnerParams", null) ?: run {
Timber.w("partnerParams is required")
return null
}
val jobTypeValue = partnerParams.getIntOrDefault("jobType", null)
val jobType = if (jobTypeValue != null) JobType.fromValue(jobTypeValue) else null
return PartnerParams(
jobType = jobType,
userId = partnerParams.getStringOrDefault("userId", null) ?: run { randomUserId() },
jobId = partnerParams.getStringOrDefault("jobId", null) ?: run { randomUserId() },
extras = partnerParams.getMapOrDefault("extras", null)?.toMap() ?: run { emptyMap() },
)
}


fun ReadableMap.getBoolOrDefault(key: String, defaultValue: Boolean): Boolean {
if (hasKey(key)) {
return getBoolean(key)
}
return defaultValue
}

fun ReadableMap.getStringOrDefault(key: String, defaultValue: String?): String? {
if (hasKey(key)) {
return getString(key)
}
return defaultValue
}

fun ReadableMap.getIntOrDefault(key: String, defaultValue: Int?): Int? {
if (hasKey(key)) {
return getInt(key)
}
return defaultValue
}

fun ReadableMap.getMapOrDefault(key: String, defaultValue: ReadableMap?): ReadableMap? {
if (hasKey(key)) {
return getMap(key)
}
return defaultValue
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.smileidentity.react.viewmanagers

import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReadableMap
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
import com.smileidentity.react.views.SmileIDBVNConsentScreen


@ReactModule(name = SmileIDBVNConsentViewManager.NAME)
class SmileIDBVNConsentViewManager(private val reactApplicationContext: ReactApplicationContext) :
SimpleViewManager<SmileIDBVNConsentScreen>() {
override fun getName(): String {
return NAME
}

override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
return mapOf(
"onSmileResult" to mapOf(
"phasedRegistrationNames" to mapOf(
"bubbled" to "onResult"
)
)
)
}

@ReactProp(name = "product")
fun setProduct(view: SmileIDBVNConsentScreen, product: ReadableMap) {
view.product = product
}

override fun createViewInstance(p0: ThemedReactContext): SmileIDBVNConsentScreen {
return SmileIDBVNConsentScreen(reactApplicationContext)
}

companion object {
const val NAME = "SmileIDBVNConsentScreenView"
}

}
Loading