Integrasi Mobile•Android (Kotlin)
Implementasi Native Android (Kotlin)
Panduan integrasi lengkap untuk aplikasi **Android Native** menggunakan bahasa Kotlin, komponen android.webkit.WebView, dan WebChromeClient.
1. Konfigurasi AndroidManifest.xml
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:usesCleartextTraffic="false"
... >
<activity android:name=".QoinWebviewActivity" />
</application>
</manifest>2. Activity Lengkap (QoinWebviewActivity.kt)
QoinWebviewActivity.kt
package id.qoin.client
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.webkit.*
import androidx.appcompat.app.AppCompatActivity
import org.json.JSONObject
class QoinWebviewActivity : AppCompatActivity() {
private lateinit var webView: WebView
private var signature: String = ""
private var palette: String = "original"
private var baseUrl: String = "https://seamless.qoin.id"
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_qoin_webview)
signature = intent.getStringExtra("EXTRA_SIGNATURE") ?: ""
palette = intent.getStringExtra("EXTRA_PALETTE") ?: "original"
baseUrl = intent.getStringExtra("EXTRA_BASE_URL") ?: "https://seamless.qoin.id"
webView = findViewById(R.id.webView)
val settings = webView.settings
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.setGeolocationEnabled(true)
settings.databaseEnabled = true
// JavaScript Bridge untuk menangkap pesan balik
webView.addJavascriptInterface(object {
@JavascriptInterface
fun postMessage(message: String) {
runOnUiThread {
handleWebviewMessage(message)
}
}
}, "QoinBridge")
// WebChromeClient untuk meneruskan izin Geolocation GPS & Kamera
webView.webChromeClient = object : WebChromeClient() {
override fun onGeolocationPermissionsShowPrompt(
origin: String,
callback: GeolocationPermissions.Callback
) {
callback.invoke(origin, true, false)
}
override fun onPermissionRequest(request: PermissionRequest) {
if (request.resources.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
request.grant(arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE))
} else {
request.deny()
}
}
}
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
injectPostMessage()
}
}
webView.loadUrl("$baseUrl/")
}
private fun injectPostMessage() {
val payload = JSONObject().apply {
put("Signature", signature)
put("Palette", palette)
}.toString()
val script = """
(function() {
window.addEventListener('message', function(event) {
if (window.QoinBridge) {
var d = typeof event.data === 'string' ? event.data : JSON.stringify(event.data);
window.QoinBridge.postMessage(d);
}
});
window.postMessage($payload, '*');
})();
""".trimIndent()
webView.evaluateJavascript(script, null)
// Retry pengiriman 500ms kemudian
Handler(Looper.getMainLooper()).postDelayed({
webView.evaluateJavascript("window.postMessage($payload, '*');", null)
}, 500)
}
private fun handleWebviewMessage(message: String) {
try {
val json = JSONObject(message)
if (json.optBoolean("close", false)) {
val intent = Intent().apply {
putExtra("RESULT_DATA", message)
}
setResult(RESULT_OK, intent)
finish()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}Hardware Back Button
Tambahkan penanganan tombol Back perangkat Android agar pengguna dapat kembali ke halaman sebelumnya di dalam WebView (
if (webView.canGoBack()) webView.goBack() else finish()).