无法从Javascript重新加载Android WebView

时间:2019-05-02 15:47:20

标签: javascript android webview android-webview

我是Android开发的新手,这种行为很奇怪,或者可能是错误的结果。

项目描述

我正在使用WebView创建一个应用程序,该应用程序加载了以前仅在浏览器中使用过的SPA:

  • 我已为WebView启用Javascript
  • 我知道要获取一些基本的JS函数(例如alert()),需要设置一个WebChromeClient。

我还添加了一个类,其中包含一些@JavascriptInterface方法来处理网页和Android应用之间的通信。

问题

网页使用Javascript调用location.reload(),但WebView会忽略它。

解决方案失败

我已经有了一个@JavascriptInterface的类,然后让我们从网页中调用Activity的方法来处理webview.reload()
简单的想法,但是行不通。

奇怪的是,执行暂停(无论是在JS中还是在Android中)都没有任何错误,但是主线程并未停止,因为该应用程序仍然可以正常工作并响应事件。

1 个答案:

答案 0 :(得分:0)

我认为这只是一种解决方法...但是可以。

在各种方法的完整执行之后,我使用了AsyncTask来延迟Activity中webview.reload()的调用。

似乎Android webview.reload()触发了某种异常,该异常在某个类内部的某个地方处理,此后什么也没有发生,只是下一行代码没有执行。 可能与他@JavascriptInterface有关,或者我只是用脚开枪射击,看不见。

我需要Android方面更资深的专家的建议:比这个AsyncTask解决方案还优雅得多?

测试项目

这是一个小型Android活动(Kotlin + XML布局)的代码,它将显示该问题。将它们粘贴到新的Android Studio项目中,按一些按钮,然后检查Logcat(过滤器“ PNK”)。

MainActivity.kt

package it.punkman.webviewreloadbug

import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.webkit.JavascriptInterface
import android.webkit.WebChromeClient
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    class JSInterface(val mainActivity: MainActivity){

        private inner class Reloader : AsyncTask<Int, Void, Int>() {
            override fun doInBackground(vararg params: Int?): Int {
                Thread.sleep(500)
                return 0
            }

            override fun onPostExecute(result: Int?) {
                super.onPostExecute(result)
                Log.d("PNK","Android - Reload Async Real execute!")
                mainActivity.refreshWebView(mainActivity.btnRefresh)
                Toast.makeText(mainActivity,"WebView refreshed! OK!",Toast.LENGTH_LONG).show(); //OK
            }
        }

        @JavascriptInterface
        fun reloadBug(){
            Log.d("PNK","Android - Reload Bug Start")
            mainActivity.refreshWebView(mainActivity.btnRefresh)
            Log.d("PNK","Android - Reload Bug End")
            Toast.makeText(mainActivity,"You cannot see this toast!",Toast.LENGTH_LONG).show(); //Unable to see
        }

        @JavascriptInterface
        fun reloadAsync(){
            Log.d("PNK","Android - Reload Async Start")
            Reloader().execute(0,null,0)
            Log.d("PNK","Android - Reload Async Stop")
        }
    }

    val HTML_SAMPLE_PAGE="""
       <!DOCTYPE html>
       <html>
         <head>
            <script>
                function refreshPage(){
                    alert("DOM - Refresh Start");
                    location.reload(); //Inside an Android WebView this isn't working!
                    alert("DOM - Refresh End\nNothing refreshed, reload ignored");
                }

                function refreshPageJSI_Bug(){
                    alert("JS Interface - Refresh Start");
                    JSI.reloadBug()
                    alert("JS Interface - Refresh End NEVER SHOWN!"); //NEVER SHOWN!
                }

                function refreshPageJSI_Async(){
                    alert("JS Interface - Refresh Start Async");
                    JSI.reloadAsync()
                    alert("JS Interface - Refresh End Async");
                }
            </script>
         </head>
         <body>
           <script>document.write(new Date())</script>
           <br/><br/>
           <button style="width:100%" onclick="refreshPage()">HTML - JS Refresh</button><br/><br/>
           <button style="width:100%" onclick="refreshPageJSI_Bug()">HTML - JavascriptInterface BUG?</button><br/><br/>
           <button style="width:100%" onclick="refreshPageJSI_Async()">HTML - JavascriptInterface with AsyncTask</button>
         </body>
       </html>
    """

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // For the purpose of this example
        // the page is just injected from a string
        // but the result is the same

        testWebView.settings.javaScriptEnabled=true
        testWebView.webChromeClient = WebChromeClient()
        testWebView.addJavascriptInterface( JSInterface(this), "JSI")
        testWebView.loadData(HTML_SAMPLE_PAGE,"text/html",null)
    }

    fun refreshWebView(v:View){
        Log.d("PNK","Android - Refresh Start")
        testWebView.reload()
        // OR again using loadUrl - testWebView.loadUrl(HTML_SAMPLE_PAGE)
        Log.d("PNK","Android - Refresh End")
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" tools:layout_editor_absoluteY="8dp"
            tools:layout_editor_absoluteX="8dp">
        <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="50dp">
            <Button
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:onClick="refreshWebView"
                    android:text="Android - Refresh"
                    android:id="@+id/btnRefresh"/>

        </LinearLayout>
        <WebView
                android:layout_width="match_parent"
                android:layout_height="match_parent" android:id="@+id/testWebView"/>
    </LinearLayout>
</android.support.constraint.ConstraintLayout>