編輯:關於Android編程
WebView可所謂是Android中最強大的控件之一,無所不能。
於是有這麼一個需求,用戶在app之中內嵌的WebView中輸入帳號密碼的時候,App需要捕獲已經輸入的帳號密碼。
當用戶輸入帳號密碼,一般情況下會進行頁面轉跳,在頁面轉跳之前執行js腳本,通過js腳本來獲取這個帳號密碼的value值。要先獲取各個元素的class值,需要解析整個html頁面,那麼我們可以重寫 onLoadResource 這個方法,代碼如下:
webview.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return false; } @Override public void onLoadResource(WebView view, String url) { getHtml(); Log.e("log-->", "onLoadResource-->>" + url); } @Override public void onPageFinished(WebView view, String url) { } });
上面這個方法在加載頁面資源時會調用,每一個資源(比如圖片)的加載都會調用一次。那麼我們可以在這個方法裡面執行注入的js腳本
先執行addJavascriptInterface方法,將一個java對象綁定到一個js對象中,代碼如下:
public class JavaScriptInterface { String mPasswrod; String mUsername; @JavascriptInterface public void getHTML(final String html) { if (!TextUtils.isEmpty(html)) { saveWebViewUserData.saveUserDataWebView(webview, html); } } @JavascriptInterface public void save_password(final String password) { if (!TextUtils.isEmpty(password)){ LogUtils.e("received from js. password = " + password); this.mPasswrod = password; checkData(mUsername, mPasswrod); } } @JavascriptInterface public void save_username(final String username) { if (!TextUtils.isEmpty(username)) { LogUtils.e("received from js. username = " + username); this.mUsername = username; checkData(mUsername, mPasswrod); } } } webview.addJavascriptInterface(new JavaScriptInterface(), "android"); private void getHtml() { webview.loadUrl("javascript:window.android.getHTML('<html>'+document.body.innerHTML+'</html>');"); }
那麼下面這句話執行完的結果將會返回到JavaScriptInterface中getHTML方法裡面。也就是說通過綁定,js代碼調用了java代碼,並將整個html作為返回值返回,執行的是saveWebViewUserData.saveUserDataWebView(webview, html);
得到了包含class的html之後,就需要依次分析了,通常來說,一般輸入帳號密碼的頁面都含有 type=”password” 字樣。先判斷這個html頁面是否含有這個字樣,如果有,那麼可能就是登錄頁面。
再判斷這個頁面的id,或者是classname是否包含password啦,pwd啦,或者什麼其他和密碼有關的了,這個元素肯定就是密碼框了,再過濾掉頁面中其他的button,hidden,submit,checkbox等等,剩下的那一個肯定就是用戶名了;過濾代碼如下:(這裡使用jsoup解析html獲取各個document,循環遍歷剔除不需要的元素)
public void saveUserDataWebView(WebView webView, String html) { Document document = Jsoup.parse(html); Elements elements = document.select("input"); boolean isContainsPassword = false; for (Element element : elements) { String type = element.attr("type"); if ("password".equals(type)) { isContainsPassword = true; break; } } if (!isContainsPassword) { return; } for (Element element : elements) { String className = element.className(); String type = element.attr("type"); webView.post(new Runnable() { @Override public void run() { LogUtils.e("this element id is = " + element.attr("id") + " type = " + type); String id = element.attr("id"); if (filterData(type, id)) { int handType = handleType(type); if (handType == NONE) { handType = handleId(id); if (handType == NONE) { handleClassName(className); } } switch (handType) { case PASSWORD: if (id==null){ }else { savePasswordById(id, webView); } break; case USERNAME: if (id==null){ }else { saveUsernameById(id, webView); } break; case NONE: break; } } } }); } } private int handleClassName(String className) { if (className == null) { return ERROR; } if (className.contains("password")) { return PASSWORD; } if (className.contains("captcha")) { return ERROR; } return USERNAME; } private boolean filterData(String type, String id) { if ("captcha".equals(type)) { return false; } else if ("login_vcode".equals(type)) { return false; } else if ("button".equals(type)) { return false; } else if ("hidden".equals(type)) { return false; } else if ("submit".equals(type)) { return false; } else if ("checkbox".equals(type)) { return false; } else if ("captcha".equals(id)) { return false; } else if ("inp_ChkCode".equals(id)) { return false; } else { return true; } } private int handleId(String id) { if (id == null) { return NONE; } if (id.contains("captcha")) { return ERROR; } if (id.contains("password")) { return PASSWORD; } if (id.contains("Phone")) { return USERNAME; } if (id.contains("username")) { return USERNAME; } if (id.contains("code")) { return ERROR; } return USERNAME; } private int handleType(String type) { if (type == null) { return NONE; } if (type.contains("tel")) { return ERROR; } if (type.contains("pwd")) { return PASSWORD; } if (type.contains("password")) { return PASSWORD; } return NONE; }
將他們倆的class id記錄下來,再次通過js代碼獲取到頁面的value值,調用java代碼保存下來。代碼如下:
private void saveUsernameById(String id, WebView webView) { webView.loadUrl("javascript:window.android.save_username(document.getElementById('" + id + "').value)"); } private void savePasswordById(String id, WebView webView) { webView.loadUrl("javascript:window.android.save_password(document.getElementById('" + id + "').value)"); }
經過上面簡單的處理,已經大致可以獲取到用戶輸入的帳號密碼了,經過測試,簡單的頁面中的帳號密碼是可以獲取到的,其他復雜的(如密碼在轉跳時清空了,又傳值到其他地方進行運算的)需要再根據不同的方案來對付了。
轉跳前先獲取整個頁面的html,用jsoup獲取頁面的所有class name,遍歷各個節點,剔除無用內容(驗證碼按鈕等),判斷密碼框在哪,剩下的可能就是帳號了,執行js代碼獲取value值。
以上就是本文的全部內容,希望大家喜歡。
在Android Studio上將項目導入Github上: Enable Version Control Integration... 2.選擇Git,點擊
首先我們要知道一共有哪幾種動畫,這個面試有可能被問哦^_^。 變換動畫(透明度、縮放、平移、旋轉)、逐幀動畫、布局動畫和屬性動畫一、變換動畫我們可以通過XML文件設置動畫
先看 SwipeLayout的效果圖圖太多了,我這只上傳一張,想看 listview和GridView效果的,和想看源碼的 —> GitHub怎麼實現後
之前的幾篇博客,我測試了View事件分發機制中的一些知識點,我們理解事件分發機制的目的就是為了能夠更好了知道View中事件的傳遞過程進而能夠對於滑動沖突有針對性的解決措施