file

這一兩天公司專案開發的 App 有需要加入 QR Code 掃描的功能,原本這並不是什麼困難的需求,但麻煩的地方在於我們目前的 App 架構都是用 WebView 包網頁的方式去做的(包括標題列等等都是網頁),而我們希望盡量不要在中途又暫時切換回到原生的畫面,以免一些 UX 上的小細節不夠一致。因此,我花了一點時間評估在 WebView 裡面用網頁來開啟 QR Code 掃描器的可行性。

先講結論;就結果來說,Android 大抵是沒有問題(當然我並沒有測試太老舊的版本),但是 iOS 只能支援到 14.3 版以上,因為一直到該版本 iOS 才終於在 WKWebView 上頭引入了 WebRTC 功能,而沒有這個功能的話當然也沒有辦法在網頁上顯示出即時的相機鏡頭(這個功能其實就是靠在網頁上播放一個即時的影片做到的,所以需要 WebRTC)。在本文寫成的時候,台灣部份的 iOS 版本統計顯示大概只有 42% 的使用者已經更新到了 14.3 版以上,算是有點尷尬的狀況,不過咱們的 PM 很樂觀地說「沒關係等到 App 全部開發完上架的時候應該就都更新了」,所以就這樣唄~ 🤣🤣🤣🤣

掃描器的部份,我採用的是 Html5-QRCode 這個套件,它意外地掃起來還算滿靈敏的,效能上並不會明顯地不如原生的掃描程式。有了套件之後,再來當然就是關鍵的 WebView 設定了;底下我分成 Android 和 iOS 兩種來描述。

先說明,我在嘗試設定的時候也是跌跌撞撞搞了老半天才終於弄到可以用,所以我做的這些設定到底哪些是絕對關鍵的、哪些又是可有可無其實我也搞不太懂,但總之最後這些全部加起來是行得通得。

內容目錄

Android

首先是 Manifest 的部份,加入底下的這些權限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera2.full" />
<uses-feature android:name="android.hardware.camera2.autofocus" />
<uses-permission android:name="android.webkit.PermissionRequest" />

然後 WebView 的設定部份(我用 Kotlin 來寫):

val settings = webView.settings
settings.allowContentAccess = true
settings.mediaPlaybackRequiresUserGesture = false

最後在 WebView 使用的 WebChromeClient 實體之中必須覆寫掉這個方法:

override fun onPermissionRequest(request: PermissionRequest) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        request.grant(request.resources)
    }
}

最後當然 App 本身在初次啟動或者準備要啟用鏡頭的時候也一樣要向使用者請求使用鏡頭的權限,這個部份跟原生的設置方法一樣(利用 ActivityCompat.shouldShowRequestPermissionRationale() 方法等等),所以這邊我就不贅述了。

iOS

跟原生一樣,必須要先在 Info.plist 裡面設置 Privacy - Camera Usage Description 來讓請求使用者同意使用鏡頭(描述字串寫什麼都沒差,是給使用者看的)。然後是 WKWebView 的設定,這部分我是採用用程式碼產生 UI 的寫法,用 Storyboard 的話應該也大同小異。

let webConfiguration = WKWebViewConfiguration()
webConfiguration.mediaTypesRequiringUserActionForPlayback = []
webConfiguration.allowsInlineMediaPlayback = true

let frame = CGRect(...)
webView = WKWebView(frame:frame, configuration: webConfiguration)
更新:

後來的版本中似乎還要明確請求鏡頭權限如下,否則系統會不認得這是一個會請求鏡頭權限的 App:

import AVFoundation

...

AVCaptureDevice.requestAccess(for: .video) { granted in
    if granted {
        // 處理機制,或者不處理也沒差
    }
}

分享此頁至:
最後修改日期: 2023/09/05

留言

James Chan 

我想問一下您是如何處理 前後鏡頭的問題呢?

    這個在 Html5-QRCode 的說明文件中有解釋;例如利用 { facingMode: “environment” } 的啟動設定就可以指定你偏好後鏡頭。

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。您的留言可能會在審核之後才出現在頁面上。