Overview
This guide explains how to integrate the Zero Hash SDK into an Android application using Kotlin. The integration requires setting up a WebView and configuring it to communicate properly with the SDK.
Prerequisites
- Read to the official Android WebView documentation.
- Read Zero Hash's documentation on how to generate JWT.
- Read our general overview on how to integrate with mobile apps.
WebView Configuration
To integrate the Zero Hash SDK, create and configure a WebView as shown in the example below:
webView = findViewById(R.id.web_view)
webView.settings.apply {
javaScriptEnabled = true
domStorageEnabled = true
allowContentAccess = true
allowFileAccess = true
mediaPlaybackRequiresUserGesture = false
javaScriptCanOpenWindowsAutomatically = true
}
// This is required for all SDKs
myJavascriptInterface = MyJavascriptInterface(activity, webView, jwt)
// DO NOT change the "NativeAndroid" parameter, otherwise the SDK won't recognize this interface.
webView.addJavascriptInterface(myJavascriptInterface, "NativeAndroid")
// This will pass along permissions from your app to the WebView.
webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
request.grant(request.resources)
}
}
// Adding a WebView inside AndroidView with layout as full screen
AndroidView(
modifier = Modifier
.fillMaxHeight()
.imePadding(),
factory = {
android.webkit.WebView(it).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
// When asked to, will pass along to the WebView the camera access.
webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest?) {
request?.grant(request.resources)
}
}
// Enables javascript in WebView.
settings.javaScriptEnabled = true
// Pass along permissions from APP to Web View
settings.domStorageEnabled = true
settings.allowContentAccess = true
settings.allowFileAccess = true
settings.mediaPlaybackRequiresUserGesture = true
// Extremely important! Without this you won't be able to communicate with the WebView.
addJavascriptInterface(
WebViewJavascriptInterface(activity, this, jwt),
"NativeAndroid"
)
}
}, update = {
it.loadUrl(zhUrl)
})
Explanation of WebView Settings:
- JavaScript Enabled: Required for SDK functionality, as JavaScript
postMessages
will be used to communicate. - DOM Storage Enabled: Ensures web storage works properly.
- Media Playback Requires User Gesture: Set to
false
to allow automatic media playback. This is particularly important for the Onboarding SDK, otherwise the camera live preview won't function properly. - JavaScript Interface: Enables communication between the WebView and the native app. Its name needs to be "NativeAndroid", otherwise the SDK won't recognize this interface.
- WebChromeClient Permissions: Grants necessary permissions, especially important for the Onboarding SDK.
Please, see official Android documentation on WebSettings and WebView for in-depth informatino.
Handling SDK Messages
Create a JavaScript interface to handle communication between the SDK and your Android app. Set this as the javascript interface attached to your WebView configuration.
class MyJavascriptInterface(
private val activity: Activity,
private val webView: WebView,
private val jwt: String
) {
fun onCloseSDK() {
// Implement actions after closing the SDK
}
@JavascriptInterface
fun postMessage(message: String) {
Log.d("WebViewMessage", "Message received: $message")
val json = JSONObject(message)
val messageType = json.optString("type")
if (messageType == "SDK_MOBILE_READY") {
val script = "window.postMessage({type: 'OPEN_MODAL', payload: { appIdentifier: <APP_POST_MESSAGE_IDENTIFIER>, jwt: <YOUR_JWT_HERE>}});"
println("Sending message to WebView: OPEN_MODAL")
activity.runOnUiThread {
webView.evaluateJavascript(script) {
println("Message sent to WebView: OPEN_MODAL")
}
}
}
if (messageType.endsWith("_CLOSE_BUTTON_CLICKED")) {
activity.runOnUiThread {
webView.visibility = View.GONE
onCloseSDK()
}
}
}
}
On line 18, the script creates a postMessage
event. The appIdentifier
attribute can have the following types:
Product | App Identifier (postMessage) | JWT Identifier (to get JWT) | sdk-mobile (to use on sdk-mobile url) | zh-web-sdk (to use on ZeroHashSDK class) |
---|---|---|---|---|
Onboarding | onboarding | onboarding | userOnboardingJWT | userOnboardingJWT |
Profile | profile | participant-profile | profileJWT | profileJWT |
Crypto Account Link | crypto-account-link | crypto-account-link | cryptoAccountLinkJWT | cryptoAccountLinkJWT |
Crypto Buy | crypto-buy | crypto-buy | cryptoBuyJWT | cryptoBuyJWT |
Crypto Sell | crypto-sell | crypto-sell | cryptoSellJWT | cryptoSellJWT |
Crypto Withdrawals | crypto-withdrawals | crypto-withdrawals | cryptoWithdrawalsJWT | cryptoWithdrawalsJWT |
Fiat Deposits | fiat-deposits | fiat-deposits | fiatDepositsJWT | fiatDepositsJWT |
Fiat Withdrawals | fiat-withdrawals | fiat-withdrawals | fiatWithdrawalsJWT | fiatWithdrawalsJWT |
Fund | fund | fwc | fundJWT | fundJWT |
Fund Withdrawals | crypto-withdrawals | crypto-withdrawals | cryptoWithdrawalsJWT | cryptoWithdrawalsJWT |
Loading the SDK-Mobile URL
To load the Zero Hash SDK, generate the URL using the appropriate parameters (as explained in the general integration guide) and load it into the WebView.
Example URL Format:
Certification Environment (For Testing & Development):
https://sdk-mobile.cert.zerohash.com/v1?zeroHashAppsURL=<your_zero_hash_apps_url>&<selectedJWT>=<your_jwt_token>
Production Environment (For Live Deployments):
https://sdk-mobile.zerohash.com/v1?zeroHashAppsURL=<your_zero_hash_apps_url>&<selectedJWT>=<your_jwt_token>
Load the URL into WebView:
webView.loadUrl("https://sdk-mobile.zerohash.com/v1?zeroHashAppsURL=<your_zero_hash_apps_url>&<selectedJWT>=<your_jwt_token>")
webView.visibility = View.VISIBLE
Onboarding SDK Permissions
The Onboarding SDK requires specific permissions to function properly, as some users may need to complete additional identity verification steps. These may include selfie checks, liveness detection, and capturing images of documents, all of which require camera access. Below is the necessary configuration for the AndroidManifest.xml file:
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<!-- Internet Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- Source: https://developer.android.com/about/versions/14/changes/partial-photo-video-access -->
<!-- Devices running Android 12L (API level 32) or lower -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- To handle the reselection within the app on devices running Android 14
or higher if your app targets Android 14 (API level 34) or higher. -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
Requesting Permissions in Kotlin
To ensure the necessary permissions are granted at runtime, use the following method. This is just a suggestion, feel free to tweak the implementation to your application needs.
fun checkPermissions(activity: Activity) {
// Camera access, required for all versions
val requiredPermissions = mutableListOf(
Manifest.permission.CAMERA
)
// Please see official docs:
// https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requiredPermissions.add(Manifest.permission.READ_MEDIA_IMAGES)
} else {
requiredPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE)
}
// Checks which permissions are already granted or not
val permissionsToRequest = requiredPermissions.filter {
ContextCompat.checkSelfPermission(activity, it) != PackageManager.PERMISSION_GRANTED
}
// Asks all permissions using only one popup
if (permissionsToRequest.isNotEmpty()) {
ActivityCompat.requestPermissions(
activity, permissionsToRequest.toTypedArray(), 1
)
}
}
Additional Considerations
- Make sure to pass necessary permissions to the WebView.
- Implement error handling and logging for debugging.
For further details, refer to the Zero Hash API documentation or contact support.