[Android]Android 插件化-续
前言
在上一篇文章中,叙述了Android 的三种完成插件的方法。不过在最终一种中,按照前面所叙述的内容完成有一个约束。
我们之前传递文件是经过evaluateJavascript
,相当于注入javascript 代码,这种方法会约束我们传递的数据的长度,当我们传递一个大一点的文件就会呈现问题,亟待一个更好的方法完成文件的传递。
MessageChannel
在web 开发中,会运用iframe,将一个页面嵌入到另一个页面中,此刻,假如需要在这两个页面中传递数据,用的便是MessageChannel。不止页面之间能够运用这种方法,native 与WebView 中的页面也能够运用这种方法。
-
第一种
在html 中,经过window 注册一个message 的listener。
window.addEventListener("message", onMessage); function onMessage(e) { ele.src = "data:image/png;base64," + e.data; // Use the transfered port to post a message back to the main frame e.ports[0].postMessage("Message back from the IFrame"); }
然后在Android 端,首要生成一对MessageChannel。回来的是一个数组,包括两个MessageChannel。
然后是注册
WebMessageCallback
val baseUrl = "http://www.example.com" val messageChannel = if (WebViewFeature.isFeatureSupported(WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL)) { WebViewCompat.createWebMessageChannel(webView) } else null if (messageChannel != null && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK)) { messageChannel[0].setWebMessageCallback(object : WebMessagePortCompat.WebMessageCallbackCompat() { override fun onMessage(port: WebMessagePortCompat, message: WebMessageCompat?) { Log.d(TAG, "onMessage() called with: port = $port, message = ${message?.data}") super.onMessage(port, message) } }) }
然后在页面加载完成后发送音讯
override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) url ?: return view ?: return messageChannel?.let { if (WebViewFeature.isFeatureSupported(WebViewFeature.POST_WEB_MESSAGE)) { val webMessageCompat = WebMessageCompat(content, it) WebViewCompat.postWebMessage(view, webMessageCompat, Uri.parse(baseUrl)) } } }
注意加载内容的方法。假如我们的内容是本地文件,需要手动置顶一个origin
webView.loadDataWithBaseURL(baseUrl, indexFile.readText(), null, null, null)
假如是http 或许https 等自带地址的就无所谓了。
理论上是这样啦,但是实际运用的时分会呈现过错
java.lang.IllegalStateException: Port is already started
一旦经过
messageChannel[0].setWebMessageCallback
设置监听,然后再发送音讯就会呈现过错。假如不设置监听,发送音讯是没有问题的,但是这样双向的交流就变成了单向的了。不过,我们还有第二种
-
第二种
在Android 端
val baseUrl = "http://www.example.com" if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { WebViewCompat.addWebMessageListener(webView, "test", setOf(baseUrl)) { view, message, sourceOrigin, isMainFrame, replyProxy -> Log.d(TAG, "onCreate() called with: view = $view, message = ${message.data}, sourceOrigin = $sourceOrigin, isMainFrame = $isMainFrame, replyProxy = $replyProxy") } }
我们传递一个
"test"
,然后我们在javascript 中便能够经过test 发送音讯以及监听数据。test.onmessage = function(event) { // prints "Got it!" when we receive the app's response. console.log(event.data); } test.postMessage("hello from yue-html")
但是,这种方法也有一个问题,无法从native 自动发送音讯,只能在html 发送音讯之后,才能在addWebMessageListener 中经过
replyProxy.postMessage
发送音讯。
最终
这种方法与evaluateJavascript 不同,MessageChannel 足以之后发送大文件。