Android与H5交互

Android通过webView来实现
1、loadUrl,加载界面
加载assets文件夹下的test.html页面:
mWebView.loadUrl("file:///android_asset/test.html")
加载Url:
mWebView.loadUrl("http://www.baidu.com")
注:还有LoadData和LoadDataWithBase方法
2、WebViewClient,主要用来辅助WebView处理各种通知、请求等事件,通过setWebViewClient方法设置。
基本的回调方法:
(1)更新历史记录
doUpdateVisitedHistory(WebView view, String url, boolean isReload)
(2)应用程序重新请求网页数据
onFormResubmission(WebView view, Message dontResend, Message resend)
(3)在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
onLoadResource(WebView view, String url)
(4)开始载入页面调用,通常我们可以在这设定一个loading的页面,告诉用户程序在等待网络响应。
onPageStarted(WebView view, String url, Bitmap favicon)
(5)在页面加载结束时调用。同样道理,我们知道一个页面载入完成,于是我们可以关闭loading 条,切换程序动作。
onPageFinished(WebView view, String url)
(6)报告错误信息
onReceivedError(WebView view, int errorCode, String description, String failingUrl)
(7)获取返回信息授权请求
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,String realm)
(8)重写此方法可以让webview处理https请求。
onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)
(9)WebView发生改变时调用
onScaleChanged(WebView view, float oldScale, float newScale)
(10)Key事件未被加载时调用
onUnhandledKeyEvent(WebView view, KeyEvent event)
(11)重写此方法才能够处理在浏览器中的按键事件。
shouldOverrideKeyEvent(WebView view, KeyEvent event)
(12)在网页跳转时调用,这个函数我们可以做很多操作,比如我们读取到某些特殊的URL,于是就可以不打开地址,取消这个操作,进行预先定义的其他操作,这对一个程序是非常必要的。
shouldOverrideUrlLoading(WebView view, String url)
注:shouldOverrideUrlLoading在网页跳转的时候调用,且一般每跳转一次只调用一次。
(13)在加载某个网页的资源的时候多次调用(已过时)
shouldInterceptRequest(WebView view, String url)
(14)在加载某个网页的资源的时候多次调用
shouldInterceptRequest(WebView view, WebResourceRequest request)
注:shouldInterceptRequest只要是网页加载的过程中均会调用,资源加载的时候都会回调该方法,会多次调用。
常用的回调:
a、调用上面方法加载的话,点击页面中的链接时,页面将会在你手机默认的浏览器上打开。想要页面在App内中打开的话,设置如下代码:
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
mWebView.loadUrl(url);
return true;
}
}
});
b、拦截HTML页面中的点击事件,设置如下代码:
mWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { //判断url拦截事件,点击之后原本要跳转的Url if (url.equals("file:///android_asset/test2.html")) { //拦截成功后要走的逻辑 return true; } } });
注:该方法中最后设置,return true,则在打开新的url时WebView就不会再加载这个url了,所有处理都需要在WebView中操作,包含加载;return false,则系统就认为上层没有做处理,接下来还是会继续加载这个url的;默认return false。
c、加载网页时替换某个资源(替换logo图片),设置如下代码:
mWebView.setWebViewClient(new WebViewClient(){
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
WebResourceResponse response = null;
if (url.contains("logo")) {
try {
InputStream logo = getAssets().open("logo.png");
response = new WebResourceResponse("image/png", "UTF-8", logo);
} catch (IOException e) {
e.printStackTrace();
}
}
return response;
}
});
注:第二个参数,WebResourceRequest 将能够获取更多的信息,提供了getUrl(),getMethod,getRequestHeaders等方法。
d、设置开始加载网页、加载完成、加载错误时处理,设置如下代码:
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
// 开始加载网页时处理 如:显示"加载提示" 的加载对话框
...
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// 网页加载完成时处理 如:让 加载对话框 消失
...
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
// 加载网页失败时处理 如:提示失败,或显示新的界面
...
}
});
e、处理https请求,为WebView处理ssl证书设置WebView默认是不处理https请求的,,设置如下代码:
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed(); // 接受信任所有网站的证书
// handler.cancel(); // 默认操作 不处理
// handler.handleMessage(null); // 可做其他处理
}
});
3、WebChromeClient主要用来辅助WebView处理Javascript的对话框、网站图标、网站标题以及网页加载进度等。通过WebView的setWebChromeClient()方法设置。
基本回调方法:
(1)监听网页加载进度
onProgressChanged(WebView view, int newProgress)
(2)监听网页标题 : 比如百度页面的标题是“百度一下,你就知道”
onReceivedTitle(WebView view, String title)
(3)监听网页图标
onReceivedIcon(WebView view, Bitmap icon)
常用的回调:
a、显示页面加载进度在WebChromeClient子类中重写父类的onProgressChanged函数,progress表示当前页面加载的进度,为1至100的整数
webView.setWebChromeClient(new WebChromeClient() { public void onProgressChanged(WebView view, int progress) { setTitle("页面加载中,请稍候..." + progress + "%"); setProgress(progress * 100); if (progress == 100) { //... } } });
b、加快HTML网页加载完成速度
//1.首先在WebView初始化时添加如下代码if(Build.VERSION.SDK_INT >= 19) { /*对系统API在19以上的版本作了兼容。因为4.4以上系统在onPageFinished时再恢复图片加载时,如果存在多张图片引用的是相同的src时,会只有一个image标签得到加载,因而对于这样的系统我们就先直接加载。*/ webView.getSettings().setLoadsImagesAutomatically(true); } else { webView.getSettings().setLoadsImagesAutomatically(false); } //2.在WebView的WebViewClient子类中重写onPageFinished()方法添加如下代码: @Override public void onPageFinished(WebView view, String url) { if(!webView.getSettings().getLoadsImagesAutomatically()) { webView.getSettings().setLoadsImagesAutomatically(true); } }
注:默认情况html代码下载到WebView后,webkit开始解析网页各个节点,发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件,但如果在这之前也有解析到image节点,那势必也会发起网络请求下载相应的图片。在网络情况较差的情况下,过多的网络请求就会造成带宽紧张,影响到css或js文件加载完成的时间,造成页面空白loading过久。解决的方法就是告诉WebView先不要自动加载图片,等页面finish后再发起图片加载。
4、setDownloadListener,通常webview渲染的界面中含有可以下载文件的链接,点击该链接后,应该开始执行下载的操作并保存文件到本地中。
创建DownloadListener
class MyDownloadListenter implements DownloadListener{ @Override public void onDownloadStart(String url, String userAgent,String contentDisposition, String mimetype, long contentLength) { //下载任务...,主要有两种方式 //(1)自定义下载任务 //(2)调用系统的download的模块 Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); }}
给webview加入监听
webview.setDownloadListener(new MyDownloadListenter());
5、goBack(),返回上一浏览页面,通过重写onKeyDown方法实现点击返回键返回上一浏览页面而非退出程序
public boolean onKeyDown(int keyCode, KeyEvent event) { //其中webView.canGoBack()在webView含有一个可后退的浏览记录时返回true if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) { webView.goBack(); return true; } return super.onKeyDown(keyCode, event); }}
6、WebSettings配置,一些对加载网页的设置
常用的设置方法:
(1)支持js
settings.setJavaScriptEnabled(true);
(2)设置缓存方式,主要有以下几种:
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
注: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,都使用缓存中的数据。
(3)开启DOM storage API功能(HTML5 提供的一种标准的接口,主要将键值对存储在本地,在页面加载完毕后可以通过 JavaScript 来操作这些数据。)
settings.setDomStorageEnabled(true);
(4)设置数据库缓存路径
settings.setDatabasePath(cacheDirPath);
(5)设置Application Caches缓存目录
settings.setAppCachePath(cacheDirPath);
(6)设置默认编码
settings.setDefaultTextEncodingName(“utf-8”);
(7)将图片调整到适合webview的大小
settings.setUseWideViewPort(false);
(8)支持缩放
settings.setSupportZoom(true);
(9)支持内容重新布局
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
(10)多窗口
settings.supportMultipleWindows();
(11)设置可以访问文件
settings.setAllowFileAccess(true);
(12)当webview调用requestFocus时为webview设置节点
settings.setNeedInitialFocus(true);
(13)设置支持缩放
settings.setBuiltInZoomControls(true);
(14)支持通过JS打开新窗口
settings.setJavaScriptCanOpenWindowsAutomatically(true);
(15)缩放至屏幕的大小
settings.setLoadWithOverviewMode(true);
(16)支持自动加载图片
settings.setLoadsImagesAutomatically(true);
7、Android本地通过Java调用HTML页面中的js方法
第一步,让webView支持调用js方法
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);//设置为可调用js方法
第二步,
若调用的js方法没有返回值,则直接可以调用mWebView.loadUrl("javascript:do()");其中do是js中的方法;
若有返回值时我们可以调用mWebView.evaluateJavascript()方法:
mWebView.evaluateJavascript("sum(1,2)", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.e(TAG, "onReceiveValue value=" + value);
}
});
8、Android本地的Java方法让js调用
在Android4.2以上可以直接使用@JavascriptInterface注解来声明定义一个方法,定义完这个方法后再调用mWebView.addJavascriptInterface()方法:
mWebView.addJavascriptInterface(new JsInteration(), "android");
9、WebView中的Cookie操作
webView需要保存从网页中获取到的Cookie 在涉及到账户体系的产品中,包含了一种登录状态的传递。比如,在Native(原生)界面的登录操作,进入到Web界面时,涉及到账户信息时,需要将登录状态传递到Web里面,避免用户二次登录。这里就涉及到WebView加载网页时的Cookie操作了。通常我们在登录时获取到用户的Cookie信息,然后将其保存到sdcard的WebView缓存文件当中,这样在加载网页时,WebView会自动将当前url的本地Cookie信息放在http请求的request中,传递给服务器。
获取cookie
//加载百度网站wv.loadUrl("http://www.baidu.com")wv.setWebViewClient(new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); CookieManager instance = CookieManager.getInstance(); //这样就可以获取到Cookie了 String cookie = instance.getCookie(url); Log.i(TAG, "onPageStarted: "+cookie); }}
设置cookie
//创建CookieSyncManager 参数是上下文 CookieSyncManager.createInstance(context); //得到CookieManager CookieManager cookieManager = CookieManager.getInstance(); //得到向URL中添加的Cookie的值 String cookieString;//获取方法不再详述,以项目要求而定 //使用cookieManager..setCookie()向URL中添加Cookie cookieManager.setCookie(url, cookieString); CookieSyncManager.getInstance().sync();
10、在activity被杀死之后,依然保持webView的状态,方便用户下次打开的时候可以回到之前的状态。webview支持saveState(bundle)和restoreState(bundle)方法。
保存状态
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); wv.saveState(outState); Log.e(TAG, "save state..."); }
恢复状态(在activity的onCreate(bundle savedInstanceState)里)
if(null!=savedInstanceState){ wv.restoreState(savedInstanceState); Log.i(TAG, "restore state"); }else{ wv.loadUrl("http://3g.cn"); }
11、android原生登录使用webview访问h5,同步登录状态
一种方式,可以先加载登录的页面,通过JAVA方法与JS进行交互,解析返回的html,成功之后再加载要跳转的页面。
注:采用静态方法Jsoup.parse(String HTML),或者Jsoup.parse(String html, String baseUri),将输入的HTML字符串解析到新的Document。
12、一些问题
a、WebViewJavascriptBridge是移动UIView和Html交互通信的桥梁,就是实现java和js的互相调用的桥梁。替代了WebView的自带的JavascriptInterface的接口,使得开发者更方便的让js和native灵活交互,使我们的开发更加灵活和安全。
Android API 4.4以前,谷歌的webview存在安全漏洞,网站可以通过js注入就可以随便拿到客户端的重要信息,甚至轻而易举的调用本地代码进行流氓行为,谷歌后来发现有此漏洞后,在API 4.4以后增加了防御措施,如果用js调用本地代码,开发者必须在代码申明JavascriptInterface, 列如在4.0之前我们要使得webView加载js只需如下代码:mWebView.addJavascriptInterface(new JsToJava(), "myjsfunction");4.4之后使用时需要在调用Java方法加入@JavascriptInterface注解,如果代码无此申明,那么也就无法使得js生效,也就是说这样就可以避免恶意网页利用js对客户端的进行窃取和攻击。 但是即使这样,我们很多时候需要在js调用本地java代码的时候,要做一些判断和限制,或者有的场景也会做些过滤或者对用户友好提示,甚至更复杂的Hybrid模式下,需要js和native之间进行交互通讯,拍照上传,因此原生的JavascriptInterface 就比较维护了,特此有了基于JavascriptInterface 封装的WebViewJavascriptBridge框架。
b、webview在布局文件中的使用:WebView对象并不是直接写在布局文件中的,而是通过一个LinearLayout容器,使用addview(webview)动态向里面添加的。另外需要注意创建webview需要使用applicationContext而不是activity的context。
webView写在其它容器中时(先销毁webview再销毁activity)因为 webview是独立进程,最好创建个viewGroup用来放置webview,Activity创建时add进来,在Activity停止时remove掉。或者最后需要及时销毁webview,onDestory()中应该先从LinearLayout中remove掉webview,再调用webview.removeAllViews();webview.destory();
c、切换WebView闪屏问题。如果你需要在同一个ViewGroup中来回切换不同的WebView(包含了不同的网页内容)的话,你就会发现闪屏是不可避免的。这应该是Android硬件加速的Bug,如果关闭硬件加速这种情况会好很多,但无法获得很好的浏览体验,你会感觉网页滑动的时候一卡一卡的,不跟手。
d、WebView硬件加速导致页面渲染闪烁问题。关于Android硬件加速 开始于Android 3.0 (API level 11),开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个副作用就是容易会出现页面加载白块同时界面闪烁现象。解决这个问题的方法是设置WebView暂时关闭硬件加速 代码如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
e、在某些手机上,Webview有视频时,activity销毁后,视频资源没有被销毁,甚至还能听到在后台播放。即便是像刚才那样各种销毁webview也无济于事,解决办法:在onDestory之前修改url为空地址。
f、WebView后台耗电问题。当你的程序调用了WebView加载网页,WebView会自己开启一些线程(?),如果你没有正确地将WebView销毁的话,这些残余的线程(?)会一直在后台运行,由此导致你的应用程序耗电量居高不下。对此我采用的处理方式比较偷懒,简单又粗暴(不建议),即在Activity.onDestroy()中直接调用System.exit(0),使得应用程序完全被移出虚拟机,这样就不会有任何问题了。
g、WebViewClient.onPageFinished()。你永远无法确定当WebView调用这个方法的时候,网页内容是否真的加载完毕了。当前正在加载的网页产生跳转的时候这个方法可能会被多次调用,StackOverflow上有比较具体的解释(How to listen for a Webview finishing loading a URL in Android?), 但其中列举的解决方法并不完美。所以当你的WebView需要加载各种各样的网页并且需要在页面加载完成时采取一些操作的话,可能WebChromeClient.onProgressChanged()比WebViewClient.onPageFinished()都要靠谱一些。
h、webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);//解决三星note4显示不全
i、XWalkView
j、
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
if (request.getUrl().toString() != null) {
return new WebResourceResponse("image/jpeg", "UTF-8", new ByteArrayInputStream(request.getUrl().toString().getBytes()));
} else {
return super.shouldInterceptRequest(view, request);
}
}







猜你喜欢

转载自blog.csdn.net/qq_16153851/article/details/80940380