Расслабляющая проверка типов MIME в Android WebView? Или принудительный тип модуля для обычного javascript? - PullRequest
2 голосов
/ 08 марта 2020

Я занимаюсь разработкой и приложением на Android, в котором есть фрагмент, написанный на javascript и python с использованием Transcrypt (это почти то же самое, что сказать, что я разрабатываю эту часть прямо в javascript, но я не имею полного контроля над тем, как все сделано). Android отображает этот раздел в Activity с WebView . Соответствующий код java для его запуска просто

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

, а соответствующая часть AndroidWebView.html аналогична Демонстрация стенограммы для iOS

        <script type="module">
            import * as my_app from "./target/my_app.js"; window.my_app = my_app;
        </script>

Приложение прекрасно работает на эмуляторе, но на реальных устройствах 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.

Если принудительно вызвать тип MIME, изменив HTML to

        <script type="text/javascript">
            import * as my_app from "./target/my_app.js"; window.my_app = my_app;
        </script>

, который, кажется, работает для других частей моей страницы, которые являются простыми javascript (не модулями), он явно не работает с Uncaught SyntaxError: Cannot use import statement outside a module.

Is есть ли способ заставить последний HTML быть модулем, или первый HTML, чтобы не проверять типы MIME так сильно?

Просмотр параметров для WebView Я не мог видеть ничего, что кажется актуальным. Оглядываясь вокруг, похоже, эта проблема вызвана именно этой ошибкой .

С другой стороны, мне кажется, что проблема в синтаксисе тега HTML script, принимающего тип: "text/javascript" или "module", но не оба одновременно (Я пытался и, кажется, использовать только первое), тогда как семантически есть причины, чтобы иметь оба. Есть ли обходной путь, или даже взломать иметь оба? Я знаю один хак, который будет работать для загрузки my_app.js, но он не сможет дополнительно загрузить другие модули (что делает my_app.js). Так что это не сработает, если не будет транспилятора или чего-то, что может автоматически объединить все мои модули в один. Кстати, эти модули генерируются из python из Transcrypt, поэтому это должен быть автоматический, а не ручной процесс.

PS: я не HTML или javascript разработчик, это мои первые шаги в это царство, поэтому, пожалуйста, будьте добры против моих предположений

PPS: Я понимаю причину не делать ничего этого на компьютере, а скорее запустить сервер. И это то, что я делаю для своей среды разработки. Но для одного действия в приложении Android HTTP-сервер кажется излишним и большой головной болью (отслеживание портов, потенциально большее количество сбоев, потенциально видимые в браузере или в других приложениях, дополнительные разрешения, дополнительные ресурсы и использование батареи, и, вероятно, больше неприятностей, о которых я не задумывался).

Ответы [ 2 ]

2 голосов
/ 13 марта 2020

Некоторые вещи, которые вы можете попробовать.

1. Убедитесь, что это html 5, добавив <!DOCTYPE html> к вашему индексу. html

2. Вместо загрузки файла непосредственно из системы с помощью file: // ... вы можете использовать WebViewAssetLoader, который вернет mimetype https://developer.android.com/reference/kotlin/androidx/webkit/WebViewAssetLoader

3. Если это не работает внутри webViewClient, вы можете перехватить запрос и вручную добавить текст / 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
    }
}
1 голос
/ 17 марта 2020

Я просто повторяю предыдущий ответ в более понятном виде (и с Java вместо Kotlin)

  1. Не уверен, что это имеет значение, но лучше всего используйте html 5, добавив <!DOCTYPE html>

  2. import androidx.webkit.WebViewAssetLoader;, как описано в этот другой вопрос

  3. force правильный тип 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...