在 Android 的 WebView 中放松 MIME 类型检查?或者强制模块类型为常规 javascript?
Relaxing MIME type checking in Android's WebView? Or forcing module type for regular javascript?
我正在 Android 中开发和应用程序,其中有一段使用 javascript 和 python 使用 Transcrypt (it'd almost be the same as saying that I am developing that part straight in javascript, but I do not have full control on how things are made). Android displays that section in an Activity with a WebView 编写的。启动它的相关 java 代码只是
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);
mWebView.loadUrl("file:///android_asset/AndroidWebView.html");
AndroidWebView.html
的相关部分类似于Transcript's demo for iOS
<script type="module">
import * as my_app from "./target/my_app.js"; window.my_app = my_app;
</script>
该应用程序在模拟器上运行良好,但在真实设备上 WebView 拒绝加载 java 脚本并吐出以下错误:
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.
如果我通过将 HTML 更改为
来强制使用 MIME 类型
<script type="text/javascript">
import * as my_app from "./target/my_app.js"; window.my_app = my_app;
</script>
这似乎适用于我的页面的其他部分,这些部分是纯 java 脚本(不是模块),它显然因 Uncaught SyntaxError: Cannot use import statement outside a module
.
而失败
有没有办法强制后者 HTML 成为一个模块,或者前者 HTML 不那么强烈地检查 MIME 类型?
正在查看 options for WebView I could not see anything that seems relevant. Looking around, this issue seems to be caused exactly by this bug。
另一方面,在我看来,问题在于接受类型的 HTML script
标记的语法是 "text/javascript"
或 "module"
但不能同时使用(我试过,它似乎只使用第一个),而在语义上有理由同时使用两者。是否有解决方法,甚至是同时拥有两者的黑客?我知道一种 hack 可以用于加载 my_app.js
,但是那个将无法进一步加载其他模块(my_app.js
可以)。因此,除非有转译器或能够自动将我的所有模块合并为一个的东西,否则这将行不通。 FWIW,这些模块是从 Transcrypt python 生成的,因此它必须是一个自动化的过程,而不是手动过程。
PS:我不是 HTML 或 java 脚本开发人员,这些是我在这个领域的第一步,所以请不要怀疑我的猜测
PPS:我理解不在计算机上执行任何这些操作而是启动服务器的原因。这就是我为我的开发环境所做的。但是对于 Android 应用程序中的一个 Activity,HTTP 服务器似乎有点矫枉过正,令人头疼(跟踪端口、潜在的更多故障模式、可能在浏览器或其他应用程序中可见、额外的权限、额外的资源和电池使用,可能还有更多我没有想到的麻烦)。
您可以尝试一些事情。
1。
通过将 <!DOCTYPE html>
添加到 index.html
来确保它是 html 5
2。
您可以使用 WebViewAssetLoader 而不是使用 file://... 直接从系统加载文件,这将 return 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
}
}
我只是以一种更易于阅读的方式重申之前的答案(并且使用 Java 而不是 Kotlin)
不确定是否重要,但最好通过添加 <!DOCTYPE html>
使用 html 5
import androidx.webkit.WebViewAssetLoader;
如
所述
强制使用类似
的正确 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;
}
});
- 用
之类的东西加载HTML
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.loadUrl("https://appassets.androidplatform.net/assets/AndroidWebView.html");
注意 HTTPS(非文件)协议,并且缺少 AllowFileAccessFromFileURLs
我正在 Android 中开发和应用程序,其中有一段使用 javascript 和 python 使用 Transcrypt (it'd almost be the same as saying that I am developing that part straight in javascript, but I do not have full control on how things are made). Android displays that section in an Activity with a WebView 编写的。启动它的相关 java 代码只是
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);
mWebView.loadUrl("file:///android_asset/AndroidWebView.html");
AndroidWebView.html
的相关部分类似于Transcript's demo for iOS
<script type="module">
import * as my_app from "./target/my_app.js"; window.my_app = my_app;
</script>
该应用程序在模拟器上运行良好,但在真实设备上 WebView 拒绝加载 java 脚本并吐出以下错误:
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.
如果我通过将 HTML 更改为
来强制使用 MIME 类型 <script type="text/javascript">
import * as my_app from "./target/my_app.js"; window.my_app = my_app;
</script>
这似乎适用于我的页面的其他部分,这些部分是纯 java 脚本(不是模块),它显然因 Uncaught SyntaxError: Cannot use import statement outside a module
.
有没有办法强制后者 HTML 成为一个模块,或者前者 HTML 不那么强烈地检查 MIME 类型?
正在查看 options for WebView I could not see anything that seems relevant. Looking around, this issue seems to be caused exactly by this bug。
另一方面,在我看来,问题在于接受类型的 HTML script
标记的语法是 "text/javascript"
或 "module"
但不能同时使用(我试过,它似乎只使用第一个),而在语义上有理由同时使用两者。是否有解决方法,甚至是同时拥有两者的黑客?我知道一种 hack 可以用于加载 my_app.js
,但是那个将无法进一步加载其他模块(my_app.js
可以)。因此,除非有转译器或能够自动将我的所有模块合并为一个的东西,否则这将行不通。 FWIW,这些模块是从 Transcrypt python 生成的,因此它必须是一个自动化的过程,而不是手动过程。
PS:我不是 HTML 或 java 脚本开发人员,这些是我在这个领域的第一步,所以请不要怀疑我的猜测
PPS:我理解不在计算机上执行任何这些操作而是启动服务器的原因。这就是我为我的开发环境所做的。但是对于 Android 应用程序中的一个 Activity,HTTP 服务器似乎有点矫枉过正,令人头疼(跟踪端口、潜在的更多故障模式、可能在浏览器或其他应用程序中可见、额外的权限、额外的资源和电池使用,可能还有更多我没有想到的麻烦)。
您可以尝试一些事情。
1。
通过将 <!DOCTYPE html>
添加到 index.html
2。 您可以使用 WebViewAssetLoader 而不是使用 file://... 直接从系统加载文件,这将 return 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
}
}
我只是以一种更易于阅读的方式重申之前的答案(并且使用 Java 而不是 Kotlin)
不确定是否重要,但最好通过添加
<!DOCTYPE html>
使用 html 5
import androidx.webkit.WebViewAssetLoader;
如 所述
强制使用类似
的正确 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;
}
});
- 用 之类的东西加载HTML
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.loadUrl("https://appassets.androidplatform.net/assets/AndroidWebView.html");
注意 HTTPS(非文件)协议,并且缺少 AllowFileAccessFromFileURLs