## (一).前言:
今天我们来学习一下重写WebView组件来实现网页的加载,以及我们平时APP开发中经常使用的JS注入,js和java相互调用的问题来重点讲解一下。如果大家都WebView加载还不是太熟悉的话,这边我之前专门写了一个WebView的专题,其他包含基本使用和js注入的问题。[(点击进入WebView进阶专题)](http://blog.csdn.net/column/details/adandroid.html)
FastDev4Android框架项目地址:[https://github.com/jiangqqlmj/FastDev4Android](https://github.com/jiangqqlmj/FastDev4Android)
## (二).重写WebView:
2.1首先我们来看一下实现的效果:
![](https://box.kancloud.cn/2016-01-18_569c8eb60a033.jpg)![](https://box.kancloud.cn/2016-01-18_569c8eb6a3f09.jpg)
2.2.重写WebView:创建一个HTML5CustomWebView类集成自WebView,然后就是一下几个步骤实现:
* 布局文件
* WebSettings初始化相关设置
* 设置重写WebChromeClient进行相关处理
* 设置重写WebViewClient进行相关处理即可
简单的来说就是以上这几步就可以了
2.3.WebView布局文件主要定义导航栏,网页加载进度,以及WebView容器布局,如下:
~~~
<?xmlversion="1.0" encoding="utf-8"?>
<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/white">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="@+id/fullscreen_custom_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/white"
android:visibility="gone"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- 自定义顶部导航功能条 -->
<includelayout="@layout/common_top_bar_layout" />
<!-- 中间显示内容 -->
<FrameLayout
android:id="@+id/main_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone" />
<!-- 网页加载进度显示 -->
<FrameLayout
android:id="@+id/frame_progress"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="visible" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical" >
<ProgressBar
style="@android:style/Widget.ProgressBar.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:indeterminate="false"
android:indeterminateDrawable="@drawable/loading_small" />
<TextView
android:id="@+id/webview_tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dip"
android:text="正在加载,已完成0%..."
android:textSize="12sp" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
</RelativeLayout>
</FrameLayout>
~~~
2.4.WebSettings初始化设置如下:
~~~
WebSettingswebSettings = this.getSettings();
webSettings.setJavaScriptEnabled(true); //开启javascript
webSettings.setDomStorageEnabled(true); //开启DOM
webSettings.setDefaultTextEncodingName("utf-8");//设置编码
// // web页面处理
webSettings.setAllowFileAccess(true);// 支持文件流
// webSettings.setSupportZoom(true);// 支持缩放
// webSettings.setBuiltInZoomControls(true);// 支持缩放
webSettings.setUseWideViewPort(true);// 调整到适合webview大小
webSettings.setLoadWithOverviewMode(true);//调整到适合webview大小
webSettings.setDefaultZoom(ZoomDensity.FAR);//屏幕自适应网页,如果没有这个,在低分辨率的手机上显示可能会异常
webSettings.setRenderPriority(RenderPriority.HIGH);
//提高网页加载速度,暂时阻塞图片加载,然后网页加载好了,在进行加载图片
webSettings.setBlockNetworkImage(true);
//开启缓存机制
webSettings.setAppCacheEnabled(true);
//根据当前网页连接状态
if(StrUtils.getAPNType(context)==StrUtils.WIFI){
//设置无缓存
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
}else{
//设置缓存
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}
~~~
2.5.WebChromeClient进行相关设置处理
~~~
private classMyWebChromeClient extends WebChromeClient {
privateBitmap mDefaultVideoPoster;
@Override
publicvoid onShowCustomView(View view,
CustomViewCallbackcallback) {
super.onShowCustomView(view,callback);
HTML5CustomWebView.this.setVisibility(View.GONE);
if(mCustomView != null) {
callback.onCustomViewHidden();
return;
}
mCustomViewContainer.addView(view);
mCustomView= view;
mCustomViewCallback= callback;
mCustomViewContainer.setVisibility(View.VISIBLE);
}
@Override
publicvoid onHideCustomView() {
if(mCustomView == null) {
return;
}
mCustomView.setVisibility(View.GONE);
mCustomViewContainer.removeView(mCustomView);
mCustomView= null;
mCustomViewContainer.setVisibility(View.GONE);
mCustomViewCallback.onCustomViewHidden();
HTML5CustomWebView.this.setVisibility(View.VISIBLE);
super.onHideCustomView();
}
/**
* 网页加载标题回调
* @param view
* @param title
*/
@Override
publicvoid onReceivedTitle(WebView view, String title) {
Log.d("zttjiangqq", "当前网页标题为:" + title);
wv_tv_title.setText(title);
}
/**
* 网页加载进度回调
* @param view
* @param newProgress
*/
@Override
publicvoid onProgressChanged(WebView view, int newProgress) {
// 设置进行进度
((Activity)mContext).getWindow().setFeatureInt(
Window.FEATURE_PROGRESS,newProgress * 100);
webview_tv_progress.setText("正在加载,已完成" +newProgress + "%...");
webview_tv_progress.postInvalidate(); //刷新UI
Log.d("zttjiangqq", "进度为:" + newProgress);
}
@Override
publicboolean onJsAlert(WebView view, String url, String message,
JsResultresult) {
returnsuper.onJsAlert(view, url, message, result);
}
}
~~~
2.6.WebViewClient进行相关设置处理
~~~
private classMyWebViewClient extends WebViewClient {
/**
*加载过程中 拦截加载的地址url
* @param view
*@param url 被拦截的url
* @return
*/
@Override
publicboolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i("zttjiangqq","-------->shouldOverrideUrlLoading url:" + url);
//这边因为考虑到之前项目的问题,这边拦截的url过滤掉了zttmall://开头的地址
//在其他项目中 大家可以根据实际情况选择不拦截任何地址,或者有选择性拦截
if(!url.startsWith("zttmall://")){
UrimUri = Uri.parse(url);
List<String>browerList = new ArrayList<String>();
browerList.add("http");
browerList.add("https");
browerList.add("about");
browerList.add("javascript");
if(browerList.contains(mUri.getScheme())) {
returnfalse;
}else {
Intentintent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.addCategory(Intent.CATEGORY_BROWSABLE);
//如果另外的应用程序WebView,我们可以进行重用
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Browser.EXTRA_APPLICATION_ID,
FDApplication.getInstance()
.getApplicationContext().getPackageName());
try{
FDApplication.getInstance().startActivity(intent);
returntrue;
}catch (ActivityNotFoundException ex) {
}
}
returnfalse;
}else{
returntrue;
}
}
/**
* 页面加载过程中,加载资源回调的方法
* @param view
* @param url
*/
@Override
publicvoid onLoadResource(WebView view, String url) {
super.onLoadResource(view,url);
Log.i("zttjiangqq","-------->onLoadResource url:" + url);
}
/**
* 页面加载完成回调的方法
* @param view
* @param url
*/
@Override
publicvoid onPageFinished(WebView view, String url) {
super.onPageFinished(view,url);
Log.i("zttjiangqq","-------->onPageFinished url:" + url);
if(isRefresh) {
isRefresh= false;
}
// 加载完成隐藏进度界面,显示WebView内容
frame_progress.setVisibility(View.GONE);
mContentView.setVisibility(View.VISIBLE);
// 关闭图片加载阻塞
view.getSettings().setBlockNetworkImage(false);
}
/**
* 页面开始加载调用的方法
* @param view
* @param url
* @param favicon
*/
@Override
publicvoid onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("zttjiangqq","onPageStarted:-----------"+url);
super.onPageStarted(view,url, favicon);
}
@Override
publicvoid onReceivedError(WebView view, int errorCode,
Stringdescription, String failingUrl) {
super.onReceivedError(view,errorCode, description, failingUrl);
}
@Override
publicvoid onScaleChanged(WebView view, float oldScale, float newScale) {
super.onScaleChanged(view,oldScale, newScale);
HTML5CustomWebView.this.requestFocus();
HTML5CustomWebView.this.requestFocusFromTouch();
}
}
~~~
以上一般使用到得方法已经做了相关的注释。
最后一步就是使用了,使用起来很简单,创建一个Activity,然后把我们定义的WebView加入到布局然后加载网页即可。如下:
~~~
packagecom.chinaztt.fda.html5;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.res.Configuration;
importandroid.net.Uri;
importandroid.os.Bundle;
importandroid.view.KeyEvent;
importandroid.view.MotionEvent;
importandroid.webkit.DownloadListener;
importandroid.webkit.JavascriptInterface;
/**
* 当前类注释:
* 项目名:FastDev4Android
* 包名:com.chinaztt.fda.html5
* 作者:江清清 on 15/11/06 08:59
* 邮箱:jiangqqlmj@163.com
* QQ: 781931404
* 公司:江苏中天科技软件技术有限公司
*/
importcom.chinaztt.fda.ui.base.BaseActivity;
public classHTML5WebViewCustomAD extends BaseActivity {
privateHTML5CustomWebView mWebView;
//http://www.zttmall.com/Wapshop/Topic.aspx?TopicId=18
privateString ad_url = "http://www.baidu.com/";
private String title="百度一下你就知道";
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWebView= new HTML5CustomWebView(this, HTML5WebViewCustomAD.this,title,ad_url);
mWebView.setDownloadListener(newDownloadListener() {
@Override
publicvoid onDownloadStart(String url, String userAgent,
StringcontentDisposition, String mimetype,
longcontentLength) {
Uriuri = Uri.parse(url);
Intentintent = new Intent(Intent.ACTION_VIEW, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
//准备javascript注入
mWebView.addJavascriptInterface(
newJs2JavaInterface(),"Js2JavaInterface");
if(savedInstanceState != null) {
mWebView.restoreState(savedInstanceState);
}else {
if(ad_url != null) {
mWebView.loadUrl(ad_url);
}
}
setContentView(mWebView.getLayout());
}
@Override
publicvoid onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(mWebView != null) {
mWebView.saveState(outState);
}
}
@Override
protectedvoid onResume() {
super.onResume();
if(mWebView != null) {
mWebView.onResume();
}
}
@Override
publicvoid onStop() {
super.onStop();
if(mWebView != null) {
mWebView.stopLoading();
}
}
@Override
protectedvoid onPause() {
super.onPause();
if(mWebView != null) {
mWebView.onPause();
}
}
@Override
protectedvoid onDestroy() {
super.onDestroy();
if(mWebView != null) {
mWebView.doDestroy();
}
}
@Override
publicvoid onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
publicboolean onTouchEvent(MotionEvent event) {
returnsuper.onTouchEvent(event);
}
@Override
publicboolean onKeyDown(int keyCode, KeyEvent event) {
returnsuper.onKeyDown(keyCode, event);
}
@Override
publicvoid onBackPressed() {
if(mWebView != null) {
if(mWebView.canGoBack()){
mWebView.goBack();
}else{
mWebView.releaseCustomview();
}
}
super.onBackPressed();
}
/**
* JavaScript注入回调
*/
publicclass Js2JavaInterface {
privateContext context;
privateString TAG = "Js2JavaInterface";
@JavascriptInterface
publicvoid showProduct(String productId){
if(productId!=null){
//进行跳转商品详情
showToastMsgShort("点击的商品的ID为:" +productId);
}else{
showToastMsgShort("商品ID为空!");
}
}
}
}
~~~
## (三).js注入方法:
仔细查看上面的代码可能大家会发现这样两块地方:
~~~
mWebView.addJavascriptInterface(
newJs2JavaInterface(),"Js2JavaInterface");
~~~
~~~
public classJs2JavaInterface {
privateContext context;
privateString TAG = "Js2JavaInterface";
@JavascriptInterface
publicvoid showProduct(String productId){
if(productId!=null){
//进行跳转商品详情
showToastMsgShort("点击的商品的ID为:" +productId);
}else{
showToastMsgShort("商品ID为空!");
}
}
}
~~~
这边就是js注入回调处理的方法,在这边的实例中是使用http://www.zttmall.com/Wapshop/Topic.aspx?TopicId=18这个地址进行加载网页的时候才会生效,因为这边点击网页图片的时候,html代码中加载js方法,
我们来看一下网页的源代码:
![](https://box.kancloud.cn/2016-01-18_569c8eb70484f.jpg)
查看源代码我们就知道
mWebView.addJavascriptInterface(
newJs2JavaInterface(),"Js2JavaInterface");
中第二个参数就是在js方法中调用的对象名字,然后注入对象中回调的方法和js方法中的方法一样即可。这样就完成了一次注入点击回调工作,我们的html就可以和原生java代码发生交互了。使用这种方式非常有助于我们的混合开发。
好了到此重写WebView实现以及js注入的基本使用就讲完了,具体全部代码已经上传到FastDev4Android项目中了。同时欢迎大家去Github站点进行clone或者下载浏览:
[https://github.com/jiangqqlmj/FastDev4Android](https://github.com/jiangqqlmj/FastDev4Android) 同时欢迎大家star和fork整个开源快速开发框架项目~
- 前言
- Android快速开发框架介绍(一)
- Android首页图片自动无限循环轮播Gallery+FlowIndicator(二)
- Android 列表下拉刷新组件PullToRefreshListView使用(三)
- Android 数据缓存器ACache的详解和使用(四)
- Android崩溃异常捕捉CustomCrash,提升用户体验(五)
- Android实现沉浸式状态栏(六)
- AndroidAnnnotations注入框架介绍和Android Studios基本配置(七)
- AndroidAnnnotations注入框架的工作原理(八)
- AndroidAnnnotations注入框架使用之注入组件Components(九)
- AndroidAnnnotations注入框架使用之Injection标签详解(十)
- AndroidAnnnotations注入框架使用之事件绑定Event Binding(十一)
- AndroidAnnnotations注入框架使用之线程处理Threading(十二)
- AndroidAnnnotations注入框架使用之第三方框架集成RoboGuice(十三)
- AndroidAnnnotations注入框架使用之第三方框架集成Otto事件总线(十四)
- AndroidAnnnotations注入框架使用之第三方框架集成OrmLite(十五)
- AndroidAnnnotations注入框架使用之最佳实践之Adapters和lists(十六)
- AndroidAnnnotations注入框架使用之最佳实践SharedPreferences(十七)
- Android MVP开发模式详解(十九)
- 消息总线EventBus的基本使用(二十)
- 消息总线EventBus源码分析以及与Otto框架对比(二十一)
- 列表头生成带文本或者字母的图片开源库TextDrawable使用和详解(二十二)
- 重写WebView网页加载以及JavaScript注入详解(二十三)
- BaseAdapterHelper的基本使用介绍,让你摆脱狂写一堆Adapter烦恼(二十四)
- BaseAdapterHelper详解源码分析,让你摆脱狂写一堆Adapter烦恼(二十五)
- Volley完全解析之基础使用(二十六)
- Volley完全解析之进阶最佳实践与二次封装(二十七)
- RecyclerView完全解析,让你从此爱上它(二十八)
- RecyclerView完全解析之打造新版类Gallery效果(二十九)
- RecyclerView完全解析之结合AA(Android Annotations)注入框架实例(三十)
- RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)
- CardView完全解析与RecyclerView结合使用(三十二)
- 神器ViewDragHelper完全解析,妈妈再也不担心我自定义ViewGroup滑动View操作啦~(三十三)
- 神器ViewDragHelper完全解析之详解实现QQ5.X侧滑酷炫效果(三十四)
- 实例解析之SwipeRefreshLayout+RecyclerView+CardView(三十五)
- HorizontalScrollView,Fragment,FragmentStatePagerAdapter打造网易新闻Tab及滑动页面效果(三十六)
- Android Design支持库TabLayout打造仿网易新闻Tab标签效果(三十七)
- 打造QQ6.X最新版本侧滑界面效果(三十八)