Hello, android-webview-dev team!
For reasons, I have to explore an idea of a headless WebView.
It has to be done in the scope of an sdk, so the only context available is application one. Attempt to attach the webview to the window is out of question, unfortunately, because it creates either set of unsolvable problems or very invasive and intrusive sdk.
The plan is to create a webview, but never attach it a window. And use it as a crude replacement for a socket connection in this particular use case.
The webview loads a page with some js runtime, that contains business logic. The sdk communicates some native calls to the js runtime, the page responds with some events. Both calls and events are asynchronous. The headless webview remains headless for the whole cycle, and other webviews, conventionally attached and detached to a widnow, can coexist at the same time.
I know this is not the best solution by a big margin, and I know js bridge is obsolete and unsafe. I'm not the shot caller, and this question is part of my effort to turn the tides.
My line of thought is: it's called a WebVIEW, and being attached to view hierarchy is part of it's expected lifecycle. But what happens when it's not attached? I barely can find any information on that. I understand that a quote from android developers WebView documentation: "
WebView objects allow you to display web content as part of your activity layout, but lack some of the features of fully-developed browsers" implies without attaching to a window all bets are off. But it's a feeling and vague logic, not an evidence.
Most likely the functionality will be implemented this way regardless, because the POC I created kinda works.
My question is what are the risks?
At the very least I want to warn the web page developers and management of what risks\pitfalls to expect with this approach. Unfortunately, I don't know anything about the webpage being loaded, i.e. js version, frameworks, etc. But I can try gather any information necessary for the best recommendation.
Thank you in advance android-webview-dev team!
Best regards,
Serhii
P.S: Here is a class which demonstrates the idea in a nutshell
internal class HeadlessWebViewAsService(
private val context: Context,
) {
private var webView: WebView? = null
private val bridge: Any = object : Any() {
@JavascriptInterface
fun sendEvent(event: String) {
// do stuff according to the received event
}
}
fun start(url: String) {
disposeWebView()
webView = WebView(context).apply {
settings.apply {
setWebContentsDebuggingEnabled(true)
javaScriptEnabled = true
}
addJavascriptInterface(bridge, "NativeAppInterface")
webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
inject(pingInjection)
}
}
}
webView?.loadUrl(url)
}
fun stop() {
disposeWebView()
}
fun inject(js: String) {
Handler(Looper.getMainLooper()).post {
webView?.evaluateJavascript(js, null)
}
}
private fun disposeWebView() {
webView?.destroy()
webView = null
}
private val pingInjection = """
(function() {
function sendPing() {
if (window.NativeAppInterface && NativeAppInterface.sendEvent) {
NativeAppInterface.sendEvent('pingEvent');
}
}
sendPing();
setInterval(sendPing, 1000);
})();
""".trimIndent()
}