最近研究了一下webview的js交互问题,遇到了各种坑。现在就遇到的坑进行讲解一下,避免其他盆友遇到同样的坑不知所挫。
1.需求:修改html中控件内容的值,如登录界面的用户名与密码自动输入问题。
初始解决方法:通过webview设置webviewClient,并重新onpagefinished()方法,该方法在页面加载完成后会调用,进行js注入还必须设置支持javascript脚本webView.getSettings().setJavaScriptEnabled(true);
出现的问题:页面刷新后,先加载正常登录页面,最后跳到修改了后只显示修改内容的空白页;其他布局,内容消失。
结果:未达到需求。
改进方法:在调用htmll的代码的时候,需要写个方法,并且需要再次调用该方法。例:在webviewClient设置中重新onpagefinished()方法并添加如下代码更改Html端的控件值。
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);
运行效果:
2.需求:通过对html的拦截,实现数据收集。
1).添加js接口
webView.addJavascriptInterface(new InJavaScriptLocalObj(), "java_obj");
注:第一个参数是java类,用于js交互的类 java_obj是用于js交互的别名,在js中交互用到。
2).重写webViewclient中的方法。
//用于处理https请求用到的证书处理,不设置默认handler.cancel()。
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// TODO Auto-generated method stub
// handler.cancel();// Android默认的处理方式 super方法包含该方法导致部分手机无法访问页面
handler.proceed();// 接受所有网站的证书
// handleMessage(Message msg);// 进行其他处理
}
@Override
// 在开始加载网页时会回调
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
// 拦截 url 跳转,在里边添加点击链接跳转或者操作
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);//用webveiw加载
return true;//返回true表示点击页面内容可跳转,否则点击页面点击事件无反应
}
@Override
public void onPageFinished(WebView view, String url) {
new Handler().postDelayed(new Runnable() {//进行延时处理
@Override
public void run() {
webView.loadUrl("javascript:function setJsAcion(){document.getElementById('u').value='13800138000'; //注入js代码
document.getElementById('p').value='13800138000'}");//获取控件并赋值
webView.loadUrl("javascript:setJsAcion()");//注入的js函数或方法再次调用 重要:直接html js赋值有问题
}
}, 500);
// 获取页面内容并通过showSource方法回传
view.loadUrl("javascript:window.java_obj.showSource("
+ "document.getElementsByTagName('html')[0].innerHTML);");
// 获取解析
并通过showDescription方法回传
view.loadUrl("javascript:window.java_obj.showDescription("
+ "document.querySelector('meta[name=\"share-description\"]').getAttribute('content')"
+ ");");
// 获取解析
并通过showJs()方法回传 注:可以加个延时同上,因为有些时候存在页面未加载完就调用了该onpagefinished()方法
view.loadUrl("javascript:window.java_obj.showJs(document.getElementById('MainContent')" + //可能出现加载的iframe框架内的数据有延时情况,建议加延迟
".contentWindow.document.getElementsByTagName('body')[0].innerHTML);");
super.onPageFinished(view, url);
}
//js交互接口类 用于拦截webview内容
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"+"进入tz" +str);
webView.loadUrl("javascript:document.getElementById('CreditCardNo').value='9999'");
}
}
//实验请打开网络连接权限

全部demo代码附上
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%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%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() {
// 设置WebView属性,能够执行Javascript脚本
// 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);
// 开启JavaScript支持
webView.getSettings().setJavaScriptEnabled(true);
// webView.loadUrl("https://pbsz.ebank.cmbchina.com/CmbBank_GenShell/UI/GenShellPC/Login/Login.aspx");
webView.addJavascriptInterface(new InJavaScriptLocalObj(), "java_obj");
// 设置WebView是否支持使用屏幕控件或手势进行缩放,默认是true,支持缩放
webView.getSettings().setSupportZoom(true);
webView.setWebChromeClient(new WebChromeClient());
// 设置WebView是否使用其内置的变焦机制,该机制集合屏幕缩放控件使用,默认是false,不使用内置变焦机制。
webView.getSettings().setBuiltInZoomControls(true);
// 设置是否开启DOM存储API权限,默认false,未开启,设置为true,WebView能够使用DOM storage API
webView.getSettings().setDomStorageEnabled(true);
// 触摸焦点起作用.如果不设置,则在点击网页文本输入框时,不能弹出软键盘及不响应其他的一些事件。
webView.requestFocus();
// 设置此属性,可任意比例缩放,设置webview推荐使用的窗口
webView.getSettings().setUseWideViewPort(true);
// 设置webview加载的页面的模式,缩放至屏幕的大小
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默认的处理方式 super方法包含该方法导致部分手机无法访问页面
handler.proceed();// 接受所有网站的证书
// handleMessage(Message msg);// 进行其他处理
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// 在开始加载网页时会回调
// 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) {
// 拦截 url 跳转,在里边添加点击链接跳转或者操作
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) {
//加这句代码可以在谷歌浏览器调试H5代码 需要
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// webView.setWebContentsDebuggingEnabled(true);
// }
// 在结束加载网页时会回调(function(){**这里是需要执行JS代码**})()
// 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=\"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);
// 获取页面内容
view.loadUrl("javascript:window.java_obj.showSource("
+ "document.getElementsByTagName('html')[0].innerHTML);");
// 获取解析
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()");
//
// }
// 获取解析
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) {
// 加载错误的时候会回调,在其中可做错误处理,比如再请求加载一次,或者提示404的错误页面
super.onReceivedError(view, errorCode, description, failingUrl);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) {
// 在每一次请求资源时,都会通过这个函数来回调
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"+"进入tz" +str);
webView.loadUrl("javascript:document.getElementById('CreditCardNo').value='9999'");
}
}
拦截截图:js调用android的方法

最后感谢【武汉-5】cokus和鱼吃肉两位大神的技术支持。