dojah-kyc-sdk-react_native 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -125
- package/android/build.gradle +3 -5
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/com/dojahkyc/{rn/DojahKycModule.kt → DojahKycModule.kt} +21 -11
- package/android/src/main/java/com/dojahkyc/{rn/DojahKycPackage.kt → DojahKycPackage.kt} +1 -1
- package/ios/DojahKyc.mm +8 -15
- package/ios/DojahKyc.swift +399 -155
- package/lib/commonjs/index.js +7 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +7 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +9 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +15 -19
- package/android/proguard-rules.pro +0 -50
package/README.md
CHANGED
|
@@ -35,14 +35,6 @@ dependencyResolutionManagement {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
### Enable Jetifier
|
|
39
|
-
Enable Jetifier in android/gradle.properties
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
android.enableJetifier=true
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
|
|
46
38
|
### Permissions
|
|
47
39
|
For Android you don't need to declare permissions, its already included in the Package.
|
|
48
40
|
|
|
@@ -133,8 +125,8 @@ To start KYC, import Dojah in your React Native code, and launch Dojah Screen
|
|
|
133
125
|
import {launchDojahKyc } from 'dojah-kyc-sdk-react_native';
|
|
134
126
|
|
|
135
127
|
|
|
136
|
-
/**
|
|
137
|
-
* The following parameters are available
|
|
128
|
+
/**
|
|
129
|
+
* The following parameters are available
|
|
138
130
|
* for launching the flow.
|
|
139
131
|
*/
|
|
140
132
|
|
|
@@ -213,11 +205,11 @@ const metadata = {
|
|
|
213
205
|
key2: 'value2'
|
|
214
206
|
};
|
|
215
207
|
|
|
216
|
-
/**
|
|
217
|
-
* to launch the flow only [widgetId] is mandatory
|
|
208
|
+
/**
|
|
209
|
+
* to launch the flow only [widgetId] is mandatory
|
|
218
210
|
* @returns - the Promise of the result, promise
|
|
219
|
-
* will return a status that you can use to track
|
|
220
|
-
* the immidiate progress.
|
|
211
|
+
* will return a status that you can use to track
|
|
212
|
+
* the immidiate progress.
|
|
221
213
|
* @throws - an error if the Dojah KYC flow fails
|
|
222
214
|
*/
|
|
223
215
|
launchDojahKyc(
|
|
@@ -258,7 +250,6 @@ launchDojahKyc(
|
|
|
258
250
|
- `WidgetID` - a `REQUIRED` parameter. You get this ID when you sign up on the Dojah platform, follow the next step to generate your WidgetId.
|
|
259
251
|
- `Reference ID` - an `OPTIONAL` parameter that allows you to initialize the SDK for an ongoing verification.
|
|
260
252
|
- `Email Address` - an `OPTIONAL` parameter that allows you to initialize the SDK for an ongoing verification.
|
|
261
|
-
- `ExtraUserData` - an `OPTIONAL` parameter that allows you to pass custom data to the SDK.
|
|
262
253
|
|
|
263
254
|
## How to Get a Widget ID
|
|
264
255
|
To use the SDK, you need a WidgetID, which is a required parameter for initializing the SDK. You can obtain this by creating a flow on the Dojah platform. Follow these steps to configure and get your Widget ID:
|
|
@@ -289,113 +280,3 @@ To use the SDK, you need a WidgetID, which is a required parameter for initializ
|
|
|
289
280
|
|
|
290
281
|
7. Copy Your Widget ID: After publishing, the platform will generate a Widget ID. Copy this Widget ID as you will need it to initialize the SDK as stated above.
|
|
291
282
|
```
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
## TroubleShooting
|
|
295
|
-
|
|
296
|
-
### Android ProGuard/R8 Configuration for Release Builds
|
|
297
|
-
When building your Android application in release mode with code shrinking (R8/ProGuard) enabled, you might encounter issues where the SDK or its dependencies fail to function correctly. This happens because R8, the default code shrinker, might remove classes or methods that are used by the SDK but aren't explicitly referenced in a way R8 can detect.
|
|
298
|
-
|
|
299
|
-
If you experience crashes or unexpected behavior related to missing classes (often indicated by errors like ClassNotFoundException or Missing classes detected while running R8), you'll need to add specific "keep" rules to your project's ProGuard configuration.
|
|
300
|
-
|
|
301
|
-
### How to Apply ProGuard Rules
|
|
302
|
-
|
|
303
|
-
Locate your ProGuard file: In your Flutter project, navigate to android/app/proguard-rules.pro. If this file doesn't exist, create it.
|
|
304
|
-
|
|
305
|
-
Add the necessary rules: Open the proguard-rules.pro file and add the following lines. These rules instruct R8 to preserve the essential components of the Dojah SDK and its underlying libraries during the build process.
|
|
306
|
-
|
|
307
|
-
```
|
|
308
|
-
# These are essential for React Native's internal mechanisms and module linking.
|
|
309
|
-
-keepclassmembers class com.facebook.react.bridge.JavaModule$$Props { *; }
|
|
310
|
-
-keepclassmembers class com.facebook.react.bridge.ModuleSpec { *; }
|
|
311
|
-
-keepclassmembers class * implements com.facebook.react.bridge.JavaScriptModule { *; }
|
|
312
|
-
-keepclassmembers class * implements com.facebook.react.bridge.NativeModule { *; }
|
|
313
|
-
|
|
314
|
-
# Prevents the stripping of unused methods in classes that are accessed dynamically.
|
|
315
|
-
-keep public class * extends com.facebook.react.bridge.ViewManager { *; }
|
|
316
|
-
-keep public class * extends com.facebook.react.uimanager.ViewManager { *; } # Older versions might use this
|
|
317
|
-
|
|
318
|
-
# Keep React Native module classes and their constructors.
|
|
319
|
-
# This is crucial for autolinking and manual linking.
|
|
320
|
-
-keep class * implements com.facebook.react.bridge.NativeModule {
|
|
321
|
-
<init>(...);
|
|
322
|
-
}
|
|
323
|
-
-keep class * extends com.facebook.react.bridge.BaseJavaModule {
|
|
324
|
-
<init>(...);
|
|
325
|
-
}
|
|
326
|
-
-keep class * extends com.facebook.react.uimanager.ViewManager {
|
|
327
|
-
<init>(...);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
# Standard dontwarn rules for common React Native dependencies
|
|
331
|
-
-dontwarn com.facebook.react.**
|
|
332
|
-
-dontwarn com.facebook.jni.**
|
|
333
|
-
-dontwarn com.facebook.soloader.**
|
|
334
|
-
-dontwarn com.facebook.yoga.**
|
|
335
|
-
-dontwarn javax.annotation.**
|
|
336
|
-
|
|
337
|
-
# Keep gRPC-related classes
|
|
338
|
-
-keep class io.grpc.** { *; }
|
|
339
|
-
-keep class com.google.android.libraries.places.** { *; }
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
-keepnames class io.grpc.internal.**
|
|
343
|
-
-keepclassmembers class io.grpc.internal.** { *; }
|
|
344
|
-
-dontwarn io.grpc.**
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
-keep class com.dojah.kyc_sdk_kotlin.domain.** { *; }
|
|
348
|
-
-keep class com.dojah.kyc_sdk_kotlin.core.Result
|
|
349
|
-
|
|
350
|
-
#For retrofit
|
|
351
|
-
-keepattributes Signature, InnerClasses, EnclosingMethod
|
|
352
|
-
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
|
|
353
|
-
-keepattributes AnnotationDefault
|
|
354
|
-
-keepclassmembers,allowshrinking,allowobfuscation interface * {
|
|
355
|
-
@retrofit2.http.* <methods>;
|
|
356
|
-
}
|
|
357
|
-
-dontwarn javax.annotation.**
|
|
358
|
-
-dontwarn kotlin.Unit
|
|
359
|
-
-dontwarn retrofit2.KotlinExtensions
|
|
360
|
-
-dontwarn retrofit2.KotlinExtensions$*
|
|
361
|
-
-if interface * { @retrofit2.http.* <methods>; }
|
|
362
|
-
-keep,allowobfuscation interface <1>
|
|
363
|
-
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
|
|
364
|
-
-keep,allowobfuscation,allowshrinking class retrofit2.Response
|
|
365
|
-
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
|
|
366
|
-
|
|
367
|
-
#For Okio
|
|
368
|
-
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
|
369
|
-
|
|
370
|
-
#For Gson
|
|
371
|
-
-keep class sun.misc.Unsafe { *; }
|
|
372
|
-
-keep class com.google.gson.examples.android.model.** { *; }
|
|
373
|
-
|
|
374
|
-
#For Glide
|
|
375
|
-
-keep public class * implements com.bumptech.glide.module.GlideModule
|
|
376
|
-
-keep class * extends com.bumptech.glide.module.AppGlideModule {
|
|
377
|
-
<init>(...);
|
|
378
|
-
}
|
|
379
|
-
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
|
|
380
|
-
**[] $VALUES;
|
|
381
|
-
public *;
|
|
382
|
-
}
|
|
383
|
-
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
|
|
384
|
-
*** rewind();
|
|
385
|
-
}
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
Ensure ProGuard is enabled: Verify that proguardFiles is pointing to the default Android ProGuard rules and your custom proguard-rules.pro file. This tells R8 to use your added rules.
|
|
389
|
-
Your release build type block should look similar to this:
|
|
390
|
-
|
|
391
|
-
``` groovy
|
|
392
|
-
android {
|
|
393
|
-
buildTypes {
|
|
394
|
-
release {
|
|
395
|
-
// ... other configurations like signingConfig
|
|
396
|
-
minifyEnabled true
|
|
397
|
-
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
```
|
package/android/build.gradle
CHANGED
|
@@ -55,7 +55,7 @@ def supportsNamespace() {
|
|
|
55
55
|
|
|
56
56
|
android {
|
|
57
57
|
if (supportsNamespace()) {
|
|
58
|
-
namespace "com.dojahkyc
|
|
58
|
+
namespace "com.dojahkyc"
|
|
59
59
|
|
|
60
60
|
sourceSets {
|
|
61
61
|
main {
|
|
@@ -74,8 +74,6 @@ android {
|
|
|
74
74
|
|
|
75
75
|
buildTypes {
|
|
76
76
|
release {
|
|
77
|
-
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
|
78
|
-
|
|
79
77
|
minifyEnabled true
|
|
80
78
|
}
|
|
81
79
|
}
|
|
@@ -107,8 +105,8 @@ dependencies {
|
|
|
107
105
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
108
106
|
|
|
109
107
|
// implementation 'com.github.dojah-inc:sdk-kotlin:v0.0.1-dev'
|
|
110
|
-
implementation 'com.github.dojah-inc:sdk-kotlin:v0.
|
|
111
|
-
|
|
108
|
+
// implementation 'com.github.dojah-inc:sdk-kotlin:v0.0.4-dev'
|
|
109
|
+
implementation 'com.github.dojah-inc:sdk-kotlin:v0.2.0'
|
|
112
110
|
|
|
113
111
|
}
|
|
114
112
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
package com.dojahkyc
|
|
1
|
+
package com.dojahkyc
|
|
2
2
|
|
|
3
3
|
import android.app.Activity
|
|
4
|
+
import android.app.Activity.RESULT_OK
|
|
4
5
|
import android.content.Intent
|
|
6
|
+
import android.widget.Toast
|
|
5
7
|
import com.dojah.kyc_sdk_kotlin.DojahSdk
|
|
6
8
|
import com.dojah.kyc_sdk_kotlin.DOJAH_RESULT_KEY
|
|
7
9
|
// import com.dojah.kyc_sdk_kotlin.BACKWARD_CALL_REQUEST_CODE
|
|
@@ -13,6 +15,9 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
|
13
15
|
import com.facebook.react.bridge.ReactMethod
|
|
14
16
|
import com.facebook.react.bridge.WritableMap
|
|
15
17
|
import com.facebook.react.bridge.WritableNativeMap
|
|
18
|
+
import androidx.activity.result.ActivityResult
|
|
19
|
+
import androidx.activity.result.ActivityResultLauncher
|
|
20
|
+
import androidx.activity.result.contract.ActivityResultContracts
|
|
16
21
|
import com.facebook.react.bridge.ReadableMap
|
|
17
22
|
import com.dojah.kyc_sdk_kotlin.domain.UserData
|
|
18
23
|
import com.dojah.kyc_sdk_kotlin.domain.GovData
|
|
@@ -41,13 +46,7 @@ class DojahKycModule(private val reactContext: ReactApplicationContext) :
|
|
|
41
46
|
widgetId: String,
|
|
42
47
|
referenceId: String? = null,
|
|
43
48
|
email: String? = null,
|
|
44
|
-
|
|
45
|
-
govData: ReadableMap? = null,
|
|
46
|
-
govId: ReadableMap? = null,
|
|
47
|
-
location: ReadableMap? = null,
|
|
48
|
-
businessData: ReadableMap? = null,
|
|
49
|
-
address: String? = null,
|
|
50
|
-
metadata: ReadableMap? = null,
|
|
49
|
+
extraData: ReadableMap? = null,
|
|
51
50
|
promise: Promise
|
|
52
51
|
) {
|
|
53
52
|
val activity = currentActivity
|
|
@@ -58,6 +57,15 @@ class DojahKycModule(private val reactContext: ReactApplicationContext) :
|
|
|
58
57
|
}
|
|
59
58
|
this.promise = promise
|
|
60
59
|
try {
|
|
60
|
+
// Extract individual data from extraData object
|
|
61
|
+
val userData = extraData?.getMap("userData")
|
|
62
|
+
val govData = extraData?.getMap("govData")
|
|
63
|
+
val govId = extraData?.getMap("govId")
|
|
64
|
+
val location = extraData?.getMap("location")
|
|
65
|
+
val businessData = extraData?.getMap("businessData")
|
|
66
|
+
val address = extraData?.getString("address")
|
|
67
|
+
val metadata = extraData?.getMap("metadata")
|
|
68
|
+
|
|
61
69
|
DojahSdk.with(reactContext)
|
|
62
70
|
.launchWithBackwardCompatibility(activity, widgetId, referenceId, email, extraData = ExtraUserData(
|
|
63
71
|
userData = UserData(
|
|
@@ -94,7 +102,7 @@ class DojahKycModule(private val reactContext: ReactApplicationContext) :
|
|
|
94
102
|
// this.promise.reject("LAUNCH_ERROR", e.message, e)
|
|
95
103
|
// this.promise = null
|
|
96
104
|
}
|
|
97
|
-
|
|
105
|
+
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
|
|
@@ -109,7 +117,7 @@ class DojahKycModule(private val reactContext: ReactApplicationContext) :
|
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
|
|
112
|
-
override fun onActivityResult(activity:Activity
|
|
120
|
+
override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
|
|
113
121
|
if (requestCode == BACKWARD_CALL_REQUEST_CODE) {
|
|
114
122
|
if (resultCode == Activity.RESULT_OK) {
|
|
115
123
|
val result = data?.getStringExtra(DOJAH_RESULT_KEY)
|
|
@@ -121,7 +129,9 @@ class DojahKycModule(private val reactContext: ReactApplicationContext) :
|
|
|
121
129
|
}
|
|
122
130
|
}
|
|
123
131
|
|
|
124
|
-
override fun onNewIntent(intent: Intent
|
|
132
|
+
override fun onNewIntent(intent: Intent) {
|
|
133
|
+
// Intent is guaranteed to be non-null in React Native New Architecture
|
|
134
|
+
// No implementation needed for this use case
|
|
125
135
|
}
|
|
126
136
|
|
|
127
137
|
companion object {
|
package/ios/DojahKyc.mm
CHANGED
|
@@ -20,20 +20,13 @@
|
|
|
20
20
|
|
|
21
21
|
RCT_EXTERN_METHOD(initialize:(NSString)appName)
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
RCT_EXTERN_METHOD(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
withLocation:(NSDictionary *)location
|
|
32
|
-
withBuisnessData:(NSDictionary *)businessData
|
|
33
|
-
withAddress:(NSString *)address
|
|
34
|
-
withMetaData:(NSDictionary *)metadata
|
|
35
|
-
resolver:(RCTPromiseResolveBlock)resolve
|
|
36
|
-
rejecter:(RCTPromiseRejectBlock)reject
|
|
37
|
-
)
|
|
23
|
+
|
|
24
|
+
RCT_EXTERN_METHOD(launch:(NSString)widgetId withReferenceId:(id)referenceId withEmail:(id)email withExtraData:(id)extraData withResolver:(RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject)
|
|
25
|
+
|
|
26
|
+
+ (BOOL)requiresMainQueueSetup
|
|
27
|
+
{
|
|
28
|
+
return NO;
|
|
29
|
+
}
|
|
30
|
+
|
|
38
31
|
@end
|
|
39
32
|
|
package/ios/DojahKyc.swift
CHANGED
|
@@ -1,81 +1,171 @@
|
|
|
1
|
-
|
|
2
1
|
import UIKit
|
|
3
2
|
import Foundation
|
|
4
3
|
import DojahWidget
|
|
5
4
|
import React
|
|
6
5
|
|
|
6
|
+
// Extension to convert dictionary to ExtraUserData (for React Native CLI compatibility)
|
|
7
|
+
extension Dictionary where Key == String, Value == Any {
|
|
8
|
+
func toExtraUserData() -> ExtraUserData {
|
|
9
|
+
let userDataDict = self["userData"] as? [String: Any]
|
|
10
|
+
let govDataDict = self["govData"] as? [String: Any]
|
|
11
|
+
let govIdDict = self["govId"] as? [String: Any]
|
|
12
|
+
let locationDict = self["location"] as? [String: Any]
|
|
13
|
+
let businessDataDict = self["businessData"] as? [String: Any]
|
|
14
|
+
let address = self["address"] as? String
|
|
15
|
+
let metadata = self["metadata"] as? [String: Any]
|
|
16
|
+
|
|
17
|
+
return ExtraUserData(
|
|
18
|
+
userData: UserBioData(
|
|
19
|
+
firstName: userDataDict?["firstName"] as? String,
|
|
20
|
+
lastName: userDataDict?["lastName"] as? String,
|
|
21
|
+
dob: userDataDict?["dob"] as? String,
|
|
22
|
+
email: userDataDict?["email"] as? String
|
|
23
|
+
),
|
|
24
|
+
govData: ExtraGovData(
|
|
25
|
+
bvn: govDataDict?["bvn"] as? String,
|
|
26
|
+
dl: govDataDict?["dl"] as? String,
|
|
27
|
+
nin: govDataDict?["nin"] as? String,
|
|
28
|
+
vnin: govDataDict?["vnin"] as? String
|
|
29
|
+
),
|
|
30
|
+
govId: ExtraGovIdData(
|
|
31
|
+
national: govIdDict?["national"] as? String,
|
|
32
|
+
passport: govIdDict?["passport"] as? String,
|
|
33
|
+
dl: govIdDict?["dl"] as? String,
|
|
34
|
+
voter: govIdDict?["voter"] as? String,
|
|
35
|
+
nin: govIdDict?["nin"] as? String,
|
|
36
|
+
others: govIdDict?["others"] as? String
|
|
37
|
+
),
|
|
38
|
+
location: ExtraLocationData(
|
|
39
|
+
longitude: locationDict?["longitude"] as? String,
|
|
40
|
+
latitude: locationDict?["latitude"] as? String
|
|
41
|
+
),
|
|
42
|
+
businessData: ExtraBusinessData(
|
|
43
|
+
cac: businessDataDict?["cac"] as? String
|
|
44
|
+
),
|
|
45
|
+
address: address,
|
|
46
|
+
metadata: metadata
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// Custom NavigationController that prevents duplicate presentations
|
|
53
|
+
class SafeDojahNavigationController: UINavigationController {
|
|
54
|
+
private var isPresenting = false
|
|
55
|
+
|
|
56
|
+
override func present(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)? = nil) {
|
|
57
|
+
// Check if we're already presenting something
|
|
58
|
+
if isPresenting {
|
|
59
|
+
print("⚠️ Already presenting, preventing duplicate: \(String(describing: type(of: viewControllerToPresent)))")
|
|
60
|
+
completion?()
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check if this view controller is already in the navigation stack
|
|
65
|
+
if viewControllers.contains(where: {
|
|
66
|
+
type(of: $0) == type(of: viewControllerToPresent)
|
|
67
|
+
}) {
|
|
68
|
+
print("⚠️ ViewController already in navigation stack: \(String(describing: type(of: viewControllerToPresent)))")
|
|
69
|
+
completion?()
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Check if we're already presenting something
|
|
74
|
+
if presentedViewController != nil {
|
|
75
|
+
print("⚠️ NavigationController already has a presentedViewController")
|
|
76
|
+
completion?()
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Mark as presenting
|
|
81
|
+
isPresenting = true
|
|
82
|
+
|
|
83
|
+
// Call super to actually present
|
|
84
|
+
super.present(viewControllerToPresent, animated: animated) { [weak self] in
|
|
85
|
+
self?.isPresenting = false
|
|
86
|
+
completion?()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
override func dismiss(animated: Bool, completion: (() -> Void)? = nil) {
|
|
91
|
+
isPresenting = false
|
|
92
|
+
super.dismiss(animated: animated, completion: completion)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
7
95
|
|
|
8
96
|
class DojahNavigationControllerDelegate: NSObject, UINavigationControllerDelegate {
|
|
9
97
|
var onDidShow: (UIViewController) -> Void = { _ in }
|
|
98
|
+
|
|
10
99
|
func navigationController(_ navigationController: UINavigationController,
|
|
11
100
|
didShow viewController: UIViewController,
|
|
12
101
|
animated: Bool) {
|
|
13
|
-
print("Did show: \(viewController)")
|
|
102
|
+
print("📱 Did show: \(viewController)")
|
|
14
103
|
onDidShow(viewController)
|
|
15
104
|
}
|
|
16
|
-
|
|
17
|
-
func navigationController(_ navigationController: UINavigationController,
|
|
18
|
-
willShow viewController: UIViewController,
|
|
19
|
-
animated: Bool) {
|
|
20
|
-
print("Will show: \(viewController)")
|
|
21
|
-
}
|
|
22
105
|
|
|
23
106
|
func setOnDidShow(_ onDidShow: @escaping (UIViewController) -> Void) {
|
|
24
107
|
self.onDidShow = onDidShow
|
|
25
108
|
}
|
|
26
109
|
}
|
|
27
110
|
|
|
111
|
+
class DojahPresentationControllerDelegate: NSObject, UIAdaptivePresentationControllerDelegate {
|
|
112
|
+
var onDidDismiss: () -> Void = { }
|
|
113
|
+
|
|
114
|
+
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
|
115
|
+
print("🛑 Modal was dismissed manually")
|
|
116
|
+
onDidDismiss()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
func setOnDidDismiss(_ onDidDismiss: @escaping () -> Void) {
|
|
120
|
+
self.onDidDismiss = onDidDismiss
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
28
124
|
@objc(DojahKyc)
|
|
29
125
|
class DojahKyc: RCTEventEmitter, RCTBridgeDelegate {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
override init() {
|
|
41
|
-
super.init()
|
|
42
|
-
|
|
43
|
-
DispatchQueue.main.async {
|
|
44
|
-
self.navCtrl = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController
|
|
45
|
-
if self.navCtrl != nil {
|
|
46
|
-
self.navCtrl!.delegate = self.navDelegate
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
func sourceURL(for bridge: RCTBridge) -> URL? {
|
|
126
|
+
|
|
127
|
+
// Track Dojah state
|
|
128
|
+
private var isDojahActive = false
|
|
129
|
+
private var dojahNavController: SafeDojahNavigationController?
|
|
130
|
+
private var prevController: UIViewController? // Track previous controller for DJDisclaimer handling
|
|
131
|
+
private var hasSeenSDKInit = false // Track if we've seen SDKInitViewController before
|
|
132
|
+
private var navDelegate = DojahNavigationControllerDelegate()
|
|
133
|
+
private var presentationDelegate = DojahPresentationControllerDelegate()
|
|
134
|
+
|
|
135
|
+
func sourceURL(for bridge: RCTBridge) -> URL? {
|
|
52
136
|
#if DEBUG
|
|
53
137
|
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index", fallbackExtension: nil)
|
|
54
138
|
#else
|
|
55
139
|
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")!
|
|
56
140
|
#endif
|
|
57
141
|
}
|
|
58
|
-
|
|
59
|
-
|
|
142
|
+
|
|
60
143
|
override var methodQueue: DispatchQueue {
|
|
61
144
|
return DispatchQueue.main;
|
|
62
145
|
}
|
|
63
|
-
|
|
64
|
-
|
|
146
|
+
|
|
147
|
+
override class func requiresMainQueueSetup() -> Bool {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
override func supportedEvents() -> [String]! {
|
|
152
|
+
return ["onChange"]
|
|
153
|
+
}
|
|
154
|
+
|
|
65
155
|
@objc(initialize:)
|
|
66
156
|
func initialize(appName:String) -> Void {
|
|
67
157
|
// Initialize the React Native bridge
|
|
68
158
|
if let bridge = RCTBridge(delegate: self, launchOptions: nil) {
|
|
69
159
|
// Create a React Native root view with the provided module name
|
|
70
160
|
let rootView = RCTRootView(bridge: bridge, moduleName: appName, initialProperties: nil)
|
|
71
|
-
|
|
161
|
+
|
|
72
162
|
// Create the initial view controller with the React Native view
|
|
73
163
|
let rootViewController = UIViewController()
|
|
74
164
|
rootViewController.view = rootView
|
|
75
|
-
|
|
165
|
+
|
|
76
166
|
// Create a UINavigationController and set it as the window's rootViewController
|
|
77
167
|
let navigationController = UINavigationController(rootViewController: rootViewController)
|
|
78
|
-
|
|
168
|
+
|
|
79
169
|
// Set the window's rootViewController
|
|
80
170
|
if let window = UIApplication.shared.delegate?.window {
|
|
81
171
|
window?.rootViewController = navigationController
|
|
@@ -84,129 +174,283 @@ class DojahKyc: RCTEventEmitter, RCTBridgeDelegate {
|
|
|
84
174
|
}else{
|
|
85
175
|
print("bridge is null")
|
|
86
176
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
177
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
resolve(status)
|
|
116
|
-
print("resolve onDidShow: \(vc)")
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
self.prevController = nil
|
|
120
|
-
}else if(String(describing:vc).contains("DojahWidget.DJDisclaimer")
|
|
121
|
-
&& self.prevController != nil){
|
|
122
|
-
self.navCtrl?.popToRootViewController(animated: false)
|
|
123
|
-
}else if(!String(describing:vc).contains("DojahWidget.SDKInitViewController")){
|
|
124
|
-
self.prevController = vc
|
|
178
|
+
|
|
179
|
+
private func getTopViewController() -> UIViewController? {
|
|
180
|
+
// Try multiple approaches to find the root view controller
|
|
181
|
+
// This handles React Native's window hierarchy setup
|
|
182
|
+
|
|
183
|
+
// Approach 1: Try window scene (iOS 13+)
|
|
184
|
+
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
|
|
185
|
+
// Try the key window first
|
|
186
|
+
if let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }),
|
|
187
|
+
let rootViewController = keyWindow.rootViewController {
|
|
188
|
+
var topViewController = rootViewController
|
|
189
|
+
while let presentedViewController = topViewController.presentedViewController {
|
|
190
|
+
topViewController = presentedViewController
|
|
191
|
+
}
|
|
192
|
+
return topViewController
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Try any window with a root view controller
|
|
196
|
+
if let window = windowScene.windows.first(where: { $0.rootViewController != nil }),
|
|
197
|
+
let rootViewController = window.rootViewController {
|
|
198
|
+
var topViewController = rootViewController
|
|
199
|
+
while let presentedViewController = topViewController.presentedViewController {
|
|
200
|
+
topViewController = presentedViewController
|
|
201
|
+
}
|
|
202
|
+
return topViewController
|
|
125
203
|
}
|
|
126
204
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
userData: mapToUserBioData(from: userData),
|
|
138
|
-
govData: mapToExtraGovData(from: govData),
|
|
139
|
-
govId: mapToExtraGovIdData(from: govId),
|
|
140
|
-
location: mapToExtraLocationData(from: location),
|
|
141
|
-
businessData: mapToExtraBusinessData(from: businessData),
|
|
142
|
-
metadata: metadata as? [String : Any]
|
|
143
|
-
),
|
|
144
|
-
navController: navCtrl!)
|
|
145
|
-
|
|
146
|
-
}catch{
|
|
147
|
-
reject("no-launch", "Could not launch Dojah Widget", error)
|
|
148
|
-
}
|
|
149
|
-
}else{
|
|
150
|
-
reject("no-launch", "Could not launch Dojah Widget", nil)
|
|
151
|
-
//throw error status to react native
|
|
152
|
-
print("rootViewController is nil")
|
|
205
|
+
|
|
206
|
+
// Approach 2: Fallback to delegate's window (for older React Native setups)
|
|
207
|
+
if let delegate = UIApplication.shared.delegate,
|
|
208
|
+
let window = delegate.window,
|
|
209
|
+
let rootViewController = window?.rootViewController {
|
|
210
|
+
var topViewController = rootViewController
|
|
211
|
+
while let presentedViewController = topViewController.presentedViewController {
|
|
212
|
+
topViewController = presentedViewController
|
|
213
|
+
}
|
|
214
|
+
return topViewController
|
|
153
215
|
}
|
|
216
|
+
|
|
217
|
+
print("⚠️ Could not find root view controller using any method")
|
|
218
|
+
return nil
|
|
154
219
|
}
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
// Mapping functions for each sub-struct
|
|
161
|
-
func mapToUserBioData(from dictionary: NSDictionary?) -> UserBioData? {
|
|
162
|
-
guard let userData = dictionary else { return nil }
|
|
163
|
-
|
|
164
|
-
return UserBioData(
|
|
165
|
-
firstName: userData["first_name"] as? String,
|
|
166
|
-
lastName: userData["last_name"] as? String,
|
|
167
|
-
dob: userData["dob"] as? String,
|
|
168
|
-
email: userData["email"] as? String
|
|
169
|
-
)
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
func mapToExtraGovData(from dictionary: NSDictionary?) -> ExtraGovData? {
|
|
173
|
-
guard let govData = dictionary else { return nil }
|
|
174
|
-
|
|
175
|
-
return ExtraGovData(
|
|
176
|
-
bvn: govData["bvn"] as? String,
|
|
177
|
-
dl: govData["dl"] as? String,
|
|
178
|
-
nin: govData["nin"] as? String,
|
|
179
|
-
vnin: govData["vnin"] as? String
|
|
180
|
-
)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
func mapToExtraGovIdData(from dictionary: NSDictionary?) -> ExtraGovIdData? {
|
|
184
|
-
guard let govId = dictionary else { return nil }
|
|
185
|
-
|
|
186
|
-
return ExtraGovIdData(
|
|
187
|
-
national: govId["national"] as? String,
|
|
188
|
-
passport: govId["passport"] as? String,
|
|
189
|
-
dl: govId["dl"] as? String,
|
|
190
|
-
voter: govId["voter"] as? String,
|
|
191
|
-
nin: govId["nin"] as? String,
|
|
192
|
-
others: govId["others"] as? String
|
|
193
|
-
)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
func mapToExtraLocationData(from dictionary: NSDictionary?) -> ExtraLocationData? {
|
|
197
|
-
guard let location = dictionary else { return nil }
|
|
198
220
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
221
|
+
private func resolveSdkResult() {
|
|
222
|
+
let vStatus = DojahWidgetSDK.getVerificationResultStatus()
|
|
223
|
+
let status = vStatus.isEmpty ? "closed" : vStatus
|
|
224
|
+
|
|
225
|
+
print("📊 Resolving SDK result: \(status)")
|
|
226
|
+
|
|
227
|
+
// Send event to React Native if bridge is valid
|
|
228
|
+
if self.bridge != nil && !self.bridge.isLoading {
|
|
229
|
+
self.sendEvent(withName: "onChange", body: ["status": status])
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Clear state
|
|
233
|
+
self.prevController = nil
|
|
234
|
+
self.hasSeenSDKInit = false
|
|
235
|
+
|
|
236
|
+
// Dismiss the navigation controller
|
|
237
|
+
self.dismissDojahController()
|
|
238
|
+
|
|
239
|
+
// Reset flag
|
|
240
|
+
self.isDojahActive = false
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private func dismissDojahController() {
|
|
244
|
+
DispatchQueue.main.async { [weak self] in
|
|
245
|
+
self?.dojahNavController?.dismiss(animated: true) {
|
|
246
|
+
self?.dojahNavController = nil
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
207
250
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
251
|
+
@objc(launch:withReferenceId:withEmail:withExtraData:withResolver:withRejecter:)
|
|
252
|
+
func launch(
|
|
253
|
+
widgetId: String,
|
|
254
|
+
referenceId: Any?,
|
|
255
|
+
email: Any?,
|
|
256
|
+
extraData: Any?,
|
|
257
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
258
|
+
reject: @escaping RCTPromiseRejectBlock
|
|
259
|
+
) -> Void {
|
|
260
|
+
// Handle null values - JavaScript null becomes NSNull in Objective-C
|
|
261
|
+
// Convert NSNull or nil to empty string
|
|
262
|
+
let safeReferenceId: String = {
|
|
263
|
+
if referenceId is NSNull || referenceId == nil {
|
|
264
|
+
return ""
|
|
265
|
+
}
|
|
266
|
+
return (referenceId as? String) ?? ""
|
|
267
|
+
}()
|
|
268
|
+
|
|
269
|
+
let safeEmail: String = {
|
|
270
|
+
if email is NSNull || email == nil {
|
|
271
|
+
return ""
|
|
272
|
+
}
|
|
273
|
+
return (email as? String) ?? ""
|
|
274
|
+
}()
|
|
275
|
+
|
|
276
|
+
// Parse extraData from React Native
|
|
277
|
+
// extraData is a dictionary containing: userData, govData, govId, location, businessData, address, metadata
|
|
278
|
+
var parsedExtraData: [String: Any]? = nil
|
|
279
|
+
|
|
280
|
+
if let extraDataDict = extraData as? [String: Any], !extraDataDict.isEmpty {
|
|
281
|
+
parsedExtraData = [:]
|
|
282
|
+
|
|
283
|
+
// Parse userData
|
|
284
|
+
if let userData = extraDataDict["userData"] as? [String: Any], !userData.isEmpty {
|
|
285
|
+
var parsedUserData: [String: Any] = [:]
|
|
286
|
+
if let firstName = userData["firstName"] as? String { parsedUserData["firstName"] = firstName }
|
|
287
|
+
if let lastName = userData["lastName"] as? String { parsedUserData["lastName"] = lastName }
|
|
288
|
+
if let dob = userData["dob"] as? String { parsedUserData["dob"] = dob }
|
|
289
|
+
if let email = userData["email"] as? String { parsedUserData["email"] = email }
|
|
290
|
+
if !parsedUserData.isEmpty { parsedExtraData?["userData"] = parsedUserData }
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Parse govData
|
|
294
|
+
if let govData = extraDataDict["govData"] as? [String: Any], !govData.isEmpty {
|
|
295
|
+
var parsedGovData: [String: Any] = [:]
|
|
296
|
+
if let bvn = govData["bvn"] as? String { parsedGovData["bvn"] = bvn }
|
|
297
|
+
if let dl = govData["dl"] as? String { parsedGovData["dl"] = dl }
|
|
298
|
+
if let nin = govData["nin"] as? String { parsedGovData["nin"] = nin }
|
|
299
|
+
if let vnin = govData["vnin"] as? String { parsedGovData["vnin"] = vnin }
|
|
300
|
+
if !parsedGovData.isEmpty { parsedExtraData?["govData"] = parsedGovData }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Parse govId
|
|
304
|
+
if let govId = extraDataDict["govId"] as? [String: Any], !govId.isEmpty {
|
|
305
|
+
var parsedGovId: [String: Any] = [:]
|
|
306
|
+
if let national = govId["national"] as? String { parsedGovId["national"] = national }
|
|
307
|
+
if let passport = govId["passport"] as? String { parsedGovId["passport"] = passport }
|
|
308
|
+
if let dl = govId["dl"] as? String { parsedGovId["dl"] = dl }
|
|
309
|
+
if let voter = govId["voter"] as? String { parsedGovId["voter"] = voter }
|
|
310
|
+
if let nin = govId["nin"] as? String { parsedGovId["nin"] = nin }
|
|
311
|
+
if let others = govId["others"] as? String { parsedGovId["others"] = others }
|
|
312
|
+
if !parsedGovId.isEmpty { parsedExtraData?["govId"] = parsedGovId }
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Parse location
|
|
316
|
+
if let location = extraDataDict["location"] as? [String: Any], !location.isEmpty {
|
|
317
|
+
var parsedLocation: [String: Any] = [:]
|
|
318
|
+
if let latitude = location["latitude"] as? String { parsedLocation["latitude"] = latitude }
|
|
319
|
+
if let longitude = location["longitude"] as? String { parsedLocation["longitude"] = longitude }
|
|
320
|
+
if !parsedLocation.isEmpty { parsedExtraData?["location"] = parsedLocation }
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Parse businessData
|
|
324
|
+
if let businessData = extraDataDict["businessData"] as? [String: Any], !businessData.isEmpty {
|
|
325
|
+
var parsedBusinessData: [String: Any] = [:]
|
|
326
|
+
if let cac = businessData["cac"] as? String { parsedBusinessData["cac"] = cac }
|
|
327
|
+
if !parsedBusinessData.isEmpty { parsedExtraData?["businessData"] = parsedBusinessData }
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Parse address
|
|
331
|
+
if let address = extraDataDict["address"] {
|
|
332
|
+
if !(address is NSNull) {
|
|
333
|
+
if let addressString = address as? String {
|
|
334
|
+
parsedExtraData?["address"] = addressString
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Parse metadata
|
|
340
|
+
if let metadata = extraDataDict["metadata"] as? [String: Any], !metadata.isEmpty {
|
|
341
|
+
parsedExtraData?["metadata"] = metadata
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Use parsed extraData or nil if empty
|
|
346
|
+
let extraDataForSDK = (parsedExtraData != nil && !parsedExtraData!.isEmpty) ? parsedExtraData : nil
|
|
347
|
+
|
|
348
|
+
guard let rootVC = getTopViewController() else {
|
|
349
|
+
print("⚠️ Failed to get top view controller")
|
|
350
|
+
reject("NO_ROOT_VIEW_CONTROLLER", "Failed to get top view controller", nil)
|
|
351
|
+
return
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
DispatchQueue.main.async { [weak self] in
|
|
355
|
+
guard let self = self else { return }
|
|
356
|
+
|
|
357
|
+
// Reset state for new launch
|
|
358
|
+
self.prevController = nil
|
|
359
|
+
self.isDojahActive = false
|
|
360
|
+
self.hasSeenSDKInit = false
|
|
361
|
+
|
|
362
|
+
// Create safe navigation controller for Dojah (prevents duplicate presentations)
|
|
363
|
+
let dojahNavController = SafeDojahNavigationController()
|
|
364
|
+
dojahNavController.modalPresentationStyle = .fullScreen
|
|
365
|
+
self.dojahNavController = dojahNavController
|
|
366
|
+
|
|
367
|
+
// Set delegate BEFORE presenting (important!)
|
|
368
|
+
dojahNavController.delegate = self.navDelegate
|
|
369
|
+
|
|
370
|
+
// Detect modal dismissal (for cancel)
|
|
371
|
+
dojahNavController.presentationController?.delegate = self.presentationDelegate
|
|
372
|
+
|
|
373
|
+
// Set up presentation delegate callback
|
|
374
|
+
self.presentationDelegate.setOnDidDismiss { [weak self] in
|
|
375
|
+
guard let self = self else { return }
|
|
376
|
+
print("🛑 Modal was dismissed manually")
|
|
377
|
+
self.resolveSdkResult()
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Track Dojah flow - simplified like original but with proper closing logic
|
|
381
|
+
self.navDelegate.setOnDidShow { [weak self] vc in
|
|
382
|
+
guard let self = self else { return }
|
|
383
|
+
|
|
384
|
+
// Use String(describing: vc) like the original code
|
|
385
|
+
let vcName = String(describing: vc)
|
|
386
|
+
print("🔄 onDidShow: \(vcName)")
|
|
387
|
+
|
|
388
|
+
// Match original + Flutter logic:
|
|
389
|
+
// 1. If not DojahWidget, resolve (but only if we were in Dojah)
|
|
390
|
+
if !vcName.contains("DojahWidget") {
|
|
391
|
+
if self.isDojahActive {
|
|
392
|
+
print("🚪 Not DojahWidget - resolving")
|
|
393
|
+
self.resolveSdkResult()
|
|
394
|
+
}
|
|
395
|
+
return
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Mark as active when we see Dojah screens
|
|
399
|
+
self.isDojahActive = true
|
|
400
|
+
|
|
401
|
+
// 2. If DJDisclaimer with prevController, pop to root (like original)
|
|
402
|
+
if vcName.contains("DojahWidget.DJDisclaimer") && self.prevController != nil {
|
|
403
|
+
print("📱 DJDisclaimer with prevController - popping to root")
|
|
404
|
+
self.dojahNavController?.popToRootViewController(animated: false)
|
|
405
|
+
return
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// 3. If not SDKInitViewController, track as prevController (like original)
|
|
409
|
+
if !vcName.contains("DojahWidget.SDKInitViewController") {
|
|
410
|
+
self.prevController = vc
|
|
411
|
+
print("✅ Tracking prevController: \(vcName)")
|
|
412
|
+
} else {
|
|
413
|
+
// 4. SDKInitViewController - resolve (matches Flutter's "else" case)
|
|
414
|
+
// Resolve if we've seen it before OR if we've progressed
|
|
415
|
+
if self.hasSeenSDKInit || self.prevController != nil {
|
|
416
|
+
print("📱 SDKInitViewController - resolving")
|
|
417
|
+
self.resolveSdkResult()
|
|
418
|
+
} else {
|
|
419
|
+
// First time seeing SDKInitViewController - allow to continue
|
|
420
|
+
print("📱 SDKInitViewController on initial launch - allowing to continue")
|
|
421
|
+
self.hasSeenSDKInit = true
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Present modally and wait for completion to ensure view hierarchy is ready
|
|
427
|
+
rootVC.present(dojahNavController, animated: true) {
|
|
428
|
+
// Add a small delay to ensure view hierarchy is fully laid out
|
|
429
|
+
// This helps with camera session initialization timing
|
|
430
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
|
431
|
+
// Initialize SDK after presentation completes and view is laid out
|
|
432
|
+
// This ensures the view hierarchy is fully set up before camera access
|
|
433
|
+
// Convert dictionary to ExtraUserData if method is available in SDK
|
|
434
|
+
// If toExtraUserData() doesn't exist, this will need to be handled differently
|
|
435
|
+
let extraUserDataForSDK: ExtraUserData? = {
|
|
436
|
+
guard let extraDataDict = extraDataForSDK else { return ExtraUserData() }
|
|
437
|
+
// Try to use toExtraUserData() if available in SDK (works in Expo)
|
|
438
|
+
return extraDataDict.toExtraUserData()
|
|
439
|
+
}()
|
|
440
|
+
|
|
441
|
+
DojahWidgetSDK.initialize(
|
|
442
|
+
widgetID: widgetId,
|
|
443
|
+
referenceID: safeReferenceId,
|
|
444
|
+
emailAddress: safeEmail,
|
|
445
|
+
extraUserData: extraUserDataForSDK ?? ExtraUserData(),
|
|
446
|
+
source: "ios_react_native_cli",
|
|
447
|
+
navController: dojahNavController
|
|
448
|
+
)
|
|
449
|
+
print("🎯 Dojah SDK initialized: widgetId=\(widgetId), referenceId=\(safeReferenceId), email=\(safeEmail)")
|
|
450
|
+
// Resolve promise after successful initialization
|
|
451
|
+
resolve("launched")
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
211
456
|
}
|
|
212
|
-
|
package/lib/commonjs/index.js
CHANGED
|
@@ -79,8 +79,13 @@ const DojahKyc = _reactNative.NativeModules.DojahKyc ? _reactNative.NativeModule
|
|
|
79
79
|
* ```
|
|
80
80
|
**/
|
|
81
81
|
|
|
82
|
-
function launchDojahKyc(widgetId, referenceId, email,
|
|
83
|
-
|
|
82
|
+
function launchDojahKyc(widgetId, referenceId, email, extraData) {
|
|
83
|
+
if (_reactNative.Platform.OS === 'ios') {
|
|
84
|
+
return DojahKyc.launch(widgetId, referenceId ?? '', email ?? '', extraData);
|
|
85
|
+
} else {
|
|
86
|
+
// Android now also uses extraData object (matching docs structure)
|
|
87
|
+
return DojahKyc.launch(widgetId, referenceId, email, extraData);
|
|
88
|
+
}
|
|
84
89
|
}
|
|
85
90
|
function getIdHistory() {
|
|
86
91
|
return DojahKyc.getIdHistory();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","DojahKyc","NativeModules","Proxy","get","Error","launchDojahKyc","widgetId","referenceId","email","
|
|
1
|
+
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","DojahKyc","NativeModules","Proxy","get","Error","launchDojahKyc","widgetId","referenceId","email","extraData","OS","launch","getIdHistory"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GACjB,qFAAqF,GACrFC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,QAAQ,GAAGC,0BAAa,CAACD,QAAQ,GACnCC,0BAAa,CAACD,QAAQ,GACtB,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACT,aAAa,CAAC;EAChC;AACF,CACF,CAAC;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,SAASU,cAAcA,CAC5BC,QAAgB,EAChBC,WAA2B,EAC3BC,KAAqB,EACrBC,SAQQ,EACgB;EACxB,IAAIb,qBAAQ,CAACc,EAAE,KAAK,KAAK,EAAE;IACzB,OAAOV,QAAQ,CAACW,MAAM,CAACL,QAAQ,EAAEC,WAAW,IAAI,EAAE,EAAEC,KAAK,IAAI,EAAE,EAAEC,SAAS,CAAC;EAC7E,CAAC,MAAM;IACL;IACA,OAAOT,QAAQ,CAACW,MAAM,CAACL,QAAQ,EAAEC,WAAW,EAAEC,KAAK,EAAEC,SAAS,CAAC;EACjE;AACF;AAEO,SAASG,YAAYA,CAAA,EAAwC;EAClE,OAAOZ,QAAQ,CAACY,YAAY,CAAC,CAAC;AAChC","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -72,8 +72,13 @@ const DojahKyc = NativeModules.DojahKyc ? NativeModules.DojahKyc : new Proxy({},
|
|
|
72
72
|
* ```
|
|
73
73
|
**/
|
|
74
74
|
|
|
75
|
-
export function launchDojahKyc(widgetId, referenceId, email,
|
|
76
|
-
|
|
75
|
+
export function launchDojahKyc(widgetId, referenceId, email, extraData) {
|
|
76
|
+
if (Platform.OS === 'ios') {
|
|
77
|
+
return DojahKyc.launch(widgetId, referenceId ?? '', email ?? '', extraData);
|
|
78
|
+
} else {
|
|
79
|
+
// Android now also uses extraData object (matching docs structure)
|
|
80
|
+
return DojahKyc.launch(widgetId, referenceId, email, extraData);
|
|
81
|
+
}
|
|
77
82
|
}
|
|
78
83
|
export function getIdHistory() {
|
|
79
84
|
return DojahKyc.getIdHistory();
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","DojahKyc","Proxy","get","Error","launchDojahKyc","widgetId","referenceId","email","
|
|
1
|
+
{"version":3,"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","DojahKyc","Proxy","get","Error","launchDojahKyc","widgetId","referenceId","email","extraData","OS","launch","getIdHistory"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AAEtD,MAAMC,aAAa,GACjB,qFAAqF,GACrFD,QAAQ,CAACE,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,QAAQ,GAAGN,aAAa,CAACM,QAAQ,GACnCN,aAAa,CAACM,QAAQ,GACtB,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACP,aAAa,CAAC;EAChC;AACF,CACF,CAAC;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAO,SAASQ,cAAcA,CAC5BC,QAAgB,EAChBC,WAA2B,EAC3BC,KAAqB,EACrBC,SAQQ,EACgB;EACxB,IAAIb,QAAQ,CAACc,EAAE,KAAK,KAAK,EAAE;IACzB,OAAOT,QAAQ,CAACU,MAAM,CAACL,QAAQ,EAAEC,WAAW,IAAI,EAAE,EAAEC,KAAK,IAAI,EAAE,EAAEC,SAAS,CAAC;EAC7E,CAAC,MAAM;IACL;IACA,OAAOR,QAAQ,CAACU,MAAM,CAACL,QAAQ,EAAEC,WAAW,EAAEC,KAAK,EAAEC,SAAS,CAAC;EACjE;AACF;AAEA,OAAO,SAASG,YAAYA,CAAA,EAAwC;EAClE,OAAOX,QAAQ,CAACW,YAAY,CAAC,CAAC;AAChC","ignoreList":[]}
|
|
@@ -60,6 +60,14 @@
|
|
|
60
60
|
* });
|
|
61
61
|
* ```
|
|
62
62
|
**/
|
|
63
|
-
export declare function launchDojahKyc(widgetId: string, referenceId?: string | null, email?: string | null,
|
|
63
|
+
export declare function launchDojahKyc(widgetId: string, referenceId?: string | null, email?: string | null, extraData?: {
|
|
64
|
+
userData?: Object | null;
|
|
65
|
+
govData?: Object | null;
|
|
66
|
+
govId?: Object | null;
|
|
67
|
+
location?: Object | null;
|
|
68
|
+
businessData?: Object | null;
|
|
69
|
+
address?: string | null;
|
|
70
|
+
metadata?: Object | null;
|
|
71
|
+
} | null): Promise<string | null>;
|
|
64
72
|
export declare function getIdHistory(): Promise<Map<string, string> | null>;
|
|
65
73
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6DI;AAEJ,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,EAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,QAAQ,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAmBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6DI;AAEJ,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,EAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,SAAS,CAAC,EAAE;IACV,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,IAAI,GACP,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAED,wBAAgB,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAElE"}
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -84,26 +84,22 @@ export function launchDojahKyc(
|
|
|
84
84
|
widgetId: string,
|
|
85
85
|
referenceId?: string | null,
|
|
86
86
|
email?: string | null,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
extraData?: {
|
|
88
|
+
userData?: Object | null;
|
|
89
|
+
govData?: Object | null;
|
|
90
|
+
govId?: Object | null;
|
|
91
|
+
location?: Object | null;
|
|
92
|
+
businessData?: Object | null;
|
|
93
|
+
address?: string | null;
|
|
94
|
+
metadata?: Object | null;
|
|
95
|
+
} | null
|
|
94
96
|
): Promise<string | null> {
|
|
95
|
-
|
|
96
|
-
widgetId,
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
govId,
|
|
102
|
-
location,
|
|
103
|
-
businessData,
|
|
104
|
-
address,
|
|
105
|
-
metadata
|
|
106
|
-
);
|
|
97
|
+
if (Platform.OS === 'ios') {
|
|
98
|
+
return DojahKyc.launch(widgetId, referenceId ?? '', email ?? '', extraData);
|
|
99
|
+
} else {
|
|
100
|
+
// Android now also uses extraData object (matching docs structure)
|
|
101
|
+
return DojahKyc.launch(widgetId, referenceId, email, extraData);
|
|
102
|
+
}
|
|
107
103
|
}
|
|
108
104
|
|
|
109
105
|
export function getIdHistory(): Promise<Map<string, string> | null> {
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# These are essential for React Native's internal mechanisms and module linking.
|
|
2
|
-
-keepclassmembers class com.facebook.react.bridge.JavaModule$$Props { *; }
|
|
3
|
-
-keepclassmembers class com.facebook.react.bridge.ModuleSpec { *; }
|
|
4
|
-
-keepclassmembers class * implements com.facebook.react.bridge.JavaScriptModule { *; }
|
|
5
|
-
-keepclassmembers class * implements com.facebook.react.bridge.NativeModule { *; }
|
|
6
|
-
|
|
7
|
-
# Prevents the stripping of unused methods in classes that are accessed dynamically.
|
|
8
|
-
-keep public class * extends com.facebook.react.bridge.ViewManager { *; }
|
|
9
|
-
-keep public class * extends com.facebook.react.uimanager.ViewManager { *; } # Older versions might use this
|
|
10
|
-
|
|
11
|
-
# Keep React Native module classes and their constructors.
|
|
12
|
-
# This is crucial for autolinking and manual linking.
|
|
13
|
-
-keep class * implements com.facebook.react.bridge.NativeModule {
|
|
14
|
-
<init>(...);
|
|
15
|
-
}
|
|
16
|
-
-keep class * extends com.facebook.react.bridge.BaseJavaModule {
|
|
17
|
-
<init>(...);
|
|
18
|
-
}
|
|
19
|
-
-keep class * extends com.facebook.react.uimanager.ViewManager {
|
|
20
|
-
<init>(...);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
# Standard dontwarn rules for common React Native dependencies
|
|
24
|
-
-dontwarn com.facebook.react.**
|
|
25
|
-
-dontwarn com.facebook.jni.**
|
|
26
|
-
-dontwarn com.facebook.soloader.**
|
|
27
|
-
-dontwarn com.facebook.yoga.**
|
|
28
|
-
-dontwarn javax.annotation.**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
# Keep your SDK's core Kotlin classes and interfaces (likely in kyc_sdk_kotlin)
|
|
32
|
-
-keep class com.dojah.kyc_sdk_kotlin.domain.** { *; }
|
|
33
|
-
-keep class com.dojah.kyc_sdk_kotlin.core.Result
|
|
34
|
-
-keep interface com.dojah.** { *; }
|
|
35
|
-
|
|
36
|
-
# IMPORTANT: Keep React Native module and package classes.
|
|
37
|
-
-keep class com.dojahkyc.rn.** {*;}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# Keep gRPC classes
|
|
41
|
-
-keep class io.grpc.** { *; }
|
|
42
|
-
|
|
43
|
-
# Keep BouncyCastle classes
|
|
44
|
-
-keep class org.bouncycastle.** { *; }
|
|
45
|
-
|
|
46
|
-
# Keep Conscrypt classes
|
|
47
|
-
-keep class org.conscrypt.** { *; }
|
|
48
|
-
|
|
49
|
-
# Keep OpenJSSE classes
|
|
50
|
-
-keep class org.openjsse.** { *; }
|