الالتقاط على React Native
افتح الالتقاط من تطبيق React Native باستخدام وحدة أصلية.
تنشئ الواجهة الخلفية لديك العملية في Human Plugin بتدفق Journey وcallbackUri يستخدم مخطط URL الخاص بتطبيقك. تفتح وحدة أصلية الرابط link من الاستجابة في ASWebAuthenticationSession على iOS وفي Custom Tabs على Android. عند انتهاء الالتقاط، تُنهي الوحدة وعدها (promise) ويستأنف التطبيق عمله.
احتفظ بـ id الخاص بـ Human Plugin من استجابة الإنشاء. ستقرأ الواجهة الخلفية لديك النتيجة به.
المتطلبات الأساسية
- React Native 0.71 أو أحدث
- Xcode 14 أو أحدث لنظام iOS
- Android Studio لنظام Android
- مخطط URL فريد لتطبيقك، مثل
myapp
1. أنشئ العملية بمخططك
ترسل الواجهة الخلفية لديك المخطط بوصفه callbackUri:
{
"flow": "humantoken",
"clientId": "client-a",
"correlationId": "order-1001",
"credential": { "type": "DUI_TYPE_NG_BVN", "value": "<document number>" },
"callbackUri": "myapp://callback"
}
وتعيد id وlink إلى التطبيق.
2. أنشئ جسر TypeScript
// src/modules/CaptureModule.ts
import { NativeModules } from 'react-native';
const { CaptureModule } = NativeModules;
if (!CaptureModule) {
throw new Error('CaptureModule not found. Make sure the native module is linked correctly.');
}
export const Capture = {
openSession: (url: string): Promise<string> => CaptureModule.openSession(url),
};
3. نفّذ وحدة iOS
- جسر Objective-C
- تنفيذ Swift
// ios/CaptureModule.m
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(CaptureModule, NSObject)
RCT_EXTERN_METHOD(openSession:(NSString *)url
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
@end
// ios/CaptureModule.swift
import AuthenticationServices
@objc(CaptureModule)
class CaptureModule: NSObject, ASWebAuthenticationPresentationContextProviding {
private var session: ASWebAuthenticationSession?
@objc func openSession(_ url: String,
resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
guard let sessionURL = URL(string: url) else {
reject("INVALID_URL", "Invalid URL", nil)
return
}
DispatchQueue.main.async {
let newSession = ASWebAuthenticationSession(
url: sessionURL,
callbackURLScheme: "myapp"
) { callbackURL, error in
self.session = nil
if let callbackURL = callbackURL {
resolve(callbackURL.absoluteString)
} else {
reject("SESSION_ERROR", error?.localizedDescription ?? "Session cancelled", error)
}
}
newSession.presentationContextProvider = self
newSession.prefersEphemeralWebBrowserSession = true
newSession.start()
self.session = newSession
}
}
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first else {
return ASPresentationAnchor()
}
return window
}
@objc static func requiresMainQueueSetup() -> Bool { return true }
}
4. نفّذ وحدة Android
أضف الاعتمادية إلى android/app/build.gradle:
implementation("androidx.browser:browser:1.5.0")
// android/app/src/main/java/<your.package>/CaptureModule.kt
package com.yourapp
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import com.facebook.react.bridge.*
class CaptureModule(private val reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
private var pendingPromise: Promise? = null
override fun getName() = "CaptureModule"
@ReactMethod
fun openSession(url: String, promise: Promise) {
pendingPromise = promise
currentActivity?.runOnUiThread {
CustomTabsIntent.Builder().build()
.launchUrl(currentActivity!!, Uri.parse(url))
} ?: promise.reject("NO_ACTIVITY", "No current activity")
}
fun handleRedirectUrl(uri: Uri) {
if (uri.scheme == "myapp") {
pendingPromise?.resolve(uri.toString())
pendingPromise = null
}
}
}
// CapturePackage.kt
package com.yourapp
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager
class CapturePackage : ReactPackage {
override fun createNativeModules(ctx: ReactApplicationContext): List<NativeModule> =
listOf(CaptureModule(ctx))
override fun createViewManagers(ctx: ReactApplicationContext): List<ViewManager<*, *>> =
emptyList()
}
سجّلها في MainApplication.kt:
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(CapturePackage())
}
عالج العودة في MainActivity.kt:
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intent.data?.let { uri ->
if (uri.scheme == "myapp") {
val module = reactInstanceManager
.currentReactContext
?.getNativeModule(CaptureModule::class.java)
module?.handleRedirectUrl(uri)
}
}
}
5. سجّل مخططك على Android
في AndroidManifest.xml:
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />
<activity android:name=".MainActivity" ...>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="callback" />
</intent-filter>
</activity>
6. ابدأ الالتقاط
import { Capture } from './modules/CaptureModule';
try {
await Capture.openSession(link);
// انتهى الالتقاط. اطلب من الواجهة الخلفية لديك قراءة النتيجة
// عبر GET /v1/processes/{id}، باستخدام id الخاص بـ Human Plugin.
} catch {
// أغلق الشخص الجلسة.
}
الملخص
| الملف | الغرض |
|---|---|
src/modules/CaptureModule.ts | جسر TypeScript |
ios/CaptureModule.m | إعلان Objective-C |
ios/CaptureModule.swift | iOS: ASWebAuthenticationSession |
android/.../CaptureModule.kt | Android: Custom Tabs |
android/.../CapturePackage.kt | تسجيل الحزمة |
android/.../MainApplication.kt | يضيف الحزمة |
android/.../MainActivity.kt | يعالج العودة |
AndroidManifest.xml | مرشّح intent |