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への呼び出し
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ハートビート・エフェクトのためのHTML+CSS
-
HTML ホテル フォームによるフィルタリング
-
HTML+cssのボックスモデル例(円、半円など)「border-radius」使いやすい
-
HTMLテーブルのテーブル分割とマージ(colspan, rowspan)
-
ランダム・ネームドロッパーを実装するためのhtmlサンプルコード
-
Html階層型ボックスシャドウ効果サンプルコード
-
QQの一時的なダイアログボックスをポップアップし、友人を追加せずにオンラインで話す効果を達成する方法
-
sublime / vscodeショートカットHTMLコード生成の実装
-
HTMLページを縮小した後にスクロールバーを表示するサンプルコード
-
html のリストボックス、テキストフィールド、ファイルフィールドのコード例