1. ホーム
  2. アンドロイド

Android Webview Jsのインタラクションで遭遇した落とし穴!

2022-03-15 07:40:06

最近、webview jsのインタラクションの問題を研究して、様々なポットホールに遭遇しました。他の人が同じ落とし穴に遭遇して挫折しないように、私が遭遇した落とし穴を説明しようと思います。

1. 要件 ログイン画面でのユーザー名、パスワードの自動入力など、htmlでの制御内容の値を変更する。

初期の解決策:設定webviewClientを介して、ページがロードされた後に呼び出されるre-onpagefinished()メソッドは、jsインジェクションもjavascriptスクリプトのためのサポートを設定する必要があります webView.getSettings().setJavaScriptEnabled(true).webviewClient を設定します。

問題:ページ更新後、まず通常のログインページがロードされ、最後に空白のページにジャンプして、修正後のコンテンツのみが表示される。他のレイアウトでは、コンテンツが消えてしまう。

結果 要件を満たしていない。

改善すること htmllのコードを呼び出す場合、メソッドを記述する必要があり、そのメソッドを再度呼び出す必要がある。例:webviewClientの設定でonpagefinished()メソッドを再呼び出し、Html側でコントロールの値を変更するために以下のコードを追加します。

# coding=utf-8
from selenium import webdriver

driver = webdriver.Firefox()
driver.get("https://www.baidu.com")

driver.find_element_by_id("kw").send_keys("selenium2")
driver.find_element_by_id("su").click()
driver.quit()

ランニングの効果



2. 要件 htmlの傍受によるデータ収集。

1). jsインターフェース追加

  webView.addJavascriptInterface(new InJavaScriptLocalObj(), "java_obj");



注:最初のパラメータはjavaのクラスで、jsのインタラクションに使われます java_objはjsのインタラクションに使われるエイリアスで、jsのインタラクションに使われます。

2). webViewclientのメソッドをオーバーライドします。

// Used to handle certificate handling for https requests, no default handler.cancel() is set. 


@Override 


public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 


    // TODO Auto-generated method stub 


    // handler.cancel();// Android's default handler super method contains this method causing some phones to not be able to access the page 


    handler.proceed();// Accept all site credentials 


    // handleMessage(Message msg);// do other processing 


} 


@Override 


// Callback when the page starts loading 


 public void onPageStarted(WebView view, String url, Bitmap favicon) { 


      super.onPageStarted(view, url, favicon); 


       } 


 // Intercept url jumps, add a link click to jump or action inside 


 @Override 


   public boolean shouldOverrideUrlLoading(WebView view, String url) { 


     view.loadUrl(url);//load with webveiw 


     return true;//return true means click on the page content to jump, otherwise click on the page click event is not responsive 


} 


  @Override 


   public void onPageFinished(WebView view, String url) { 


                new Handler().postDelayed(new Runnable() {//Delayed processing  


                                             @Override 


                                             public void run() { 


                                                 webView.loadUrl("javascript:function setJsAcion(){document.getElementById('u').value='13800138000'; //Inject js code 


document.getElementById('p').value='13800138000'}");//Get the control and assign the value 


                                                 webView.loadUrl("javascript:setJsAcion()");//injected js function or method called again Important: direct html js assignment has problems 


                                             } 


                                         }, 500); 


                                         // Get the page content and pass it back through the showSource method 


                                         view.loadUrl("javascript:window.java_obj.showSource(" 


                                                 + "document.getElementsByTagName('html')[0].innerHTML);"); 






                                         // Get the parsed <meta name="share-description" content="Get the value"> and pass it back through the showDescription method 


                                         view.loadUrl("javascript:window.java_obj.showDescription(" 



                                                 + "document.querySelector('meta[name=\"share-description\"]').getAttribute('content')" 


                                                 + ");"); 


  // Get the parsed <meta name="iframe" body="Get the value"> and pass it back via the showJs() method Note: You can add a delay as above, because there are times when the onpagefinished() method is called before the page has finished loading 


                                         view.loadUrl("javascript:window.java_obj.showJs(document.getElementById('MainContent')" + //there may be a delay in loading the data in the iframe frame, it is recommended to add a delay 


                                           ".contentWindow.document.getElementsByTagName('body')[0].innerHTML);"); 


super.onPageFinished(view, url); 


                                     } 


//js interaction interface class for intercepting webview content 


  public final class InJavaScriptLocalObj { 


        @JavascriptInterface 


        public void showSource(final String html) { 


            Log.e(TAG, "htmlshowsource: " + html); 


            System.out.println("====>htmlshowsource===" + html); 


        } 






        @JavascriptInterface 


        public void showDescription(String str) { 


            System.out.println("====>htmlshowdescription==" + str); 


            Log.e(TAG, "htmlshowdescription: " + str); 


        } 






        @JavascriptInterface 


        public void showJs(String str) { 


            Log.e(TAG, "htmlshowjs: " + str); 


            System.out.println("====>htmlshowjs==" + str); 


        } 


        public void Tz(String str){ 


            Log.e(TAG, "htmlshowTz"+"enter tz" +str); 


            webView.loadUrl("javascript:document.getElementById('CreditCardNo').value='9999'"); 


        } 


    } 
// Please turn on network connection permissions for experiments

デモの全コードを添付します。

public class MainActivity extends AppCompatActivity { 


    private static final String TAG = "msg";
    private static String BaseUrl = "https://ui.ptlogin2.qq.com/cgi-bin/login?style=9&appid=522005705&daid=4&s_url=https% 3A%2F%2Fw.mail.qq.com%2Fcgi-bin%2Flogin%3Fvt%3Dpassport%26vm%3Dwsk%26delegate_url%3D%26f%3Dxhtml%26target%3D&hln_css=http%3A%3A 2F%2Fmail.qq.com%2Fzh_CN%2Fhtmledition%2Fimages%2Flogo%2Fqqmail%2Fqqmail_logo_default_200h.png&low_login=1&hln_autologin=% E8%AE%B0%E4%BD%8F%E7%99%BB%E5%BD%95%E7%8A%B6%E6%80%81&pt_no_onekey=1";
    private static String BaseUrl1 = "https://ui.ptlogin2.qq.com/cgi-bin/login?style=9&appid=522005705&daid=4&s_url=https% 3A%2F%2Fw.mail.qq.com%2Fcgi-bin%2Flogin%3Fvt%3Dpassport%26vm%3Dwsk%26delegate_url%3D%26f%3Dxhtml%26target%3D&hln_css=http%3A%3A 2F%2Fmail.qq.com%2Fzh_CN%2Fhtmledition%2Fimages%2Flogo%2Fqqmail%2Fqqmail_logo_default_200h.png&low_login=1&hln_autologin=% E8%AE%B0%E4%BD%8F%E7%99%BB%E5%BD%95%E7%8A%B6%E6%80%81&pt_no_onekey=1";
    private WebView webView; 






    @Override 


    protected void onCreate(Bundle savedInstanceState) { 


        super.onCreate(savedInstanceState); 


        setContentView(R.layout.activity_main); 


        webView = findViewById(R.id.webView); 


        initWebView(); 


        webView.loadUrl(BaseUrl); 


    } 











    private void initWebView() { 


        // Set the WebView properties to be able to execute Javascript scripts 


// webView.getSettings().setJavaScriptEnabled(true); 


// webView.setWebChromeClient(new WebChromeClient()); 


         wvAboutUs.setLayerType(View.LAYER_TYPE_HARDWARE, null); 


         wvAboutUs.getSettings().setLoadWithOverviewMode(true); 


// webView.getSettings().setBuiltInZoomControls(false); 


// webView.getSettings().setUseWideViewPort(true); 


// webView.getSettings().setLoadWithOverviewMode(true); 


// webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); 


// webView.setBackgroundColor(0); 


        // Turn on JavaScript support 


        webView.getSettings().setJavaScriptEnabled(true); 


// webView.loadUrl("https://pbsz.ebank.cmbchina.com/CmbBank_GenShell/UI/GenShellPC/Login/Login.aspx"); 






        webView.addJavascriptInterface(new InJavaScriptLocalObj(), "java_obj"); 






        // Set whether the WebView supports scaling using on-screen controls or gestures, default is true, scaling is supported 


        webView.getSettings().setSupportZoom(true); 






        webView.setWebChromeClient(new WebChromeClient()); 






        // Set whether the WebView uses its built-in zoom mechanism, which is used by the collection of screen zoom controls, the default is false and does not use the built-in zoom mechanism. 


        webView.getSettings().setBuiltInZoomControls(true); 






        // Set whether to enable DOM storage API permission, default false, not enabled, set to true, WebView can use DOM storage API 


        webView.getSettings().setDomStorageEnabled(true); 






        // Touch focus works. If not set, the soft keyboard will not pop up and will not respond to some other events when the web text input box is clicked. 


        webView.requestFocus(); 






        // Set this property to scale to any scale and set the recommended window for the webview 


        webView.getSettings().setUseWideViewPort(true); 






        // Set the mode of the page loaded by the webview, scaling to the size of the screen 


        webView.getSettings().setLoadWithOverviewMode(true); 






        webView.setWebViewClient(new WebViewClient() { 


                                     @Override 


                                     public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 


                                         // TODO Auto-generated method stub 


                                         // handler.cancel();// Android's default handler super method contains this method causing some phones to not be able to access the page 


                                         handler.proceed();// Accept all site credentials 


                                         // handleMessage(Message msg);// do other processing 


                                     } 






                                     @Override 


                                     public void onPageStarted(WebView view, String url, Bitmap favicon) { 


                                         // Callback when the page starts to load 


// view.loadUrl("javascript:document.getElementById('CreditCardNo').value='2222222';"); 


// view.loadUrl("javascript:window.java_obj.Tz()"); 


                                         super.onPageStarted(view, url, favicon); 


                                     } 


                                     @Override 


                                     public boolean shouldOverrideUrlLoading(WebView view, String url) { 


                                         // Intercept url jumps, add a click on the link to jump or action inside 



                                          view.loadUrl(url); 


                                          return true; 


// if (url.startsWith("iframe")) { 


                                            view.loadUrl("javascript:window.java_obj.showJs(document.getElementById('MainContent')" + 


                                                    ".contentWindow.document.getElementsByTagName('body')[0].innerHTML);"); 


// return false; 


// } else { 


// return super.shouldOverrideUrlLoading(view, url); 


// } 


                                     } 






                                     @Override 


                                     public void onPageFinished(WebView view, String url) { 










                                        //add this code to debug H5 code in Google Chrome requires a wall 


// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 


// webView.setWebContentsDebuggingEnabled(true); 


// } 


                                         // Callback (function(){**here is the JS code that needs to be executed**)() at the end of loading the page) 


// view.loadUrl("javascript:(function(){document.getElementById('CreditCardNo').value='6202222';})()"); 


// Log.e(TAG, "onPageFinished: " + url); 


// view.loadUrl("javascript:document.getElementById('CreditCardNo').value='32343';"); 


// view.loadUrl("javascript:document.getElementById('u').value='323263262';"); 


// view.reload(); 


// webView.loadUrl("javascript:document.getElementById('u').value='6202222';"); 


// new Handler().postDelayed(new Runnable() { 


// 


// @Override 


// public void run() { 


                                                webView.loadUrl("javascript:function setJsAcion(){var privateForm=document.getElementById(\"privateForm\").value=\& quot;ejia\"}"); 


                                                webView.loadUrl("javascript:setJsAcion()"); 


// webView.loadUrl("javascript:setJs(){var input=document.getElementById('u').value='6202222'}"); 


// }}, 500); 






                                         new Handler().postDelayed(new Runnable() { 






                                             @Override 


                                             public void run() { 


                                                 webView.loadUrl("javascript:function setJsAcion(){document.getElementById('u').value='13800138000'; document.getElementById('p' ).value='13800138000'}"); 


                                                 webView.loadUrl("javascript:setJsAcion()"); 


                                             } 



                                         }, 500); 


                                         // Get the page content 


                                         view.loadUrl("javascript:window.java_obj.showSource(" 


                                                 + "document.getElementsByTagName('html')[0].innerHTML);"); 






                                         // Get parsed <meta name="share-description" content="Get the value"> 


                                         view.loadUrl("javascript:window.java_obj.showDescription(" 


                                                 + "document.querySelector('meta[name=\"share-description\"]').getAttribute('content')" 


                                                 + ");"); 


// if (url.contains("CreditCardNo")) { 


// view.loadUrl("javascript:window.java_obj.Tz()"); 


// 


// } 






                                         // Get to parse <meta name="iframe" body="Get to value"> 


                                         view.loadUrl("javascript:window.java_obj.showJs(document.getElementById('MainContent')" + 


                                                 ".contentWindow.document.getElementsByTagName('body')[0].innerHTML);"); 






                                         super.onPageFinished(view, url); 


                                     } 










                                     @Override 


                                     public void onReceivedError(WebView view, int errorCode, 


                                                                 String description, String failingUrl) { 


                                         // Callback on load error, where you can do error handling, such as requesting another load, or prompting a 404 error page 


                                         super.onReceivedError(view, errorCode, description, failingUrl); 


                                     } 






                                     @Override 


                                     public WebResourceResponse shouldInterceptRequest(WebView view, 


                                                                                       WebResourceRequest request) { 


                                         // This function is called back each time a resource is requested 


                                         return super.shouldInterceptRequest(view, request); 


                                     } 


                                 } 


        ); 


    } 






    public final class InJavaScriptLocalObj { 


        @JavascriptInterface 


        public void showSource(final String html) { 


            Log.e(TAG, "htmlshowsource: " + html); 


            System.out.println("====>htmlshowsource===" + html); 


        } 






        @JavascriptInterface 


        public void showDescription(String str) { 


            System.out.println("====>htmlshowdescription==" + str); 


            Log.e(TAG, "htmlshowdescription: " + str); 


        } 






        @JavascriptInterface 



        public void showJs(String str) { 


            Log.e(TAG, "htmlshowjs: " + str); 


            System.out.println("====>htmlshowjs==" + str); 


        } 


        public void Tz(String str){ 


            Log.e(TAG, "htmlshowTz"+"enter tz" +str); 


            webView.loadUrl("javascript:document.getElementById('CreditCardNo').value='9999'"); 


        } 


    }

インターセプトのスクリーンショット:jsからandroidへの呼び出し