android-webview开发中的各种使用方法(持续更,尽量全)
最新坑A:(没看过的可以从下面开始处看起): 测试部门测出来一个坑,当多次点击退出后,会出现app崩溃现象,报如下错误:
java.lang.IllegalArgumentException: Receiver not registered: android
经过四处查资料,才知道这是android系统里的一个bug.这些咱都不管,只说解决办法,各种查找,找到如下办法,在webview所在Acitivity的onDestory()方法中加入如下方法。
@Override protected void onDestroy() { super.onDestroy(); infoWebView.setVisibility(View.GONE); }
解决原理好像是不让zoombutton什么的显示,反正我也不清楚就这样解决了。
开始:不知道你有没有注意,最近的app中越来越多的使用webview了,个人感觉,一方面是因为微信公众号开发增多的促进,让很多页面开发后用到微信上面后,还要吣在公司的app中使用,又加上html5的进一步火热,可以跨平台使用,一次开发,可以用在Ios,android客户端上,这样,极大的节省了公司的开发成本,缩小了开发周期,让公司的产品可以进快的投入市场中,在与同类产品竞争中拔得一个先机。同时,在一个页面中,想要做一个广告活动,也不必像原生控件写的app那样必须升级,让用户体验非常之不好,只要在页面中加上一个链接就可以了,就是这么简单,就是这么esay。至于目前在app内嵌html页面最大的掣肘,可能个人感觉还是中国移动,中国联通,与中国电信三家公司,试想,如果有一天,我们的移动网络可以普遍的像pc互联网一样高速,低费用,那么,我感觉那时就是html5的天下了。
所以,html5的学习,应该被广大安卓开发提上日程,试想,如果一个安卓开发人员,同时又精通html5,是不是可以给你所在的公司节省一名专门的开发人员,是不是要节省一大笔工资开销,那这节省下来的工资开销怎么着是不是也要分给你点。同时,在你找工作时,会html5至少可以为你的薪资在你期望薪资的基础上提高20个百
分点。
目前我也打算开始学习html5了,不过之前在做安卓开发中,也有内嵌了一些网页,用了webview,则在此先总结下,此控件的一些常用方法。费话不多说,开始。
1.webview控件的使用:在layout的布局文件中,如同常用的安卓原生控件一样的使用,如listview,textview,button等。
<WebView android:id="@+id/wv_page" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerHorizontal="true" />
2.在java代码中初始化:
WebView infoWebView= (WebView) findViewById(R.id.wv_page);
3.设置webview的屏幕适配:有自己的理解,也有参考:http://www.cnblogs.com/bluestorm/archive/2013/04/15/3021996.html
1 //a方法 2 WebSettings settings = webView.getSettings(); 3 settings.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); 4 //LayoutAlgorithm是一个枚举用来控制页面的布局,有三个类型: 5 //1.NARROW_COLUMNS:可能的话使所有列的宽度不超过屏幕宽度 6 //2.NORMAL:正常显示不做任何渲染 7 //3.SINGLE_COLUMN:把所有内容放大webview等宽的一列中 8 //用SINGLE_COLUMN类型可以设置页面居中显示,页面可以放大缩小,但这种方法不怎么 9 //好,有时候会让你的页面布局走样而且我测了一下,只能显示中间那一块,超出屏幕的部分 10 //都不能显示。 11 12 13 //b:加上这两句基本上就可以做到屏幕适配了 14 infoWebView.getSettings().setUseWideViewPort(true); 15 infoWebView.getSettings().setLoadWithOverviewMode(true); 16 17 //c:(主要用于平板,针对特定屏幕代码调整分辨率) 18 DisplayMetrics metrics = new DisplayMetrics(); 19 getWindowManager().getDefaultDisplay().getMetrics(metrics); 20 int mDensity = metrics.densityDpi; 21 22 23 if (mDensity == 120) { 24 settings.setDefaultZoom(ZoomDensity.CLOSE); 25 }else if (mDensity == 160) { 26 settings.setDefaultZoom(ZoomDensity.MEDIUM); 27 }else if (mDensity == 240) { 28 settings.setDefaultZoom(ZoomDensity.FAR); 29 }
4.设置html页面定位的支持
1 infoWebView.getSettings.setGeolocationEnabled(true); 2 //同时也要在清单文件里设置定位的权限支持 3 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 4 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
如今,页面中包含js的情况也很多,所以要添加对js功能的支持
1 infoWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); 2 infoWebView.getSettings().setBuiltInZoomControls(true);
5.当要对网页内的源码进行解析功能时,要加上:
1 infoWebView.getSettings().setDomStorageEnabled(true);
6.当页面有拨打电话号码功能时(电话号已经显示的那种),可以用如下代码判断
1 wv_page.setWebViewClient(new WebViewClient() { 2 3 @Override 4 public boolean shouldOverrideUrlLoading(WebView view, String url) { 5 if (url.startsWith("tel")) { 6 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 7 startActivity(intent); 8 } else if (url.startsWith("http:") || url.startsWith("https:")) { 9 view.loadUrl(url); 10 } 11 return true; 12 } 13 14 });
7.当你要设置html页面的返回键点击后返回上一层页面,而不是 退出当前activity,可以加上如下代码
1 @Override 2 public boolean onKeyDown(int keyCode, KeyEvent event) { 3 // 设置webview页面时设置后退时,回退到上一web页面。 4 if (keyCode == KeyEvent.KEYCODE_BACK && infoWebView.canGoBack()) { 5 infoWebView.goBack(); 6 if (View.VISIBLE == shareRel.getVisibility()) { 7 shareRel.setVisibility(View.GONE); 8 } 9 return true; 10 } 11 return super.onKeyDown(keyCode, event); 12 }
8.若要在当前activity的webview中加载url,而不是跳转到手机别的浏览器中,可以在代码中添加如下代码:
1 infoWebView.setWebViewClient(new WebViewClient() { 2 3 @Override 4 public boolean shouldOverrideUrlLoading(WebView view, String url) { 5 // TODO 设置不加载外面的浏览器 6 view.loadUrl(url); 7 return true; 8 }
}
9.webViewClient中有一些方法,可以用来对webview加载的状态等的一些监听,等功能,如可以用来判断一个页面加载前,后
1 infoWebView.setWebViewClient(new WebViewClient() { 2 3 @Override 4 public boolean shouldOverrideUrlLoading(WebView view, String url) { 5 // TODO 设置不加载外面的浏览器 6 view.loadUrl(url); 7 return true; 8 } 9 10 @Override 11 public void onPageStarted(WebView view, String url, Bitmap favicon) { 12 // TODO Auto-generated method stub 13 super.onPageStarted(view, url, favicon); 14 LogUtil.debug(activity.class, "get start url地址----------:" + infoWebView.getUrl()); 15 //这里可以用来判断页面加载前的url地址,等 ,也可以在这里来启动一个progressbar,用来显示正在加载。 16 } 17 18 @Override 19 public void onPageFinished(WebView view, String url) { 20 super.onPageFinished(view, url);
//这里是webview加载结束时调用的,可以在这里结束前面设置的一个progressbar.
//也可以做一些别的功能的处理,如得到源码中的一些数据,下面会详细说下。
21 } 22 }
从这里开始都是一些比较含坑的方法了,老纳也是静心苦经书,才有点体会。
10.对源码进行一些解析。首先,如果项目对安全性要求不高的话,可以用第三方的库,josup.但当页面中有一些sesson权限的操作时,这种方法就有点不知道还能不能用了。
josup的jar包,还是我的360网盘 JSOUP 访问密码 4e3d
josup的详细使用方法:啦啦啦
简单的说下,jsoup的解析可以实现两种,一种是对本地的html文件的解析。另一种是对url的解析,具体的方法上面都很清楚。不过,有时对非jsp页面的解析好像支持的不太好,本次开发中就遇到了这种情况,让我着实的无语了很长时间,才导致了下面的方法的查找。
11.通过webview本身的infoWebView.load()方法进行一些document解析方法,来进行解析。
example:a得到全部的html源码的方法:
1 //1先在class类中定义一个内部类(非内部类应该也可以,没有试) 2 public class InCalssForHtml{ 3 public void showHtmlStr(String html){ 4 //在这里打下log就行了。 5 } 6 7 } 8 //下面当js解析出来网页源码时,就会回调用此类中的方法,并将数据传入。
然后在
webRecruits.setWebViewClient(new WebViewClient(){ @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); //1,先创建上面定义方法的对象 InClassForHtml inForHtml = new InClassForHtml(); //添加js接口支持 infoWebView.addJavascriptInterface(inForHtml , "getHtml"); //通过webview.load();方法来进行源码解析,并返回string类型的数据 view.loadUrl("javascript:window.getHtml.showHtmlStr('<head>'+" + "document.getElementsByTagName('html')[0].innerHTML+'</head>');"); LogUtil.debug(RecruitsTestActivity.this, "加载完成后的url-----------"+url); } }); //注意,view.loadUrl()中的window.getHtml(与上面添加接口支持的第 //二个参数相同,用来代码本地类对象).showHtmlStr(与本地类中的方法 //名要相同。) //这样,解析后会自动调用本地类中的方法,并把string类型的源码回调
12.对title的二种获得方式
1 //方法1(多用这种) 2 infoWebView.setWebViewClient(new WebViewClient() { 3 @Override 4 public void onPageFinished(WebView view, String url) { 5 super.onPageFinished(view, url); 6 7 String title = infoWebView.getTitle(); 8 } 9 } 10 12 //方法2 13 public class InJavaSetTitle { 14 public void setTetle(String title) { 15 Log.d("title"+title); 16 } 17 } 18 //onPageFinished()方法中 19 InJavaSetTitle inJST = new InJavaSetTitle(); 20 21 infoWebView.addJavascriptInterface(inJST, "get_title"); 22 view.loadUrl("javascript:window.get_title.setTetle(" 23 + "document.getElementsByTagName('title')[0].innerHTML);"); 24 25 //方法3,不常用,就不写了。主要还是用方法一。 26
13.对html源码中的标签进行获取,对标签中的属性值进行获取
//比如,要得到属性name="type"的<input xxxxxxxxxxxxxxxxxxxx>标签中的value //值,取得方法如下 02-24 15:11:13.440: D/InformationActivity(24499): <script type="text/javascript" src="js/jweixin-1.0.0.js"></script> 02-24 15:11:13.440: D/InformationActivity(24499): <input type="hidden" name="cardId" value="241"> 02-24 15:11:13.440: D/InformationActivity(24499): <input type="hidden" name="type" value="02"> 02-24 15:11:13.440: D/InformationActivity(24499): <input id="listPicUrl" type="hidden" name="listPicUrl" value="http:/xxxxxxooooe.com.cn/map/images/weixin_share_card.png"> 02-24 15:11:13.440: D/InformationActivity(24499): <input id="title" type="hidden" name="title" value="国庆节贺卡"> //a public class InJavaScriptLocalObj { public void showSource(String html) { Log.e(tag, html); //"type----xxxxx", } } //b.创建对象 InJavaScriptLocalObj ijslo = new InIjavaScriptLocalObj(); infoWebView.addJavascriptInterface(ijslo, "local_obj");// 用来得到网页源代码 // c.这句在onPageFinish方法中。type走完这一步,就会把结果传给上面a中定义的方法,这时可以通过截取结果的方式,进行操作。结果形式"type----xxxxx", //如果不加下面语句中的'type'+'----'这点,传递的就只有"xxxxx", view.loadUrl("javascript:window.local_obj.showSource('type'+'----'+" + "document.querySelector('input[name=\"type\"]').getAttribute('value')" + ");");
14.当html网页中有alter弹框时,有时会弹不内容,要加上下面这句话。
webRecruits.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { //加这段可以证webview中的alert弹出来 return super.onJsAlert(view, url, message, result); } });
14.续,另外可以在android中定义弹框的类型,代替默认的.
可以看看这篇博客:噶噶噶
15.另外,其实可以在js中定义接口方法,然后调用安卓本地写的一些方法,个人觉得这篇文章写的不错,自己就不写了。
这篇:呵呵呵
16.最后就是一个大坑,当apk签名后,会造成js代码无法调用本地定义的类,与类中的方法,而导致的无法到解析数据。
方法就是对这定义的类与方法进行不混淆设置。
-keep public class <Package Name>.MainActivity$InJavaScriptLocalObj{ public void showSource(java.lang.String); } //.MainAcitivy是指的,当前存放定义返回数据接口InJavaScriptLocalObj的类名如果是独立的类,
//就不用加MainAcitivy类直接写后面的就行,$后的是接口类名InJavaScriptLocalObj
好了,就写这么多吧。