Pengambilan di Flutter
Buka pengambilan dari aplikasi Flutter dengan platform channel.
Back-end Anda membuat proses di Human Plugin dengan alur Journey dan callbackUri yang menggunakan URL scheme aplikasi Anda. Sebuah MethodChannel membuka link dari respons di ASWebAuthenticationSession pada iOS dan di Custom Tabs pada Android. Tidak diperlukan paket eksternal.
Simpan id Human Plugin dari respons pembuatan. Back-end Anda membaca hasilnya dengannya.
Prasyarat
- Flutter 3 atau lebih baru
- Xcode 14 atau lebih baru untuk iOS
- Android Studio untuk Android
- URL scheme yang unik untuk aplikasi Anda, seperti
myapp
1. Buat proses dengan scheme Anda
Back-end Anda mengirim scheme sebagai callbackUri:
{
"flow": "humantoken",
"clientId": "client-a",
"correlationId": "order-1001",
"credential": { "type": "DUI_TYPE_NG_BVN", "value": "<document number>" },
"callbackUri": "myapp://callback"
}
dan mengembalikan id serta link ke aplikasi.
2. Buat service Dart
// lib/services/capture_service.dart
import 'package:flutter/services.dart';
class CaptureService {
static const _channel = MethodChannel('capture_plugin');
/// Mengembalikan true saat pengambilan berakhir, false saat orang tersebut menutupnya.
Future<bool> open(String link) async {
try {
final result = await _channel.invokeMethod<String>('openSession', {'url': link});
return result != null;
} on PlatformException {
return false;
}
}
}
3. Implementasikan 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
}
}
Daftarkan di AppDelegate.swift:
CapturePlugin.register(with: self.registrar(forPlugin: "CapturePlugin")!)
4. Implementasikan plugin Android
Tambahkan dependensi ke 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 }
}
Daftarkan dan tangani kembalinya pengguna di 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. Daftarkan scheme Anda
- iOS
- Android
Di Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Di AndroidManifest.xml, di dalam <activity> utama Anda:
<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. Mulai pengambilan
final ended = await CaptureService().open(link);
if (ended) {
// Pengambilan berakhir. Minta back-end Anda membaca hasilnya
// dengan GET /v1/processes/{id}, menggunakan id Human Plugin.
} else {
// Orang tersebut menutup sesi.
}
Ringkasan
| File | Tujuan |
|---|---|
lib/services/capture_service.dart | Service Dart MethodChannel |
ios/Runner/CapturePlugin.swift | iOS: ASWebAuthenticationSession |
ios/Runner/AppDelegate.swift | Pendaftaran plugin |
android/.../CapturePlugin.kt | Android: Custom Tabs |
android/.../MainActivity.kt | Pendaftaran plugin dan penanganan kembalinya pengguna |
Info.plist | URL scheme iOS |
AndroidManifest.xml | Intent filter Android |