无法从Javascript重新加载Android WebView [英] Unable to reload Android WebView from Javascript

查看:72
本文介绍了无法从Javascript重新加载Android WebView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm quite new to the Android Development and this behaviour is quite weird or could be a result of a bug.

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

I'm creating an App with a WebView that load a SPA that was previously used only in browsers:

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

我还添加了一个带有@JavascriptInterface方法的类,用于处理网页和Android应用之间的通信.

I've also added a class with some @JavascriptInterface methods to handle communications between the webpage and the Android app.

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

Webpage calls location.reload() in Javascript but this is ignored by the WebView.

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

I've already a class with @JavascriptInterface in place, then let's call an method of the Activity from the webpage to handle the webview.reload().
Simple idea but doesn't work.

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

The strange thing is that execution just halt (both in JS and in Android) without any sort of errors but the main thread isn't stopped because the app still works and respond to events.

推荐答案

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

I think is just a workaround...but works.

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

I've used an AsyncTask to delay the call of webview.reload() in the Activity after the complete executions of the various methods.

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

Seems that the Android webview.reload() triggers some sort of exception that is handled somewhere inside some class and nothing happens after, simply the next the line of code isn't executed. Probably is something connected to he @JavascriptInterface or I'm just shooting myself in the foot and I can't see it.

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

I need an advice from someone more expert in Android: there is something much more elegant than this AsyncTask solution?

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

Here is the code of a small Android Activity (Kotlin+XML Layout) that will show the problem. Paste them in an new Android Studio project, press some buttons and check Logcat (filter 'PNK').

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>

这篇关于无法从Javascript重新加载Android WebView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆