android 与 webview 互相调用通信

围巾🧣 2024年07月05日 185次浏览

在 Android 应用中,可以通过 WebView 和 JavaScript 的双向通信实现 Android 和 Web 内容的互动。

通信方法:

以下代码示例展示了

如何使用 @JavascriptInterface 注解来实现从 JavaScript 到 Android 的同步调用

如何使用 evaluateJavascript 来实现从 Android 到 JavaScript 的同步调用

在 Android 应用中,如果你想从 Android 端调用 JavaScript 方法并传递数据给 WebView 中的 JavaScript,可以使用 evaluateJavascript 方法。以下是一个详细的示例,展示了如何实现这一点。

Android 端代码

  • 创建 JavaScriptInterface 类:

    用来接收来自 js 的回调

class MyJavaScriptInterface {

    @JavascriptInterface
    fun callFunctionSync(funcName: String, dataFromJs: String): String {
        Log.d("MyJavaScriptInterface", "callFunctionSync: 方法名=$funcName, dataFromJs=$dataFromJs")
        var handleResult = ""
        // Convert async process to synchronous
        runBlocking {
            handleResult = handleRequestSync(funcName, dataFromJs)
        }
        return handleResult
    }

    private suspend fun handleRequestSync(funcName: String, dataFromJs: String): String {
        val handleResult = suspendCoroutine<String> { continuation ->
            mCommunicator?.handleJsRequest(funcName, dataFromJs) { callbackResult ->
                continuation.resume(callbackResult)
            }
        }
        return handleResult
    }

    private var mCommunicator: Communicator? = null

    interface Communicator {
        fun handleJsRequest(funcName: String, data: String, callback: (String) -> Unit)
    }

    fun setCommunicator(communicator: Communicator) {
        mCommunicator = communicator
    }
}
  • 在 Activity 或 Fragment 中设置 Communicator 并调用 JavaScript 方法:

    设置 WebView 并启用 JavaScript:

class WebviewActivity : AppCompatActivity(), MyJavaScriptInterface.Communicator {

    private lateinit var binding: ActivityWebviewBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityWebviewBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val webView = binding.webView
        webView.settings.javaScriptEnabled = true
        val jsInterface = MyJavaScriptInterface()
        jsInterface.setCommunicator(this)
        webView.addJavascriptInterface(jsInterface, "AndroidFunction")
        webView.loadUrl("file:///android_asset/index.html")

        // 从Android调用JavaScript函数的例子
        binding.button.setOnClickListener {
            webView.evaluateJavascript("javascript:showMessageFromAndroid('Hello from Android')", null)
        }
    }

    override fun handleJsRequest(funcName: String, data: String, callback: (String) -> Unit) {
        // Handle the JS request and call the callback with the result
        val result = "Result: 666"
        callback(result)

        // 也可以从Android调用JavaScript函数把结果回调
        runBlocking(Dispatchers.Main) {
//            val webView = binding.webView
//            val jsCode = "javascript:handleResponseFromAndroid('$result')"
//            webView.evaluateJavascript(jsCode, null)
        }
    }
}
  • 布局文件 res/layout/activity_webview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".WebsocketActivity">

    <WebView
        android:layout_margin="24dp"
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="400dp"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="调用 webview 的方法" />


</LinearLayout>

HTML 和 JavaScript 端代码

创建 assets/index.html

在 HTML 文件中,定义 JavaScript 方法以便 Android 调用:

<!DOCTYPE html>
<html>
<head>
    <title>WebView Communication</title>
</head>
<body>
<h1>WebView Communication</h1>
<button onclick="callAndroidFunction()">Call Android Function</button>
<textarea id="textArea" style="width: 100%; height: 200px;">Text~~~</textarea>

<script type="text/javascript">
        function callAndroidFunction() {
            var result = AndroidFunction.callFunctionSync("someFunction", "data from JS");
            setTextAreaContent("Result from Android: " + result);
        }

        function showMessageFromAndroid(message) {
            setTextAreaContent("Message from Android: " + message);
        }

        function handleResponseFromAndroid(response) {
            setTextAreaContent("Response from Android: " + response);
        }

        function setTextAreaContent(content) {
            var textarea = document.getElementById('textArea');
            textarea.value = content;
        }
    </script>
</body>
</html>

说明

  1. JavaScript 调用 Android 方法:通过 AndroidFunction.callFunctionSync 调用 Android 方法,并传递函数名称和数据。返回结果可以同步接收。
  2. Android 调用 JavaScript 方法:通过 evaluateJavascript 方法调用 JavaScript 代码,例如 showMessageFromAndroidhandleResponseFromAndroid
  3. 通信接口Communicator 接口用于处理 JavaScript 请求,并通过回调返回结果。调用 evaluateJavascript 实现从 Android 到 JavaScript 的调用。