Android:WebView全面总结
1.为何使用WebView?
我们先来探讨一下,为何好端端的一个app,嵌入了WebVIew这种控件。
WebVIew控件带来的好处:
- 复用性高。 只需要写一次 HTML5 代码,就可以在 Android 和 iOS 平台上运行,这就是所谓的「 跨平台 」。
- 动态更新。 由于页面是由HTML5实现的,出现的大部分改动问题,只需要修改服务器对应的HTML5页面,而不需要移动端重新打包编译上架。
但为什么它并没有被广泛地使用呢?
WebVIew控件使用的缺点:
- 兼容性差。 由于Android版本碎片化严重,无法很好的向下兼容,运行效率不一。
- 内存泄露。 webView内部的一些线程持有activity对象,导致activity无法释放。继而内存泄漏。
- 加载速度慢。 加载速度比原生慢上许多,造成了不好的用户体验。
适用场景:
- 简单的界面,不涉及复杂功能。 因为涉及到一些比较复杂的需求,依赖WebVIew,交互过多,对性能和兼容性的要求较高。
2.如何使用WebView?
2.1 基本用法
(1)获取网络权限
(2)XML文件:
<?xml version="1.0" encoding="utf-8"?>
(3)代码实现:
class WebViewActivity:Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.layout_webview) wv.loadUrl("https://blog.csdn.net/QQ1010110087") }}
(4)实现效果:
- 点击其中的链接,默认会跳转到网页显示,而不是在WebVIew上直接显示。
原因
- 不提供WebVIewClient,默认情况下,WebView将要求Activity Manager 为URL选择适合的处理程序。
- 提供了WebVIewClient,如果shouldOverrideUrlLoading方法
返回true,宿主应用程序处理URL,返回false,WebView处理URL。
因此,在WebVIew上显示,需要设置WebViewClient对象
class WebViewActivity:Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.layout_webview) wv.loadUrl("https://blog.csdn.net/QQ1010110087") //设置WebViewClient对象 wv.webViewClient= WebViewClient() ; }
2.1.1 获取并显示标题栏
class WebViewActivity:Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.layout_webview) wv.loadUrl("https://blog.csdn.net/QQ1010110087") //设置WebViewClient wv.webViewClient= WebViewClient() ; //设置WebChromeClient wv.webChromeClient = object : WebChromeClient() { //获取HTML标题 override fun onReceivedTitle(view: WebView?, title: String?) { tvTitle.setText(title) super.onReceivedTitle(view, title) } } }}
2.1.2 WebViewClient和WebChromeClient用法
我们在处理URL和获取标题栏,分别使用到了WebViewClient、WebChromeClient.
Android应用开发的时候可能会用到WebView这个组件,使用过程中可能会接触到WebViewClient与WebChromeClient,那么这两个类到底有什么不同呢?
WebViewClient主要帮助WebView处理各种通知、请求事件的,比如:
- onLoadResource
- onPageStart
- onPageFinish
- onReceiveError
- onReceivedHttpAuthRequest
WebChromeClient主要辅助WebView处理Javascript的对话框、网站图标、网站title、加载进度等比如
- onCloseWindow(关闭WebView)
- onCreateWindow()
- onJsAlert (WebView上alert无效,需要定制WebChromeClient处理弹出)
- onJsPrompt
- onJsConfirm
- onProgressChanged
- onReceivedIcon
- onReceivedTitle
看上去他们有很多不同,实际使用上:
- 如果你的WebView只是用来处理一些html的页面内容,只用WebViewClient就行了。
- 如果需要更丰富的处理效果,比如JS、进度条等,就要用到WebChromeClient。
2.1.3 WebViewClient和WebChromeClient简单使用
wv.webViewClient = object : WebViewClient() { override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { Log.v("WebViewActivity", "onPageStarted") super.onPageStarted(view, url, favicon) } override fun onPageFinished(view: WebView?, url: String?) { Log.v("WebViewActivity", "onPageFinished") super.onPageFinished(view, url) } } wv.webChromeClient = object : WebChromeClient() { //获取HTML标题 override fun onReceivedTitle(view: WebView?, title: String?) { Log.v("WebViewActivity", "onReceivedTitle:title=" + title) super.onReceivedTitle(view, title) } } wv.loadUrl("https://blog.csdn.net/QQ1010110087")
打印日志:
2.2 WebView下载文件
//允许与JS进行交互 wv.settings.javaScriptEnabled=true //加载百度手机助手页面 wv.loadUrl("https://shouji.baidu.com/appsearch/") //设置下载监听事件 wv.setDownloadListener(object:DownloadListener{ override fun onDownloadStart( url: String?, userAgent: String?, contentDisposition: String?, mimetype: String?, contentLength: Long ) { //限制加载文件为apk或带有.apk url?.run { if(contains(".apk")){ val uri=Uri.parse(url) //调用系统自带的下载界面 val intent=Intent(Intent.ACTION_VIEW,uri) startActivity(intent) } } } })
- 在onDownloadStart方法中,我们也可以自己利用流去下载保存文件。
2.3 WebView与Js交互
2.3.1 Android调用Js方法
- WebView的loadUrl()方法
html页面:
webview Hello world! This is WebView Test
在app/src/main目录下,创建assets目录,复制这个html文件到这个目录下。
XML文件:
<?xml version="1.0" encoding="utf-8"?>
代码实现:
class WebViewActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.layout_webview) /** * 调用Js方法 */ callJSMethod() } fun callJSMethod() { /** * file:///android_asset 代表app/src/main/assets这个目录 */ wv.loadUrl("file:///android_asset/index.html") //允许与Js交互 wv.settings.javaScriptEnabled = true wv.settings.javaScriptCanOpenWindowsAutomatically = true wv.webChromeClient = object : WebChromeClient() { override fun onReceivedTitle(view: WebView?, title: String?) { super.onReceivedTitle(view, title) //设置标题栏标题 tvTitle.setText(title) } //拦截Js的alert方法,可在该方法内重写alert的布局实现 override fun onJsAlert(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean { val alertDialog = AlertDialog.Builder([email protected]) alertDialog.setTitle("onJsAlert") alertDialog.setMessage(message) alertDialog.setPositiveButton("确认", object : DialogInterface.OnClickListener { override fun onClick(dialog: DialogInterface?, which: Int) { //dialog.dismiss() 若调用这个方法而不调用result的confirm方法,会出现只能调用一次警告框的情况 result?.confirm() } }) alertDialog.setCancelable(false) alertDialog.show() return true } } btCallJS.setOnClickListener { wv.loadUrl("javascript:callJs()") } }}
效果图:
- 需要在每次调完onJsAlert后设置参数JsResult调用cancel()或者confirm()方法,否则再去调用时,警告框不会出现。
2.3.2 JS调用Android方法
- WebView的addJavascriptInterface()方法 对象映射
addJavascriptInterface(obj:Object, interfaceName:String)
(1)HTML页面添加button回调android方法
webview Hello world! This is WebView Test
(2)根据HTML中的对象名和对象方法设置对象名称和对象回调方法
class WebViewActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.layout_webview) callAndroidSetting() } fun callAndroidSetting(){ //对象为该activity,该activity对应html文件中wvActivity对象 wv.settings.javaScriptEnabled=true wv.loadUrl("file:///android_asset/index.html") wv.addJavascriptInterface(this,"wvActivity") } @JavascriptInterface fun androidMethod(jsParams:String){ Log.v("WebViewActivity","androidMethod:"+jsParams) } }
(3)实现效果
点击Button,打印日志如下:
2.4 处理系统返回键
问题:系统返回键,调用的是Activity的finish方法,而不是页面的回退操作。
解决方案:Activity的onBackPressed方法中判断webview是否有上一个页面?
- 有,则返回到上一个HTML页面。
- 没有,则执行父类方法。
override fun onBackPressed() { if (wv.canGoBack()) { wv.goBack() }else super.onBackPressed() }
2.4 WebView的Cookie处理
- 获取CookieSyncManager
CookieSyncManager.createInstance(this); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true);
- 设置Cookie
//帐号的cookie设置规则 String mCookie = "wv.token=xxxxxxx"; //设置Cookie cookieManager.setCookie(Url, mCookie); //同步Cookie CookieSyncManager.getInstance().sync();
- 获取Cookie
String mCookie = cookieManager.getCookie(Url);
- 清除Cookie
cookieManager.removeAllCookie(); CookieSyncManager.getInstance().sync();
总结
后续待补充。
更多相关文章
- 安全新手入坑——HTML标签
- Nginx系列教程(四)| 一文带你读懂Nginx的动静分离
- android - ui 研究,QQ登陆篇
- Android中AsyncTask与handler用法实例分析
- Android(安卓)中不同项目共用通用库Module方法
- 基于android的Socket通信
- Android中BroadcastReceiver的运用
- Canvas和Drawable
- Android操作JNI函数以及复杂对象传递