Ouvrez la capture depuis une application Flutter avec un platform channel.
Votre back-end crée le processus dans Human Plugin avec un flux Journey et un callbackUri qui utilise le scheme d'URL de votre application. Un MethodChannel ouvre le link de la réponse dans ASWebAuthenticationSession sur iOS et dans Custom Tabs sur Android. Aucun package externe n'est nécessaire.
Conservez l'id Human Plugin de la réponse de création. Votre back-end lit le résultat avec cet id.
Prérequis
- Flutter 3 ou version ultérieure
- Xcode 14 ou version ultérieure pour iOS
- Android Studio pour Android
- Un scheme d'URL propre à votre application, tel que
myapp
1. Créer le processus avec votre scheme
Votre back-end envoie le scheme comme callbackUri :
{
"flow": "humantoken",
"clientId": "client-a",
"correlationId": "order-1001",
"credential": { "type": "DUI_TYPE_NG_BVN", "value": "<document number>" },
"callbackUri": "myapp://callback"
}
et renvoie id et link à l'application.
2. Créer le service Dart
// lib/services/capture_service.dart
import 'package:flutter/services.dart';
class CaptureService {
static const _channel = MethodChannel('capture_plugin');
/// Renvoie true lorsque la capture est terminée, false lorsque la personne l'a fermée.
Future<bool> open(String link) async {
try {
final result = await _channel.invokeMethod<String>('openSession', {'url': link});
return result != null;
} on PlatformException {
return false;
}
}
}
3. Implémenter le plugin 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
}
}
Enregistrez-le dans AppDelegate.swift :
CapturePlugin.register(with: self.registrar(forPlugin: "CapturePlugin")!)
4. Implémenter le plugin Android
Ajoutez la dépendance à 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 }
}
Enregistrez-le et gérez le retour dans 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. Enregistrer votre scheme
- iOS
- Android
Dans Info.plist :
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Dans AndroidManifest.xml, à l'intérieur de votre <activity> principale :
<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. Démarrer la capture
final ended = await CaptureService().open(link);
if (ended) {
// La capture est terminée. Demandez à votre back-end de lire le résultat
// avec GET /v1/processes/{id}, en utilisant l'id Human Plugin.
} else {
// La personne a fermé la session.
}
Récapitulatif
| Fichier | Rôle |
|---|---|
lib/services/capture_service.dart | Service Dart MethodChannel |
ios/Runner/CapturePlugin.swift | iOS : ASWebAuthenticationSession |
ios/Runner/AppDelegate.swift | Enregistrement du plugin |
android/.../CapturePlugin.kt | Android : Custom Tabs |
android/.../MainActivity.kt | Enregistrement du plugin et gestion du retour |
Info.plist | Scheme d'URL iOS |
AndroidManifest.xml | Intent filter Android |