Skip to main content

Handling Permissions

The Scantrust Web Video Authentication experience requests browser-level permissions (camera and geolocation). When the experience is loaded inside a WebView / WKWebView, these JavaScript permission request can fire on top of the OS-level request your native app has already asked.

To avoid this, you can intercept the WebView's permission requests in your delegate and resolve them programmatically using your app's native permission state.

Android

Manifest

Declare the required permissions and camera hardware features in AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />

<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

Setting android:required="false" on the camera features keeps the app installable on devices without a camera.

Bridge the WebView's Camera Request

Override WebChromeClient.onPermissionRequest to intercept JavaScript camera requests, and answer them from your native permission state. Use ActivityResultContracts.RequestPermission to acquire the native Manifest.permission.CAMERA if it is not already granted:

private var pendingRequest: PermissionRequest? = null

private val cameraPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
pendingRequest?.let { req ->
if (granted) req.grant(req.resources) else req.deny()
pendingRequest = null
}
}

webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest?) {
request?.let { req ->
if (req.resources.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
if (ContextCompat.checkSelfPermission(
this@MainActivity, Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED) {
req.grant(req.resources)
} else {
pendingRequest = req
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
} else {
// Other resources (e.g. microphone) — grant or deny per your app's policy.
req.grant(req.resources)
}
}
}
}

For the full integration including WebView setup and a permission rationale dialog, see the Android example app.

iOS

Info.plist

Add a camera usage description so the OS-level prompt shows your app's branding and explanation:

KeyValue
Privacy - Camera Usage Description (NSCameraUsageDescription)A short message explaining why the app needs camera access.

If the video authentication is configured to use the browser's geolocation API, also add a location usage description:

KeyValue
Privacy - Location When In Use Usage Description (NSLocationWhenInUseUsageDescription)A short message explaining why the app needs location access.

Bridge the WKWebView's Camera Request

Conform to WKUIDelegate on the view controller managing your WKWebView, set it as the uiDelegate, and implement requestMediaCapturePermissionFor. Use AVCaptureDevice.authorizationStatus(for: .video) to answer the JavaScript request from native state:

import AVFoundation
import WebKit

class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!

override func viewDidLoad() {
super.viewDidLoad()
webView = WKWebView(frame: view.bounds, configuration: WKWebViewConfiguration())
webView.uiDelegate = self
view.addSubview(webView)
}

func webView(_ webView: WKWebView,
requestMediaCapturePermissionFor origin: WKSecurityOrigin,
initiatedByFrame frame: WKFrameInfo,
type: WKMediaCaptureType,
decisionHandler: @escaping (WKPermissionDecision) -> Void) {
guard type == .camera || type == .cameraAndMicrophone else {
decisionHandler(.prompt)
return
}
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized:
decisionHandler(.grant)
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { granted in
DispatchQueue.main.async { decisionHandler(granted ? .grant : .deny) }
}
case .denied, .restricted:
decisionHandler(.deny)
@unknown default:
decisionHandler(.deny)
}
}
}

For the full integration including a "Settings" alert when camera access is denied, see the iOS example app.