在 Android 的 WebView 中放松 MIME 类型检查?或者强制常规 JavaScript 的模块类型?

Dav*_*ide 8 javascript android webview

我正在 Android 中开发应用程序,其中有一个使用Transcrypt用 javascript 和 python 编写的部分(这几乎与我直接用 javascript 开发该部分相同,但我无法完全控制事物的制作方式)。Android 使用WebView在 Activity 中显示该部分。启动它的相关java代码很简单

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAllowFileAccessFromFileURLs(true);
        webSettings.setAllowUniversalAccessFromFileURLs(true);
        mWebView.loadUrl("file:///android_asset/AndroidWebView.html");
Run Code Online (Sandbox Code Playgroud)

相关部分AndroidWebView.html类似于Transcript 的 iOS 演示

        <script type="module">
            import * as my_app from "./target/my_app.js"; window.my_app = my_app;
        </script>
Run Code Online (Sandbox Code Playgroud)

该应用程序在模拟器上运行良好,但在真实设备上 WebView 拒绝加载 javascript 并抛出以下错误:

Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
Run Code Online (Sandbox Code Playgroud)

如果我通过将 HTML 更改为强制 MIME 类型

        <script type="text/javascript">
            import * as my_app from "./target/my_app.js"; window.my_app = my_app;
        </script>
Run Code Online (Sandbox Code Playgroud)

这似乎适用于我的页面的其他部分,即普通的 javascript(不是模块),它显然会失败Uncaught SyntaxError: Cannot use import statement outside a module

有没有办法强制后面的 HTML 成为一个模块,或者前面的 HTML 不那么严格地检查 MIME 类型?

查看WebView 的选项,我看不到任何相关的内容。环顾四周,这个问题似乎正是由这个错误引起的。

另一方面,在我看来,问题在于script接受类型的 HTML 标记的语法可以是其中之一"text/javascript""module"但不能同时是两者(我尝试过,它似乎只使用第一个),而从语义上讲,有两者都有的理由。是否有解决方法,或者甚至是两者兼得的黑客?我知道一种可以用于加载 的 hack my_app.js,但是该 hack 无法进一步加载其他模块(确实my_app.js如此)。因此,除非有一个转译器或能够自动将我的所有模块合并为一个的东西,否则这是行不通的。FWIW,这些模块是从 Transcrypt 的 python 生成的,所以它必须是一个自动化的过程,而不是手动的过程。

PS:我不是 HTML 或 javascript 开发人员,这些是我在这个领域的第一步,所以请善待我的猜测

PPS:我理解不在计算机上执行任何操作而是启动服务器的原因。这就是我为我的开发环境所做的。但对于 Android 应用程序中的单个 Activity,HTTP 服务器似乎是一种矫枉过正和令人头疼的问题(跟踪端口、潜在的更多故障模式、在浏览器或其他应用程序中可能可见、额外的权限、额外的资源和电池使用情况,以及可能还有更多我没有想到的麻烦)。

Har*_*enH 6

有些事情你可以尝试。

<!DOCTYPE html>1. 通过添加到你的index.html来确保它是html 5

2. 您可以使用 WebViewAssetLoader,而不是使用 file://... 直接从系统加载文件,这将返回 mimetype https://developer.android.com/reference/kotlin/androidx/webkit/WebViewAssetLoader

3. 如果这在 webViewClient 中不起作用,您可以拦截请求并手动添加 text/javascript mimetype:

val webViewAssetLoader = WebViewAssetLoader.Builder()
        .addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(context!!))
        .build()

val webViewClient = object : WebViewClient() {

    override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest): WebResourceResponse? {
        val interceptedWebRequest = webViewAssetLoader.shouldInterceptRequest(request.url)
        interceptedWebRequest?.let {
            if (request.url.toString().endsWith("js", true)) {
                it.mimeType = "text/javascript"
            }
        }
        return interceptedWebRequest
    }
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*ide 5

我只是以更容易阅读的方式重述之前的答案(并且使用 Java 而不是 Kotlin)

  1. 不确定这是否重要,但最佳实践是通过添加来使用 html 5<!DOCTYPE html>

  2. import androidx.webkit.WebViewAssetLoader;正如另一个问题中所述

  3. 强制使用正确的 MIME 类型,例如

        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
                WebResourceResponse intercepted = assetLoader.shouldInterceptRequest(request.getUrl());
                if (request.getUrl().toString().endsWith("js")) {
                        if (intercepted != null) {
                            intercepted.setMimeType("text/javascript");
                        }
                }
                return intercepted;
            }
        });
Run Code Online (Sandbox Code Playgroud)
  1. 使用类似的内容加载 HTML
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        mWebView.loadUrl("https://appassets.androidplatform.net/assets/AndroidWebView.html");
Run Code Online (Sandbox Code Playgroud)

请注意 HTTPS(而非文件)协议,并且缺少AllowFileAccessFromFileURLs