個案研究

SmileID 如何運用 CameraX,將身分驗證功能擴展至超過 18,000 種 Android 裝置

4 分鐘讀物
查看 Donovan McMurray 的個人資料
Donovan McMurray 開發人員關係工程師

銀行和 SIM 卡註冊的身分驗證應用程式需要清晰的高解析度臉部圖像,才能偵測到假冒和深偽內容。Android 相機開發人員常面臨一項挑戰:如何擷取足夠清晰的影格,以便進行活體偵測和防詐欺檢查,同時避免低記憶體裝置當機。

SmileID 是非洲領先的身分驗證 SDK,由於硬體生態系統多元,這項挑戰更加艱鉅。Android 占 SmileID 目標裝置市占率的 85%,包括處理器效能受限的入門級智慧型手機、不知名的區域機型,以及堅固耐用的自訂銷售點 (POS) 終端機。

harun_quote_card_green.png

在採用 CameraX 之前,SmileID 面臨標準但棘手的相機工程障礙:預覽畫面拉伸、感應器方向旋轉、記憶體不足 (OOM) 當機,以及自訂原始設備製造商 (OEM) 錯誤。SmileID 將核心 Android SDK 遷移至 CameraX,成功將這些挑戰轉化為重大業務優勢。

根據 SmileID 的說法,將 Android SDK 遷移至 CameraX 後,獲得了以下成果:

指標遷移至 CameraX 的影響
SDK 採用率成長第 2 年增加 20 倍 (採用 CameraX 前為 2 到 3 倍)
驗證通過率使用 SmileID SDK 的應用程式增加 20%
擷取解析度自拍/活體偵測像素增加 4 倍,且不會造成網路負擔
裝置型號相容性支援超過 18,000 種 Android 裝置
驗證總數 (已調整)處理超過 1.6 億次身分驗證

挑戰:硬體碎片化和舊版 API 難題

為確認使用者身分,SmileID 的 SDK 必須擷取高解析度自拍畫面,以便在裝置上進行活體偵測,並在雲端偵測 Deepfake。

在舊版 Camera1 和低階 Camera2 API 實作中,由於以下幾個原因,很難持續達到這個目標:

  • 原始設備製造商 (OEM) 自訂和異常狀況:不同製造商的裝置回報實體鏡頭感應器方向的方式不同,導致預覽畫面旋轉或臉部擷取方向不正確。
  • 顯示比例失真:在平價裝置上要求特定影格大小,往往會導致相機預覽畫面垂直或水平拉伸,造成使用者臉部失真,導致生物辨識驗證無法使用。
  • 記憶體不足 (OOM) 導致當機:在 RAM 較低 (通常為 1 GB 以下) 的裝置上處理原始高解析度圖片,經常會導致記憶體配置嚴重當機。

由於這些阻礙,SmileID 的 SDK 採用率年增率僅限於 2 到 3 倍,許多驗證作業必須改為透過高延遲 REST API 上傳靜態相片,而非在裝置端即時執行活體偵測。

解決方案:使用 CameraX 建立一致的管道

SmileID 使用 CameraX 從頭重新設計行動 SDK。CameraX 專為簡化基礎裝置生態系統而設計,並提供一致且原生生命週期感知的開發人員介面。

SmileID 使用 CameraX 的核心用途 (特別是 Preview 和 ImageAnalysis),建構出強大的雙用途相機管道:

  • 預覽:即時預覽攝影機畫面,並以完美比例呈現,引導使用者操作。
  • ImageAnalysis:在本機即時持續處理影格,自動偵測活體和臉部是否在畫面中,並擷取驗證過的自拍影格。

為了擷取超清晰細節,以便偵測 Deepfake,同時避免 OOM 異常終止,SmileID 直接在 ImageAnalysis 設定中加入 CameraX 的新版 ResolutionSelector API。開發人員可以要求目標解析度,並在裝置不支援該大小時選擇備用規則。舉例來說,下圖和設定範例說明 ResolutionSelector 如何評估 1200x900 目標附近的候選大小:

resolution_selector_diagram_vertical.png

以下對應的程式碼範例說明如何在自己的應用程式中,將 ResolutionSelector 與 STRATEGY_KEEP_ONLY_LATEST 搭配使用 (使用 FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER 優先考量清晰度,或使用 FALLBACK_RULE_CLOSEST_LOWER_THEN_HIGHER 限制記憶體用量):

import android.util.Size
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.core.resolutionselector.AspectRatioStrategy
import androidx.camera.core.resolutionselector.ResolutionSelector
import androidx.camera.core.resolutionselector.ResolutionStrategy
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.lifecycle.LifecycleOwner

fun configureCameraX(cameraProvider: ProcessCameraProvider, lifecycleOwner: LifecycleOwner, 
                     surfaceProvider: Preview.SurfaceProvider, 
                     executor: java.util.concurrent.Executor, analyzer: ImageAnalysis.Analyzer) {
    // 1. Define a resolution strategy requesting high quality (for example, 1200x900px) 
    // and selecting the closest higher (or, if unavailable, lower) resolution.
    val resolutionSelector = ResolutionSelector.Builder()
        .setResolutionStrategy(
            ResolutionStrategy(
                Size(1200, 900),
                ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER
            )
        )
        .setAspectRatioStrategy(AspectRatioStrategy.RATIO_4_3_FALLBACK_AUTO_STRATEGY)
        .build()

    // 2. Configure the ImageAnalysis use case with the resolution selector
    // and a backpressure strategy that keeps the UI responsive on slow processors.
    val imageAnalysis = ImageAnalysis.Builder()
        .setResolutionSelector(resolutionSelector)        
        // Drops older frames if the device's CPU is still busy analyzing the previous one
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .build()

    // 3. Set up the preview stream and attach the Analyzer and SurfaceProvider
    imageAnalysis.setAnalyzer(executor, analyzer)
    val preview = Preview.Builder().build().also { it.surfaceProvider = surfaceProvider }

    // 4. Bind both use cases concurrently to the lifecycle provider
    try {
        cameraProvider.unbindAll()
        cameraProvider.bindToLifecycle(
            lifecycleOwner,
            CameraSelector.DEFAULT_FRONT_CAMERA,
            preview,
            imageAnalysis
        )
    } catch (exc: Exception) {
        // Handle binding failure safely
    }
}

SmileID 要求高密度像素影格,並在本機處理,因此自拍解析度提高 4 倍。SmileID 也壓縮了裝置上裁剪的臉部區域,因此網路的上傳大小與先前的系統相同。這種架構可確保機器學習模型獲得更清晰的資料,同時不會增加使用者的行動數據費用。

CameraX 如何解決硬體差異

SmileID 採用 CameraX 做為標準,代表他們可以仰賴兩層相容性工程,確保 SDK 在各種裝置上都能穩定運作:

1. Google 的相機和媒體測試實驗室

CameraX 的相容性是透過持續的實體硬體驗證來確保。在 Google 專屬的相機和媒體測試實驗室中,自動化測試套件每天都會在超過 190 款 Android 裝置型號的大型輪替矩陣中執行。包括不同晶片組、OS 版本和硬體功能的裝置。

為確保熱門裝置的行為更一致,Google 的相機和媒體測試實驗室會自動偵測程式庫迴歸,避免影響正式版程式碼。

2. 自動解決裝置異常問題

不同 Android 裝置有不同的實體限制。有些可能無法設定自訂曝光設定,有些則可能在使用特定顯示比例時,回報顛倒的圖片資料。為避免開發人員根據裝置製造商和型號,在程式碼集中加入複雜的條件區塊,CameraX 會在 camera-camera2 (DeviceQuirksLoader.kt) 中維護內部裝置異常類別,例如 DeviceQuirks 和 CameraQuirks。當 CameraX 偵測到裝置有已知問題時,會自動插入量身打造的解決方法。對 SmileID 來說,這代表他們的 SDK 可以在超過 18,000 種 Android 裝置上穩定運作,不需要在程式碼集中加入裝置專屬修補程式。

驗證次數增加至超過 1.6 億次

SmileID 遷移至 CameraX 後,簡化了外部應用程式開發人員的 SDK 整合流程。

消除顯示比例失真、預覽畫面延遲和突然 OOM 異常終止等問題後,使用其 SDK 的服務驗證通過率提高了 20%。對非洲各地的金融機構和行動貨幣應用程式來說,通過率提高 20% 意味著數十萬名合法使用者成功完成註冊,而不是流失。

juma_quote_card_blue.png

開發人員也注意到這點。由於採用 CameraX 的 SDK 易於整合,第一年的採用率激增 15 倍,第二年更攀升至 20 倍。目前為止,SmileID 已使用 CameraX 成功處理超過 1.6 億次身分驗證。

運用 CameraX 技能打造相容性故事

開發相機功能並不難。為協助團隊採用 SmileID 使用的 CameraX 模式,Android 推出 AI 程式設計代理專用的 CameraX Skill。

在開發環境中使用 CameraX Skill 時,Gemini 等 AI 程式碼代理會套用目前的 CameraX 模式,用於遷移、生命週期繫結、ConcurrentCamera 和 MlKitAnalyzer。無論是要設定雙攝影機畫面、使用 PreviewView 或 CameraXViewfinder 設定預覽畫面,還是管理即時機器學習 (ML) 分析,CameraX 技能都能引導代理生成精確、可部署於正式環境的程式碼。

作者:
繼續閱讀