Introduction
TrustX is not only supported in browser flows but also allows for integration through WebView objects such that users can implement the TrustX flow directly through their native applications.
This document will cover integration requirements for Android devices.
WebView Configuration
Android WebView is a standard Android framework component located in android.webkit package. The WebView component has several configuration options that need to be set in order for it to correctly load the TrustX flow. Mandatory configuration options that need to be set are listed below:
- webChromeClient
- settings
- JavaScript interface
WebChromeClient Configuration
A WebChromeClient is another class in Android used in conjunction with a WebView
component to provide additional customization and control over the behavior of web content displayed within an Android application. While
the WebViewClient focuses on the loading and navigation aspects of the WebView, the WebChromeClient
deals with interactions and events related to the Chrome browser
itself, such as JavaScript dialogs, permission requests, and progress
updates.
WebChromeClient configuration for Daon TrustX flow includes overriding two callbacks:
onPermissionRequest(request: PermissionRequest?)- This callback is triggered when certain permissions are requested from theWebView. In case of TrustX flow, this is in regards toCAMERApermissions. Therequestparameter has all of the necessary information and options to handle permission request response actions, includinggrant()anddeny()calls. Origin URI (request?.origin) should be checked every time this callback is triggered to make sure that the provided request came from the genuine WebApp.onConsoleMessage(consoleMessage: ConsoleMessage?)- Is used to capture and handle messages logged to the JavaScript console. This override is optional and serves the purpose of giving more information about the flow that happens inside of theWebViewcomponent.onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean- Is used to handle the file chooser event that is triggered by the user on the WebView component. Overriding is mandatory for the additional documents upload feature as the additional document images and/or files need to be uploaded from the file system of the device. Options for file choosing can differ between devices, but nevertheless should include camera capture and file manager options for the user to choose from.
A code sample of the component configuration is shown below (given in Kotlin syntax):
class CustomWebChromeClient(private val listener: WebChromeClientListener) : WebChromeClient() { private lateinit var permissionRequest: PermissionRequest override fun onPermissionRequest(request: PermissionRequest?) { if (request != null) { permissionRequest = request listener.onRequestPermission(request.resources[0]) } } override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean { ... return super.onConsoleMessage(consoleMessage) } fun onPermissionGranted() { permissionRequest.grant(permissionRequest.resources) } override fun onShowFileChooser( webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams? ): Boolean { listener.onShowFilePicker(filePathCallback, fileChooserParams) return true }}Camera Permissions
WebView handling of camera permissions requires that users override the onPermissionRequest as detailed in the section above.
In this example, permissions are granted for the WebView first by overriding the onPermissionRequest() method and sending a permissions request to the device.
Example:
//This section is requesting permissions for WebView.class CustomWebChromeClient(private val listener: WebChromeClientListener) : WebChromeClient() { private lateinit var permissionRequest: PermissionRequest override fun onPermissionRequest(request: PermissionRequest?) { if (request != null) { permissionRequest = request listener.onRequestPermission(request.resources[0]) } } fun onPermissionGranted() { permissionRequest.grant(permissionRequest.resources) }}Once the onPermissionRequest callback has been triggered, the camera permission request is sent via the listener to Activity implementation. The example below demonstrates how permissions are requested from the user and, if granted, the permission information is returned to the Chrome client using the onPermissionGranted() call.
Example:
// Handling application layer camera permissionsprivate val requestCameraPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean -> if (!isGranted) { Log.d(TAG, "isNotGranted: ") } else { Log.d(TAG, "isGranted: ") customWebChromeClient.onPermissionGranted() } }Settings Configuration
WebView settings refer to a set of configuration options and parameters that control the behavior and functionality of a WebView component. These settings allow developers to customize how web content is displayed and interacted with inside the WebView. You can access and configure these settings using the WebSettings class, which is typically obtained from the WebView via the getSettings() method.
WebView settings configuration for Daon TrustX flow includes:
- useWideViewPort set to
true- When set totrue, it allows the web page's "viewport" to be scaled to fit the width of theWebViewcontrol. - loadWithOverviewMode set to
true- When set totrue, theWebViewwill load the web page and display it as if it were zoomed out to fit the width of theWebView's viewport. - javaScriptEnabled set to
true- When set totrue, it allows JavaScript code embedded in the web pages displayed in theWebViewto execute. - mediaPlaybackRequiresUserGesture set to
false- When set tofalse, media elements on web pages will automatically start running when the page is loaded. This option is mandatory in order for camera capture screens to work without requiring any user interaction. - domStorageEnabled set to
true- controls whether web page scripts are allowed to use the web storage feature of the Document Object Model (DOM). For TrustX use cases, it is mandatory that this value is set totrueso that web pages can uselocalStorageandsessionStorage.
A code sample of the settings configuration is shown below (given in Kotlin syntax, but very similar in Java):
settings.apply { useWideViewPort = true loadWithOverviewMode = true javaScriptEnabled = true mediaPlaybackRequiresUserGesture = false domStorageEnabled = true}JavaScript Interface Configuration
A JavaScript interface of the WebView component is a mechanism that allows JavaScript code to run in a web page displayed within a WebView. This allows the Javascript code to communicate with and invoke methods in the Android application's Java code. It enables bi-directional communication between JavaScript running in the WebView and native Java code, making it possible to exchange data and trigger actions between the web page and the Android app.
Integration of JavaScript interface is fairly simple, and requires only adding it to the WebView component using the addJavaScriptInterface standard function. This call requires one additional parameter which is the name of the JavaScript interface that is being set. This name is used on the web side to indicate which interface is being set and used for this particular WebView component.
A code sample of the Daon TrustX JavaScript interface setup is shown below (given in Kotlin syntax, but very similar in Java):
//This name is required to be set in order for WebView to work with Daon TrustX flowprivate const val MOBILE_FORM_HANDLER = "MobileFormHandler"...val webView = findViewById(R.id.trustXWebView)webView.addJavascriptInterface(trustXJavaScriptHelper, MOBILE_FORM_HANDLER)...And the implementation of JavaScript interface class TrustXJavaScriptHelper is shown below:
class TrustXJavaScriptHelper { fun webLoaded() { /* * Used to notify the Android app that the web page was successfully loaded. * There are other mechanisms for this, but in Daon TrustX use case, we're * ensuring that our own web page is being loaded because after this callback * is received, Daon TrustX web app waits for the same callback from Android * app to be triggered. */ } fun webCompleted() { /* * Used to notify the Android app that the Daon TrustX flow has been completed. */ } fun webTimeout() { /* * Indicates that an activity has expired during the TrustX flow. */ } fun openCameraSettings() { /* * Used to notify the Android app that the WebApp is requesting opening of the application settings. */ } fun error(message: String) { /* * Used to notify the Android app that the WebApp has encountered an error. */ }}The following table details all String messages that will be received from TrustX.
| Event Name | Description |
|---|---|
webLoaded | A safety feature to ensure that only the TrustX web app can be loaded. |
webCompleted | indicates the completion of the TrustX flow. |
webTimeout | Indicates that an activity has expired during the TrustX flow. |
openCameraSettings | Used to notify the Android app that the WebApp is requesting to open the application settings. |
error | Indicates an error has occurred. |
Example of full WebView component configuration
Below is the code example showing how to initialise, configure and load URL into WebView component using the above implementations:
class MainActivity : AppCompatActivity(), WebChromeClientListener { private val MOBILE_FORM_HANDLER = "MobileFormHandler" private lateinit var webView: WebView private var filePathCallback: ValueCallback<Array<Uri>>? = null private var fileChooserParams: WebChromeClient.FileChooserParams? = null private lateinit var customWebChromeClient: CustomWebChromeClient private val fileChooserLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {} private val requestCameraPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {} private val settingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {} override fun onCreate(savedInstanceState: Bundle?) {} override fun onBackPressed() {} override fun onShowFilePicker( filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: WebChromeClient.FileChooserParams? ) {} override fun onRequestPermission(permission: String) {} override fun onWebLoaded() {} override fun onWebCompleted() {} override fun onWebTimeout() {} override fun openCameraSettings() {}}interface WebChromeClientListener {}Note: The URL string that required for the webView.loadUrl() should be the Process Definition Token URL. More information on Process Definitions could be found in the Process Definition guide.
Handling Android Back Action
This section will describe the configuration parameters, that are not tightly connected to the WebView component integration, but are mandatory for the use cases in TrustX flow.
Activities and Fragments in Android framework are notified about the keyboard back action events through the onBackPressed callback. In the Daon TrustX use case, this callback need to be overridden in the component that started the WebView and the back action should be delegated to WebView in the way that is shown below, to ensure that the navigation in the flow is correctly executed:
override fun onBackPressed() { if (webView.canGoBack()) { webView.goBack() } else { super.onBackPressed() }}Android Manifest
The application should implement support for two Android permissions in order for the TrustX flow to work correctly:
- INTERNET permission - allows the application to access the internet (used in this flow to communicate with the WebApp).
- CAMERA permission - allows the application to access the camera (used in this flow to capture face and/ or documents).
Example:
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.CAMERA" />Known Issues and Limitations
One of the main issues that Android WebView integration with TrustX flow has shown is the very slow and often interrupted camera flow. It is best described as a “lagging” issue that happens when the camera is actively trying to capture and analyse frames. This can happen during the Face and Document capture steps. To ensure that this issue happens as rarely as possible, Daon have added several implementation insurances that the WebView component is overloaded as little as possible memory-wise.
Some solutions included:
- Starting the whole
WebViewflow in the new process and enablinghardware accelerationfeature.
Code Sample:
<activity android:name="com.example.DaonTrustXActivity" android:exported="true" android:process=":Onboarding" android:hardwareAccelerated="true"/>- Clearing all of the cashed memory of the
WebViewafter the completed session and before the start of the new session.
Code Sample:
webView.apply { clearCache(true) clearFormData() clearHistory() clearSslPreferences()}CookieManager.getInstance().apply { removeAllCookies(null) flush()}WebStorage.getInstance().deleteAllData()webView.removeAllViews()webView.destroy()These options help to mitigate the occurrences of this particular issue, but intermittent issues may occur in some integrations.