الالتقاط على Flutter
افتح الالتقاط من تطبيق Flutter عبر platform channel.
تنشئ الواجهة الخلفية لديك العملية في Human Plugin بتدفق Journey وcallbackUri يستخدم مخطط URL الخاص بتطبيقك. يفتح MethodChannel الرابط link من الاستجابة في ASWebAuthenticationSession على iOS وفي Custom Tabs على Android. لا حاجة إلى حزمة خارجية.
احتفظ بـ id الخاص بـ Human Plugin من استجابة الإنشاء. ستقرأ الواجهة الخلفية لديك النتيجة به.
المتطلبات الأساسية
- Flutter 3 أو أحدث
- 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. أنشئ خدمة Dart
// lib/services/capture_service.dart
import 'package:flutter/services.dart';
class CaptureService {
static const _channel = MethodChannel('capture_plugin');
/// يعيد true عند انتهاء الالتقاط، وfalse عند إغلاق الشخص له.
Future<bool> open(String link) async {
try {
final result = await _channel.invokeMethod<String>('openSession', {'url': link});
return result != null;
} on PlatformException {
return false;
}
}
}
3. نفّذ إضافة iOS
// ios/Runner/CapturePlugin.swift
import Flutter
import AuthenticationServices
class CapturePlugin: NSObject, FlutterPlugin, ASWebAuthenticationPresentationContextProviding {
private var session: ASWebAuthenticationSession?
static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "capture_plugin", binaryMessenger: registrar.messenger())
let instance = CapturePlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
guard call.method == "openSession",
let args = call.arguments as? [String: Any],
let urlString = args["url"] as? String,
let url = URL(string: urlString) else {
result(FlutterMethodNotImplemented)
return
}
let newSession = ASWebAuthenticationSession(
url: url,
callbackURLScheme: "myapp"
) { callbackURL, error in
self.session = nil
if let callbackURL = callbackURL {
result(callbackURL.absoluteString)
} else {
result(FlutterError(code: "SESSION_ERROR",
message: error?.localizedDescription ?? "Session cancelled",
details: nil))
}
}
newSession.presentationContextProvider = self
newSession.prefersEphemeralWebBrowserSession = true
newSession.start()
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
}
}
سجّلها في AppDelegate.swift:
CapturePlugin.register(with: self.registrar(forPlugin: "CapturePlugin")!)
4. نفّذ إضافة Android
أضف الاعتمادية إلى android/app/build.gradle:
implementation("androidx.browser:browser:1.5.0")
// android/app/src/main/kotlin/<your.package>/CapturePlugin.kt
package com.yourapp
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class CapturePlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware {
private var channel: MethodChannel? = null
private var binding: ActivityPluginBinding? = null
private var pendingResult: MethodChannel.Result? = null
override fun onAttachedToEngine(flutterBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterBinding.binaryMessenger, "capture_plugin")
channel?.setMethodCallHandler(this)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
if (call.method == "openSession") {
val url = call.argument<String>("url") ?: return result.error("MISSING_URL", "URL is required", null)
pendingResult = result
val activity = binding?.activity ?: return result.error("NO_ACTIVITY", "No activity", null)
CustomTabsIntent.Builder().build().launchUrl(activity, Uri.parse(url))
} else {
result.notImplemented()
}
}
fun handleRedirect(uri: Uri) {
if (uri.scheme == "myapp") {
pendingResult?.success(uri.toString())
pendingResult = null
}
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) { this.binding = binding }
override fun onDetachedFromActivity() { binding = null }
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { this.binding = binding }
override fun onDetachedFromActivityForConfigChanges() { binding = null }
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { channel = null }
}
سجّلها وعالج العودة في MainActivity.kt:
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
flutterEngine.plugins.add(CapturePlugin())
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intent.data?.let { uri ->
if (uri.scheme == "myapp") {
val plugin = flutterEngine?.plugins?.get(CapturePlugin::class.java) as? CapturePlugin
plugin?.handleRedirect(uri)
}
}
}
5. سجّل مخططك
- iOS
- Android
في Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
في AndroidManifest.xml، داخل <activity> الرئيسي لديك:
<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>
6. ابدأ الالتقاط
final ended = await CaptureService().open(link);
if (ended) {
// انتهى الالتقاط. اطلب من الواجهة الخلفية لديك قراءة النتيجة
// عبر GET /v1/processes/{id}، باستخدام id الخاص بـ Human Plugin.
} else {
// أغلق الشخص الجلسة.
}
الملخص
| الملف | الغرض |
|---|---|
lib/services/capture_service.dart | خدمة Dart من نوع MethodChannel |
ios/Runner/CapturePlugin.swift | iOS: ASWebAuthenticationSession |
ios/Runner/AppDelegate.swift | تسجيل الإضافة |
android/.../CapturePlugin.kt | Android: Custom Tabs |
android/.../MainActivity.kt | تسجيل الإضافة ومعالجة العودة |
Info.plist | مخطط URL على iOS |
AndroidManifest.xml | مرشّح intent على Android |