图片发自简书App

概述

从去年4月项目就一直用起了JsBridge,前面也针对jsBridge使用姿势介绍过一篇入门篇,《Android JsBridge实战 打造专属你的Hybrid APP》,本篇接着继续深入,通过再次优化封装,大大优化了部分代码,简化上层调用流程,快速部署你的Hybridge APP。

再进行具体编码前 ,我先进行了一般商业APP对WebView的需求

可加载本地和云端H5

拥有cookie持久能力

添加公共参数

回退前进功能

Js与本地navtive交互

拥有加载默认错误页面能力

加载网页可展现进度

好为了满足以上常用功能,大致对webview相关知识进行下普及。

WebView

谷歌提供的系统组件,用来加载和展现html网页,其采用webkit内核驱动,来实现网页浏览功能。

拥有load() URL和本地html文件

// 云端

webView.loadUrl("https://www.baidu.com");

// 本地

webView.loadUrl("file:///android_asset/demo.html");

WebViewClient

WebViewClient主要辅助WebView执行处理各种响应请求事件的,比如:

onLoadResource

onPageStart

onPageFinish

onReceiveError

onReceivedHttpAuthRequest

shouldOverrideUrlLoading

本次加载失败页面,和拦截加入header头必须用到它,由于android无法拦截h5本身ajax的请求,所以对header同步不是很好,建议大家对于ajax请求采用cookie形式,以防止url参数服务端无法获取的问题。

加入header 一般直接使用webView.load(url, header)

view.loadUrl(url, header);

为了方便上层开发者调用,可以将此code加入到WebViewClient 的shouldOverrideUrlLoading中执行

姿势那就是这样:

public boolean shouldOverrideUrlLoading(WebView view, String url) {

if(this.onPageHeaders(url) != null) {

view.loadUrl(url, this.onPageHeaders(url));

}

return super.shouldOverrideUrlLoading(view, url);

}

错误页面也是复写WebViewClient的onReceivedError() 来加入自定义的抽象onPageError(),姿势如下:

public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {

view.loadUrl(this.onPageError(failingUrl));

}

onPageHeaders()便是上层抽象出来的接口,方便我们直接加入header,而onPageError()是方便指定加载错误页面,那么在activity中就是这样了,

mProgressBarWebView.setWebViewClient(new CustomWebViewClient(mProgressBarWebView.getWebView()) {

@Override

public String onPageError(String url) {

return "file:///android_asset/error.html";

}

@Override

public Map onPageHeaders(String url) {

return CookieManger.getHeader(getContext());

}

});

WebChromeClient

主要辅助WebView处理Javascript的对话框、网站Logo、网站title、load进度等处理。

onCloseWindow(关闭WebView)

onCreateWindow()

onJsAlert ()

onJsPrompt

onJsConfirm

onProgressChanged

onReceivedIcon

onReceivedTitle

onShowCustomView

WebView只是用来处理一些html的页面内容,只用WebViewClient就行了,如果需要更丰富的处理效果,比如JS、进度条等,就要用到WebChromeClient。因为这次功能要用加载进度,不得不说它。

为了加入顶部的加载进度条,复写WebChromeClient中onProgressChanged,在这里更改我们加入的ProgressBar的进度,你也可以设置网页标题,甚至可以全屏!

public class CustomWebChromeClient extends WebChromeClient {

private NumberProgressBar mProgressBar;

public CustomWebChromeClient(NumberProgressBar progressBar) {

this.mProgressBar = progressBar;

}

public void onProgressChanged(WebView view, int newProgress) {

if(newProgress >= 95) {

this.mProgressBar.setVisibility(8);

} else {

if(this.mProgressBar.getVisibility() == 8) {

this.mProgressBar.setVisibility(0);

}

this.mProgressBar.setProgress(newProgress);

}

super.onProgressChanged(view, newProgress);

}

//获取tittle

@Override

public void onReceivedTitle(WebView view, String title) {

super.onReceivedTitle(view, title);

}

//全屏

@Override

public void onShowCustomView(View view, CustomViewCallback callback) {

super.onShowCustomView(view, callback);

}

}

好了准备好了同步Header和进度条之后,就的考虑cookie同步问题

CookieSync

CookieManager

CookieManager是用来管理Cookie的,主要来管理cookie相关,提供如下API

setAcceptCookie()

setCookie()

getCookie(String url);

removeSessionCookies();

hasCookies()

removeAllCookie()

CookieSyncManager

CookieSyncManagerl继承WebSyncManager,来管理同步cookie相关,主要有以下API

resetSync()

stopSync()

sync()

syncFromRamToFlash()

checkInstanceIsAllowed()

Https

private class SSLTolerentWebViewClient extends WebViewClient {

public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {

handler.proceed(); // Ignore SSL certificate errors

}

}

你想问这些api什么意思,请保留点你的童真,不要问这么简单的问题好吗?

接着我们就可以这样操作来实现cookie同步了,

CookieManager cookieManager = CookieManager.getInstance();

// 接受服务器cookie

cookieManager.setAcceptCookie(true);

//移除之前的cookie

cookieManager.removeSessionCookie();

// 注入cookies

List cookies = getCookies(customCookies);

for (String cookie : cookies) {

cookieManager.setCookie(uri.getHost(), cookie);

}

// 同步cookie

CookieSyncManager.getInstance().sync();

这里需要注意棒棒糖以上的会出现无法同步问题那么请这样做

if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

cookieManager.flush();

} else {

CookieSyncManager.getInstance().sync();

}

经测试,完美!

你可能想问?我想自定义像header一样加入一些自定义cookie,行,没问题,继续看!

public static List createCustomCookies() {

List cookies = new ArrayList<>();

cookies.add(“author ” + "= " + "tamic");

cookies.add(“data” + "= " + "2016.8.15");

cookies.add(“key” + "= " + 4fdfsfd34dfdfswer");

cookies.add(“chanel” + "= " + "简书");

return cookies;

}

很可能会遇到处理缓存问题,设置缓存webView缓存模式!这里在普及下相关姿势!

缓存模式

webview缓存模式有5种,具体方式:

LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据

LOAD_DEFAULT: 根据cache-control决定是否从网络上取数据。

LOAD_CACHE_NORMAL: API level 17中已经废弃, 从API level 11开始作用同LOAD_DEFAULT模式

LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.

LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。

www.baidu.com的cache-control为no-cache,在模式LOAD_DEFAULT下,无论如何都会从网络上取数据,如果没有网络,就会出现错误页面;在LOAD_CACHE_ELSE_NETWORK模式下,无论是否有网,只要本地有缓存,都会加载缓存。本地没有缓存时才从网络上获取,

这个和Http缓存一致,我不在过多介绍,如果你想自定义缓存策略和时间,可以尝试下,

清除缓存

CacheManager来处理webview缓存相关:

clearCache(boolean)

CacheManager.clear

在4.4以上的此api已经无法使用,也就是说缓存清空涉及安全,需要你自己去实现,就类似picasso, okhttp缓存,一样要开发者自我去实现。

当然也可以这样:

WebView.clearCache(true);

清空历史记录

mWebview.clearHistory();

需要在onPageFinished()的方法之后调用

ProgressBarWebView

学习了上面基础知识,我这里就开始进行自定义的进度条ProgressBarWebView的封装了,这里我直接对BridgeWebView进行扩展。下面是主要部分。

public class ProgressBarWebView extends LinearLayout {

static final String TAG = ProgressBarWebView.class.getSimpleName();

private NumberProgressBar mProgressBar;

private BridgeWebView mWebView;

public ProgressBarWebView(Context context) {

super(context);

this.init(context, (AttributeSet)null);

}

public ProgressBarWebView(Context context, AttributeSet attrs) {

super(context, attrs);

this.init(context, attrs);

}

@TargetApi(11)

public ProgressBarWebView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

this.init(context, attrs);

}

@TargetApi(21)

public ProgressBarWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

this.init(context, attrs);

}

为了使webview能有后退功能!我屏蔽了长按事件,并且对返回键建进行了拦截。

mWebView.setOnLongClickListener(new OnLongClickListener() {

public boolean onLongClick(View v) {

return true;

}

});

this.mWebView.setOnKeyListener(new OnKeyListener() {

public boolean onKey(View v, int keyCode, KeyEvent event) {

if(event.getAction() == 0 && keyCode == 4 && ProgressBarWebView.this.mWebView.canGoBack()) {

ProgressBarWebView.this.mWebView.goBack();

return true;

} else {

return false;

}

}

});

如果防止webview代码产生内存泄漏,请及时在activity销毁时,清空webview

@Override

public void onDestroy() {

super.onDestroyView();

if (mProgressBarWebView.getWebView() != null) {

mProgressBarWebView.getWebView().destroy();

}

}

看了构造方法你已明白,里面包含一个BridgeWebView和一个NumberProgressBar 成员属性,

接着就是对JsBridge进行封装了

js调用Java

public void registerHandler(final String handlerName, final JsHandler handler) {

this.mWebView.registerHandler(handlerName, new BridgeHandler() {

public void handler(String data, CallBackFunction function) {

if(handler != null) {

handler.OnHandler(handlerName, data, function);

// data实际就是js返回的jsonString数据,本案例为了统一处理,data统一采用{code,msg ,data} 形式,

}

}

});

}

Java调用js代码:

public void callHandler(final String handlerName, String javaData, final JavaCallHandler handler) {

this.mWebView.callHandler(handlerName, javaData, new CallBackFunction() {

public void onCallBack(String data) {

if(handler != null) {

handler.OnHandler(handlerName, data);

}

}

});

}

看可jsBridge的可能问这个JsHandler谁神马。本来在jsBridge源码中没这个东东的, 是为了方便上层调用我自己封装的接口,

public interface JsHandler {

void OnHandler(String var1, String var2, CallBackFunction var3);

好了 关键的东西已经介绍完,如果对jsBridge可以看看去年我写的一篇对他的介绍:Android JsBridge实战 打造专属你的Hybrid APP,

接着使用我们封装好的ProgressBarWebView

案列使用

Dependencies

Gradle:

root:

repositories {

maven { url "https://jitpack.io" }

jcenter()

}

Module:

dependencies {

.....

compile 'com.tamic:browse:1.0.0'

}

初始化

ProgressBarWebView mProgressBarWebView = (ProgressBarWebView) findViewById(R.id.login_progress_webview);

设置自定义WebViewClient

mProgressBarWebView.setWebViewClient(new CustomWebViewClient(mProgressBarWebView.getWebView()) {

@Override

public String onPageError(String url) {

//指定网络加载失败时的错误页面

return "file:///android_asset/error.html";

}

@Override

public Map onPageHeaders(String url) {

// 可以加入header

return null;

}

});

加载指定Url

mProgressBarWebView.loadUrl("file:///android_asset/demo.html");

当然,也可以支持网络url;

注册Js回调函数

ArrayList mHandlerNames = new ArrayList<>();

mHandlers.add("login");

mHandlers.add("callNative");

mHandlers.add("callJs");

mHandlers.add("open");

回调js的方法

mProgressBarWebView.registerHandlers(mHandlers, new JsHandler() {

@Override

public void OnHandler(String handlerName, String responseData, CallBackFunction function) {

if (handlerName.equals("login")) {

Toast.makeText(MainActivity.this, responseData, Toast.LENGTH_SHORT).show();

} else if (handlerName.equals("callNative")) {

Toast.makeText(MainActivity.this, responseData, Toast.LENGTH_SHORT).show();

function.onCallBack("我在上海");

} else if (handlerName.equals("callJs")) {

Toast.makeText(MainActivity.this, responseData, Toast.LENGTH_SHORT).show();

// 想调用你的方法:

function.onCallBack("好的 这是图片地址 :xxxxxxx");

} if (handlerName.equals("open")) {

mfunction = function;

pickFile();

}

}

});

Native调用js

mProgressBarWebView.callHandler("callNative", "hello H5, 我是java", new JavaCallHandler() {

@Override

public void OnHandler(String handlerName, String jsResponseData) {

Toast.makeText(MainActivity.this, "h5返回的数据:" + jsResponseData, Toast.LENGTH_SHORT).show();

}

});

Native发送消息给js

mProgressBarWebView.send("哈喽", new CallBackFunction() {

@Override

public void onCallBack(String data) {

Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();

}

});

}

Xml文件和js代码这里不做介绍,具体看项目案列中源码:

如果喜欢,请star!

效果图:

图片发自简书App

结束语

这里感谢曾技术经理出身的同事的对相关部分代码的封装,感谢振南同学!

android 加载条封装,Android基于JsBridge封装的高效带加载进度的WebView相关推荐

  1. web高德地图怎么加载离线地图_基于 QGIS 在内网中离线加载卫星地图的方法

    1. 概述 我们之前为大家分享过在三维地球开源平台离线加载卫星影像的方法,主要包括基于桌面端的OsgEarth开源三维地球和基于Web端的Cesium开源三维地球等平台的局域网离线影像加载. 另外,也 ...

  2. matlab生成s加减速曲线,一种基于移动平均算法的S曲线加减速控制方法与流程

    本发明属于运动控制领域,具体涉及一种基于移动平均算法的S曲线加减速控制方法. 背景技术: 加减速技术是数控系统的关键技术之一,算法的优劣直接决定着加工效率和加工精度.一种优秀的加减速算法既可以保证机床 ...

  3. android 增加一条广播,Android中BroadcastReceiver广播使用及注意点

    Android中的广播用途很广,是四大组件之一.在android中可以看到它的各种应用,从系统发出的广播,用户自定义的广播等. 这里详细记录下广播的分类以及使用方法. 广播,是由两方面组成一个流程:广 ...

  4. android定义一条虚线,android自定义TextView添加虚线(虚线下划线)

    目前相关文字下方添加虚线的文章非常少,备选方案有: 1 文字下方添加一个drawable实现虚线样式 2 通过spannable方案自定义 3 通过textview的getpaint实现 4 实现自定 ...

  5. list ajax封装,util-pagelist_基于layui封装的ajax分页列表

    /** * layui分页列表模板引擎(使用时请使用new Pagelist(), 将每个分页模板当成一个独立的实例) * @param tplid 模板id * @param viewid 渲染模板 ...

  6. Android循环滚动广告条的完美实现,封装方便,平滑过渡,从网络加载图片,点击广告进入对应网址

    关注finddreams,一起分享,一起进步: http://blog.csdn.net/finddreams/article/details/44619589 今天给大家带来一点干货,就是横向循环滚 ...

  7. android 刷新某条数据_Android 支持刷新、加载更多、带反弹效果的RecyclerView

    点击上方"Android技术杂货铺",选择"标星" 干货文章,第一时间送达! 开篇 当前市面上很多支持刷新.加载更多RecyclerView开源库,为何我这里还 ...

  8. VS2015 Cordova实现WebView加载页面进度条(Android)

    因为使用Cordova做app时,加载页面没有进度条,用户无法感知打开进度,故加入进度条,具体实现如下: 1.  如果项目没有生成过apk,需先生成一次,这样在项目下面才会出现platforms/an ...

  9. android图标随着进度条动画,Android开发之ProgressBar字体随着进度条的加载而滚动...

    在网上翻阅了很多关于ProgressBar滚动效果,但是始终没有找到适合项目中的这种效果,故自己写这篇文章,记录一下写作过程,给大家做一个参考.先看下最终效果效果图 我这里用的是LICEcap软件录制 ...

最新文章

  1. tensorboard merge报错_什么是TensorBoard?
  2. bayer格式插值算法实现
  3. 反浏览器指纹追踪(反浏览器指纹追踪技术)
  4. verilog for循环_HDLBits:在线学习 Verilog (二十四 · Problem 115-119)
  5. 【计算机组成原理】乘法阵列器
  6. [收藏]REST -维基百科
  7. mysql数据库的字符集_mysql数据库中字符集乱码问题原因及解决
  8. Burst Balloons
  9. sql server 视图_SQL Server –具有引用视图的开发实践
  10. nginx 启动、重启、关闭
  11. 文言文已经没啥用了?错!还能编程用!
  12. PostgreSQL column cryptographic use pgcrypto extension and optional openssl lib
  13. 机电传动控制第四周作业
  14. PacketTracer简单使用】
  15. android 校园 源码,android 校园交易APP
  16. 计算机类期刊审稿周期及录用比例
  17. 分享网页微信防撤回插件
  18. OpenSSL密码库算法笔记——第2.2.2章 Barrett约化的优越性
  19. svn查找历史版本_svn历史版本对比以及还原到历史版本
  20. 论大数据时代下的海量数据存储技术

热门文章

  1. MySQL调优(六):分区设计,分区优化案例
  2. 【JavaScript】请求数据时,添加时间戳,避免浏览器缓存
  3. PAT1044 火星数字 (20 分)
  4. vs unity shader插件_一些Shader资料
  5. leetcode--207. 课程表
  6. zoj 3327 Friend Number 模拟题
  7. 【测试点三、四、五分析】1032 Sharing (25 分)_28行代码AC
  8. 【终极方法】 Cannot create PoolableConnectionFactory (Unknown database ‘jdbc‘)
  9. 做系统ghost步骤图解_Ghost 博客搭建超全指南
  10. python操作hive数据库代码_windows下怎么用python连接hive数据库