在WebView中注入Javascript桥

时间:2016-08-05 19:13:06

标签: javascript java android webview javascript-injection

我想从Android的网页中提取一些内容。我知道有解析HTML的库,但我想也许我可以作弊。

这就是我正在做的事情。

  1. 使用应用程序上下文以编程方式创建WebView,因此不必在UI中显示。
  2. 加载网页
  3. 附加JS接口
  4. 注入一些Javascript以与主机应用程序进行交互
  5. 这里有一些代码......

        public void getLatestVersion(){
            Log.e("Testing", "getLatestVersion called...");
            WebView webview = new WebView(context.getApplicationContext());
            webview.loadUrl("https://example.com");
            webview.addJavascriptInterface(new jsInterface(), "Droid");
            webview.loadUrl("javascript: window.onload=function(){ Droid.showToast('testing!'); }");
        }
    
        class jsInterface{
            @JavascriptInterface
            public void showToast(String message){
                Log.e("Testing", message);
                Toast.makeText(context, message, Toast.LENGTH_LONG).show();
            }
        }
    

    由于在UI中看不到WebView,因此很难分辨出哪个部分正在破坏。我所知道的是调用了第一个被调用的Log,但JavascriptInterface中的Log和Toast从未显示过。

    我尝试做的甚至可能吗?如果是这样,我做错了什么?如果没有,为什么不呢?

    修改

    将视图放在用于测试的UI中,显然第二次调用loadUrl不起作用。无论我试图注入什么Javascript,它都无法正常工作。

    编辑2

    我对忘记启用Javascript感到愚蠢,但它仍无法正常工作..我已添加以下内容..

        WebSettings webSettings = webview.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webview.loadUrl("javascript: alert('farts0');");
    
        webview.loadUrl("https://example.com");
        setContentView(webview);
    
        String js = "document.body.innerHTML = '<p>test<p>';";
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            webview.evaluateJavascript(js, null);
        }else{
            webview.loadUrl("javascript: "+js);
        }
    

    编辑3

    感谢大家的建议,你们一直很有帮助,但到目前为止它还没有工作,除非有人在下一个小时提供工作代码,否则Nainal将得到一半的赏金。如果是这样的话,我不确定我是否会被允许再给它一个赏金,因为问题仍未得到解决。

    在考虑了此页面上的建议并尝试了一些我不太了解的手册中的设置之后,到目前为止我的完整代码。

    import android.graphics.Bitmap;
    import android.os.Bundle;
    import android.os.Handler;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.webkit.JavascriptInterface;
    import android.webkit.WebChromeClient;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        WebView webView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            webView = new WebView(getApplicationContext());
    
    
            if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
                webView.getSettings().setAllowFileAccessFromFileURLs(true);
    
            if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
                webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
    
            webView.getSettings().setDomStorageEnabled(true);
            webView.getSettings().setJavaScriptEnabled(true);
            try {
                webView.setWebContentsDebuggingEnabled(true);
            }catch(Exception e){}
            webView.setWebChromeClient(new WebChromeClient());
            webView.setWebViewClient(new WebViewClient() {
                @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    webView.setVisibility(View.GONE);
    
                }
                @Override
                public void onPageFinished(final WebView view, String url) {
                    Log.e("checking", "MYmsg");
                    Log.e("content-url", webView.getSettings().getAllowContentAccess()?"y":"n");
                    webView.loadUrl("javascript: void window.CallToAnAndroidFunction.setVisible(document.getElementsByTagName('body')[0].innerHTML);");
    
    
    
                }
            });
            webView.setVisibility(View.INVISIBLE);
            webView.addJavascriptInterface(new myJavaScriptInterface(), "CallToAnAndroidFunction");
            webView.loadUrl("http://example.com");
        }
        public class myJavaScriptInterface {
            @JavascriptInterface
            public void setVisible(final String aThing) {
                Handler handler = new Handler();
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
    
                        MainActivity.this.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                webView.setVisibility(View.VISIBLE);
                                Toast.makeText(MainActivity.this, "Reached JS: "+aThing, Toast.LENGTH_LONG).show();
    
                            }
                        });
    
    
                    }
                };handler.postDelayed(runnable,2000);
    
            }}
    
    
    
    }
    

    编辑4

    开始新的赏金并将奖励增加到100分。 Nainal得到了最有帮助的最后一笔赏金,而不是解决问题。

5 个答案:

答案 0 :(得分:4)

请尝试这个,它正在调用javascript函数并显示toast消息。

public class Main3Activity extends AppCompatActivity {
     WebView webView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        webView = new WebView(getApplicationContext());
        webView.getSettings().setJavaScriptEnabled(true);

        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                webView.setVisibility(View.GONE);

            }
            @Override
            public void onPageFinished(final WebView view, String url) {
                Log.e("checking", "MYmsg");
                webView.loadUrl("javascript:(function() { " +
                        "document.body.innerHTML = '<p>test<p>';" + "})()");
                webView.loadUrl("javascript: window.CallToAnAndroidFunction.setVisible()");



            }
        });
        webView.setVisibility(View.INVISIBLE);
        webView.addJavascriptInterface(new myJavaScriptInterface(), "CallToAnAndroidFunction");
        webView.loadUrl("https://example.com");
    }
    public class myJavaScriptInterface {
        @JavascriptInterface
        public void setVisible() {

            Handler handler = new Handler();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {

                    Main3Activity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            webView.setVisibility(View.VISIBLE);
                            Log.e("Testing", "no");
                            Toast.makeText(Main3Activity.this, "Reached JS", Toast.LENGTH_LONG).show();

                        }
                    });


                }
            };handler.postDelayed(runnable,2000);

        }}
}

它不会在UI中显示webView,因为webview未在xml布局中定义。

答案 1 :(得分:2)

向我展示了一些事情。

  1. 在加载任何网址之前,应附加JavaScript界面​​。

  2. 第二个loadURL window.onload可能会在原始网址加载后分配。从setWebViewClient()方法调用Droid.showToast('testing!');并致电onPageFinished会更有意义。

  3. @JavascriptInterface未在主UI线程上运行,这将阻止您的祝酒词运行。

  4. 第二个编辑的innerHTML代码无效的问题与第2点有关。您正在同步单个区块中进行调用,而应该是在页面dom加载了AKA之后{ {1}}

答案 2 :(得分:2)

webview.addJavascriptInterface(new jsInterface(), "Droid");必须在webview.loadUrl("https://example.com");

之前到来

然后使用Webview Listener。 onFinish()方法..然后在onFinish方法中注入webview.loadUrl("javascript: window.onload=function(){ Droid.showToast('testing!'); }");

我已经做了大量的webview注入修改网络...我认为它应该工作..

EDIT
在加载webview时使用chrome://inspect/#devices检查您的应用

答案 3 :(得分:1)

这是一个清理版本,最大限度地减少了不需要的代码。这适用于API级别18和23仿真器(以及我的6.0.1手机)。 WebView永远不会添加到视图层次结构中。吐司显示从网站上拉出的HTML。使用Java 8针对A​​PI 25进行编译。

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = new WebView(getApplicationContext());

        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebChromeClient(new WebChromeClient());

        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(final WebView view, String url) {
                webView.loadUrl("javascript: void AndroidHook.showToast(document.getElementsByTagName('body')[0].innerHTML);");
            }
        });

        webView.addJavascriptInterface(new JSInterface(), "AndroidHook");
        webView.loadUrl("http://example.com");
    }

    public class JSInterface {
        @JavascriptInterface
        public void showToast(final String html) {

            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, "Reached JS: " + html, Toast.LENGTH_LONG).show();
                }
            });
        }
    }
}

这是布局。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    tools:context="com.foo.jsinjectiontest.MainActivity">

</RelativeLayout>

最后是清单。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.foo.jsinjectiontest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.INTERNET"/>

</manifest>

答案 4 :(得分:0)

如何在onProgressChanged()中使用WebChromeClient

我已将某些代码从Edit 3更改为喜欢此内容,

webView.setWebChromeClient(new WebChromeClient(){
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
            if(newProgress == 100){
                webView.loadUrl("javascript: void window.CallToAnAndroidFunction.setVisible(document.getElementsByTagName('body')[0].innerHTML);");
            }
        }
    });

更改是您在progress==100而不是onPageFinished()

时调用javascript