首页 文章

在WebView中注入Javascript桥

提问于
浏览
8

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

这就是我在做什么..

  • 使用应用程序上下文以编程方式创建WebView,因此不必在UI中显示 .

  • 加载网页

  • 附加JS接口

  • 注入一些Javascript以与主机应用程序进行交互

这是一些代码......

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();
        }
    }

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

我正在努力做甚么可能吗?如果是这样,我做错了什么?如果没有,为什么不呢?

EDIT

将视图保留在UI中进行测试,显然第二次调用loadUrl不起作用 . 无论我尝试注入什么Javascript,它都不起作用 .

EDIT 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);
    }

EDIT 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);

        }}



}

Edit 4

开始新的赏金并将奖励增加到100分 . 奈纳尔获得了最有益的最后奖励,而不是解决问题 .

5 回答

  • 2

    这是一个清理版本,最大限度地减少了不需要的代码 . 这适用于API级别18和23仿真器(以及我的6.0.1手机) . WebView永远不会添加到视图层次结构中 . 吐司显示从网站上拉出的HTML . 使用Java 8针对API 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>
    
  • 2

    请尝试这个,它调用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布局中定义 .

  • 0

    突然出现在我身上的一些事情 .

    • 在加载任何URL之前,应附加JavaScript接口 .

    • 可能在加载原始URL之后分配第二个loadURL window.onload . 调用 setWebViewClient() 并从 onPageFinished 方法中调用 Droid.showToast('testing!'); 会更有意义 .

    • @JavascriptInterface 不在主UI线程上运行,这将阻止您的toast运行 .

    • 第二个编辑的 innerHTML 代码无法正常工作的问题与第2点有关 . 您在同步单个块中进行调用,而应该在页面dom加载后进行调用AKA onPageFinished()

  • 4

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

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

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

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

  • 1

    如何在 WebChromeClient 中使用 onProgressChanged()

    我已经将 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

相关问题