Ionic 캡처
로컬 Capacitor 플러그인을 사용해 Ionic 앱에서 캡처를 엽니다.
백엔드가 Journey 플로우와 앱의 URL 스킴을 사용하는 callbackUri로 Human Plugin에서 프로세스를 생성합니다. 로컬 Capacitor 플러그인이 응답의 link를 Android에서는 Custom Tabs, iOS에서는 ASWebAuthenticationSession으로 엽니다. 캡처가 끝나면 플러그인이 resolve되고 앱이 제어를 이어받습니다.
생성 응답의 Human Plugin id를 보관하세요. 백엔드가 이 값으로 결과를 읽습니다.
사전 요구 사항
- Capacitor 4 이상을 사용하는 Ionic
- Xcode 14 이상 및 Android Studio
- 앱 고유의 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. 플러그인 인터페이스 정의
// src/plugins/capture-plugin.ts
import { registerPlugin } from '@capacitor/core';
export interface CapturePlugin {
openSession(options: { url: string }): Promise<{ callbackUrl: string }>;
}
const Capture = registerPlugin<CapturePlugin>('CapturePlugin');
export default Capture;
3. iOS 플러그인 구현
import Capacitor
import AuthenticationServices
@objc(CapturePlugin)
public class CapturePlugin: CAPPlugin, ASWebAuthenticationPresentationContextProviding {
private var session: ASWebAuthenticationSession?
@objc func openSession(_ call: CAPPluginCall) {
guard let urlString = call.getString("url"),
let url = URL(string: urlString) else {
call.reject("Invalid URL")
return
}
DispatchQueue.main.async {
let newSession = ASWebAuthenticationSession(
url: url,
callbackURLScheme: "myapp"
) { callbackURL, error in
self.session = nil
if let callbackURL = callbackURL {
call.resolve(["callbackUrl": callbackURL.absoluteString])
} else {
call.reject(error?.localizedDescription ?? "Session cancelled")
}
}
newSession.presentationContextProvider = self
newSession.prefersEphemeralWebBrowserSession = true
newSession.start()
self.session = newSession
}
}
public 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
}
}
4. Android 플러그인 구현
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import com.getcapacitor.JSObject
import com.getcapacitor.Plugin
import com.getcapacitor.PluginCall
import com.getcapacitor.PluginMethod
import com.getcapacitor.annotation.CapacitorPlugin
@CapacitorPlugin(name = "CapturePlugin")
class CapturePlugin : Plugin() {
private var pendingCall: PluginCall? = null
@PluginMethod
fun openSession(call: PluginCall) {
val url = call.getString("url") ?: return call.reject("Missing URL")
pendingCall = call
activity.runOnUiThread {
CustomTabsIntent.Builder().build()
.launchUrl(activity, Uri.parse(url))
}
}
override fun handleOnNewIntent(intent: Intent) {
super.handleOnNewIntent(intent)
intent.data?.let { uri ->
if (uri.scheme == "myapp") {
pendingCall?.resolve(JSObject().put("callbackUrl", uri.toString()))
pendingCall = null
}
}
}
}
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>
build.gradle에 추가합니다.
implementation("androidx.browser:browser:1.5.0")
6. 캡처 시작
플러그인을 감싸는 Angular 서비스입니다.
import { Injectable } from '@angular/core';
import Capture from '../plugins/capture-plugin';
@Injectable({ providedIn: 'root' })
export class CaptureService {
/** 캡처가 끝나면 true, 사용자가 닫으면 false로 resolve됩니다. */
async open(link: string): Promise<boolean> {
try {
await Capture.openSession({ url: link });
return true;
} catch {
return false;
}
}
}
const ended = await this.captureService.open(link);
if (ended) {
// 캡처가 끝났습니다. 백엔드에 Human Plugin id로
// GET /v1/processes/{id}를 호출해 결과를 읽도록 요청하세요.
}
요약
| 파일 | 용도 |
|---|---|
capture-plugin.ts | Capacitor 플러그인 인터페이스 |
CapturePlugin.swift | iOS: ASWebAuthenticationSession |
CapturePlugin.kt | Android: Custom Tabs |
Info.plist | iOS URL 스킴 |
AndroidManifest.xml | Android 인텐트 필터 |
capture.service.ts | Angular 서비스 |