iOS SDK 集成指南
概述
Width Identity SDK 爲 iOS
應用提供即插即用的身份驗證流程。支持 KYC 和 KYB 工作流。你
import WidthIdentity 並調用一個入口;SDK 即呈現完整的採集 /
活體 / 審覈界面,並返回單一結果。公共 API 使用 Swift
原生類型(帶關聯值的枚舉、結構體、閉包),從 Swift 中使用。
系統要求
| 要求 | 最低版本 |
|---|---|
| iOS | 16.0+(部署目標) |
| Xcode | 16+ |
| 依賴管理器 | Swift Package Manager 或 CocoaPods |
安裝
方式 A:Swift Package Manager(推薦)
WidthIdentity-iOS 是私有倉庫 —
在你的 GitHub 賬號拿到訪問權之前,Xcode 和 git
都只會提示倉庫不存在,所以先確認訪問權已開通,再執行下面的步驟。
在 Xcode 中:File > Add Package Dependencies…,輸入:
https://github.com/width-com/WidthIdentity-iOS.git
或在 Package.swift 中:
dependencies: [
.package(url: "https://github.com/width-com/WidthIdentity-iOS.git", from: "1.0.11"),
],
targets: [
.target(name: "MyApp", dependencies: [
.product(name: "WidthIdentity", package: "WidthIdentity-iOS"),
]),
]方式 B:CocoaPods
WidthIdentity 發佈在 Width 的私有 Specs 倉庫,因此需在
Podfile 中聲明該源:
該 Specs 倉庫同樣是私有的 — 只有你的 GitHub
賬號拿到訪問權之後,pod install
才解析得到;沒有訪問權時,這個源看起來就是「倉庫不存在」。
source 'https://github.com/width-com/Specs.git' source 'https://cdn.cocoapods.org/' # default trunk, for any public pods target 'YourApp' do pod 'WidthIdentity', '~> 1.0.11' end
然後執行 pod install。
Info.plist 權限
SDK token 不再存放於 Info.plist。它在運行時通過
CredentialsConfig.sdkToken
傳入(見快速開始)。相機、麥克風、語音識別三項使用描述都必須聲明;照片庫那一項可選:
<!-- Required: document capture and liveness -->
<key>NSCameraUsageDescription</key>
<string>Used to capture identity documents and complete the liveness check.</string>
<!-- Required: document verification records background audio (anti-fraud) -->
<key>NSMicrophoneUsageDescription</key>
<string>Used to record background audio during document verification to help prevent fraud.</string>
<!-- Optional: only if you let users pick a document image from the photo
library. The SDK uses the system PhotosPicker, which does not strictly
require this key. -->
<key>NSPhotoLibraryUsageDescription</key>
<string>Used to select identity document images.</string>
<!-- Required by App Store ingestion, never requested at runtime (see below) -->
<key>NSSpeechRecognitionUsageDescription</key>
<string>This app does not request speech recognition.</string>
NSCameraUsageDescription 與
NSMicrophoneUsageDescription
兩項都是必填:證件掃描環節會錄製背景音頻用於反欺詐,缺了麥克風這個
key,應用會在運行時直接崩潰。SDK
沒有任何與環境相關的 Info.plist key。
NSSpeechRecognitionUsageDescription
必填的原因不一樣。SDK 運行時從不申請語音識別,但
AwsLiveness.xcframework 靜態吸收了 Amplify 的 Predictions
插件,該插件引用了 SFSpeechRecognizer。缺這個 key,App
Store 會在入庫(ingestion,上傳包進入審覈前的自動校驗)階段直接退回(錯誤碼
ITMS-90683)—
而且是在整個二進制包傳完之後才報,與這個接口有沒有被調用無關。這個 key
的文案直說「本應用不使用語音識別」即可:權限永不申請,用戶也就永遠看不到這句話。
打包構成
SDK 一共包含八個
xcframework:WidthIdentity、SecCamera、onnxruntime、AwsLiveness、Veriff、DocumentReader、DocumentReaderCore、RegulaCommon,全部自動嵌入。其中
AwsLiveness 是自包含的,你不需要自己引入任何 Amplify 或
AWS 依賴。
快速開始
import WidthIdentity 提供兩種等價的入口風格 —
按喜好選擇即可。兩者驅動完全相同的驗證界面。
直接輸入(UIKit)
import UIKit
import WidthIdentity
final class ViewController: UIViewController {
func startVerification() throws {
let input = try VerificationInput(
credentials: CredentialsConfig(
domain: "YOUR_DOMAIN",
sdkToken: "YOUR_SDK_TOKEN"
),
customer: CustomerConfig(
// Both customerId and email are required and must be non-empty.
customerId: "user-123",
email: "user@example.com"
)
)
WIDTHVerification.present(from: self, input: input) { result in
switch result {
case .completed(let id, let decision): // .approved / .rejected / .review
print("done:", id, decision)
case .waiting(let id): print("waiting:", id)
case .dismissed(let id): print("dismissed:", id ?? "(no execution)")
case .cancelled(let id): print("cancelled:", id)
case .failed(let code, let message, _): print("failed:", code, message)
}
}
}
}直接輸入(SwiftUI)
import SwiftUI
import WidthIdentity
struct ContentView: View {
@State private var presenting = false
@State private var customerId = ""
@State private var email = ""
var body: some View {
Button("Verify") { presenting = true }
.widthVerification(isPresented: $presenting, input: {
// Lazy closure — built only when the cover is about to present.
try VerificationInput(
credentials: CredentialsConfig(
domain: "YOUR_DOMAIN", sdkToken: "YOUR_SDK_TOKEN"
),
customer: CustomerConfig(customerId: customerId, email: email)
)
}) { result in
// If the input closure throws, you'll receive .failed(code: "W-INIT-410", ...) here.
}
}
}Handler 風格入口(備選)
WIDTHMobileSDK 是另一種入口風格,以對象方式使用 —
先構造對象,設置屬性與各個 handler 閉包,再調用
present。
import WidthIdentity
let sdk = WIDTHMobileSDK(accessToken: "YOUR_SDK_TOKEN") // RiskSec sdkToken
sdk.credentials = .init(domain: "YOUR_DOMAIN") // appId/apiKey decoded from accessToken
sdk.applicant = .init(customerId: "user-123", email: "user@example.com")
sdk.dayNightMode = .night // optional; omit to follow the system
sdk.language = .zh // optional; .en (default) / .zh
sdk.verificationHandler { isApproved in
print(isApproved ? "approved" : "finally rejected")
}
sdk.onStatusDidChange { sdk, _ in
print("status:", sdk.status, "exec:", sdk.executionId ?? "-")
if let fail = sdk.failReason { print("failed:", fail.code, fail.message) }
}
sdk.onEvent { _, event in /* INFO/WARN/ERROR lifecycle log */ } // optional
sdk.present(from: self)SwiftUI:
Button("Verify") { presenting = true }
.widthMobileSDK(isPresented: $presenting) {
let sdk = WIDTHMobileSDK(accessToken: "YOUR_SDK_TOKEN")
sdk.credentials = .init(domain: "YOUR_DOMAIN") // appId/apiKey decoded from accessToken
sdk.applicant = .init(customerId: customerId, email: email)
sdk.verificationHandler { isApproved in /* ... */ }
return sdk
}accessToken 裏裝的是
sdkToken;其餘憑據在客戶端通過
sdk.credentials / sdk.applicant
設置。憑據或申請人信息缺失這類配置錯誤,會表現爲
sdk.status == .failed,並在
sdk.failReason 中給出原因。
事件日誌(可選)
直接輸入入口接受一個 SdkEventLogger,可將 SDK
生命週期事件(INFO / WARN /
ERROR)接入你自己的管道(Crashlytics、DataDog 等);回調觸發前已脫敏
PII(個人身份信息)。Handler 風格入口通過
sdk.onEvent 暴露相同的事件流。
final class MyLogger: SdkEventLogger {
func onEvent(level: SdkLogLevel, tag: String, message: String, error: Error?) {
// forward to your logging backend
}
}
let input = try VerificationInput(credentials: ..., customer: ..., eventLogger: MyLogger())配置參考
輸入結構與 Android
相同:VerificationInput、CredentialsConfig(domain
與 sdkToken)以及
CustomerConfig(customerId +
email,兩者都必填)。字段詳情參見
Android 配置參考。在 iOS 上,VerificationInput
的初始化器是 throws 的,並額外接受一個可選的
eventLogger。
iOS 特定的入口與主題覆蓋:
| 符號 | 用途 |
|---|---|
WIDTHVerification.present(from:input:completion:)
|
UIKit 原生入口 |
View.widthVerification(isPresented:input:onResult:)
|
SwiftUI 原生入口 |
WIDTHMobileSDK(accessToken:) +
credentials/applicant
+
present(from:)
|
UIKit Handler 風格入口 |
View.widthMobileSDK(isPresented:makeSDK:) |
SwiftUI Handler 風格入口 |
ThemeConfig / ThemeMode |
可選主題覆蓋 |
UILanguage |
可選的界面語言(.en 爲默認值 /
.zh)
|
結果處理
直接輸入的 VerificationResult
五種 Swift 枚舉變體(與 Android 的五種變體對應):
| 變體 | 何時 |
|---|---|
.completed(executionId, .approved) |
服務端通過 |
.completed(executionId, .rejected) |
服務端拒絕 |
.completed(executionId, .review) |
提交在帶外進行人工審覈 |
.waiting(executionId) |
等待服務端通知最終決定 |
.dismissed(executionId?) |
用戶退出但打算稍後返回(可恢復);若工作流尚未開始,executionId
爲 nil
|
.cancelled(executionId) |
用戶主動放棄;執行已銷燬,不可恢復 |
.failed(code, message, executionId?) |
內部錯誤 |
.dismissed 表示用戶暫停、可恢復;.cancelled
表示用戶放棄、服務端執行已銷燬(不可恢復)。若失敗發生在執行創建之前,executionId
可能爲 nil;如果存在,請在工單中附上該 ID
以加快排查。
Handler 風格入口
verificationHandler { (isApproved: Bool) }
在最終通過/拒絕決定時觸發。sdk.status(WIDTHStatus):.approved、.finallyRejected、.pending(人工審覈)、.incomplete(中途退出
/
等待,可恢復)、.cancelled(已銷燬)、.failed。當爲
.failed
時,sdk.failReason(WIDTHException)爲
.initialization、.network、.api、.permission、.workflow、.unknown
之一 — 每個都暴露 code 與 message。
主題定製
驗證界面默認跟隨系統外觀。用 dayNightMode
強制指定模式;省略則跟隨系統。
let sdk = WIDTHMobileSDK(accessToken: "YOUR_SDK_TOKEN") sdk.dayNightMode = .night // optional; omit to follow the system
恢復與生命週期
與 Android 行爲一致。在 iOS 上,活躍工作流期間會禁用 sheet 的下滑關閉手勢,以防止意外丟失進度。
| 用戶選擇 | 行爲 | 結果 | 可恢復? |
|---|---|---|---|
| 暫停並退出(保留進度) | 服務端執行被保留 | .dismissed |
是 |
| 結束驗證(放棄) | 服務端取消,執行已銷燬 | .cancelled |
否 |
恢復驗證時,使用相同的 customerId 再次啓動驗證界面,SDK
會自動檢測進行中的工作流。
權限
| 權限 | Info.plist 鍵 | 必填 | 用途 |
|---|---|---|---|
| 相機 | NSCameraUsageDescription |
是 | 證件採集、活體檢測 |
| 麥克風 | NSMicrophoneUsageDescription |
是 | 證件驗證流程錄製背景音頻作爲反欺詐措施 |
| 照片庫 | NSPhotoLibraryUsageDescription |
否 | 僅當允許用戶從照片庫選取證件圖片時(系統 PhotosPicker 並不嚴格要求該 key) |
| 語音識別 | NSSpeechRecognitionUsageDescription |
是 | 由 App Store 入庫校驗檢查。運行時永不申請該權限,用戶也就永遠看不到這句文案 |
NSMicrophoneUsageDescription
會在啓動時導致硬崩潰。NSSpeechRecognitionUsageDescription
同樣必填,但它卡的是 App Store 入庫校驗、不是運行時(見「安裝」一節)。沒有任何
SDK 環境相關的 Info.plist key(無位置 key、無 token key)。網絡:通過
URLSession 使用 HTTPS,無需配置
NSAppTransportSecurity 例外。
App Thinning:XCFramework 支持 App Thinning。不嵌入
Bitcode(已在 Xcode 14 中棄用)。如遇 release 構建問題,請檢查應用
target 中
Strip Swift Symbols
(STRIP_SWIFT_SYMBOLS) 是否設置爲默認值 (YES)。
故障排查
| 問題 | 解決方案 |
|---|---|
| No such module 'WidthIdentity' |
SPM:File > Packages > Resolve Package
Versions。確認 WidthIdentity 庫已添加到
Target > General > Frameworks, Libraries, and Embedded
Content
中。CocoaPods:聲明私有源
source 'https://github.com/width-com/Specs.git',執行
pod install,並打開 .xcworkspace(而非
.xcodeproj)。
|
啓動時返回 .failed(如
W-INIT-410)
|
VerificationInput 初始化器在 domain /
sdkToken 爲空,或 customerId /
email
爲空時拋錯;輸入閉包拋出的錯誤會表現爲
.failed。請確認這四項都非空。
|
| 攝像頭無法使用 |
確保 Info.plist 中存在
NSCameraUsageDescription
且描述不爲空。若用戶此前已拒絕權限,iOS 不會重新彈窗 — SDK
會檢測到此狀態並顯示引導界面,指引用戶前往設置 > 你的應用 > 相機開啓權限。
|
| 主題顏色未生效 | 檢查十六進制值、令牌名稱(區分大小寫)及正確的主題字典 |
| SwiftUI sheet 未彈出 |
將 .widthVerification /
.widthMobileSDK
附加到視圖層級中的視圖上,而非條件性添加
|
| UIKit:"not in window hierarchy" |
在 viewDidAppear 之後從視圖控制器發起呈現
|
| 活體檢測頁面語言不對 |
AWS 活體檢測頁面的文案跟隨設備語言,不跟隨 SDK 的
language 設置。流程的其餘部分仍按
sdk.language 顯示。
|
from: 值,或 Podfile 裏的版本),再重新解析依賴即可。
集成說明
請按上文獲取軟件包訪問權限並完成安裝。SDK 構建版本及所用憑證須與目標 WIDTH 環境保持一致。