Kotlin

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

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:

ProductApp Identifier (postMessage)JWT Identifier (to get JWT)sdk-mobile (to use on sdk-mobile url)zh-web-sdk (to use on ZeroHashSDK class)
OnboardingonboardingonboardinguserOnboardingJWTuserOnboardingJWT
Profileprofileparticipant-profileprofileJWTprofileJWT
Crypto Account Linkcrypto-account-linkcrypto-account-linkcryptoAccountLinkJWTcryptoAccountLinkJWT
Crypto Buycrypto-buycrypto-buycryptoBuyJWTcryptoBuyJWT
Crypto Sellcrypto-sellcrypto-sellcryptoSellJWTcryptoSellJWT
Crypto Withdrawalscrypto-withdrawalscrypto-withdrawalscryptoWithdrawalsJWTcryptoWithdrawalsJWT
Fiat Depositsfiat-depositsfiat-depositsfiatDepositsJWTfiatDepositsJWT
Fiat Withdrawalsfiat-withdrawalsfiat-withdrawalsfiatWithdrawalsJWTfiatWithdrawalsJWT
FundfundfwcfundJWTfundJWT
Fund Withdrawalscrypto-withdrawalscrypto-withdrawalscryptoWithdrawalsJWTcryptoWithdrawalsJWT

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.