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();

总结

后续待补充。

更多相关文章

  1. 安全新手入坑——HTML标签
  2. Nginx系列教程(四)| 一文带你读懂Nginx的动静分离
  3. android - ui 研究,QQ登陆篇
  4. Android中AsyncTask与handler用法实例分析
  5. Android(安卓)中不同项目共用通用库Module方法
  6. 基于android的Socket通信
  7. Android中BroadcastReceiver的运用
  8. Canvas和Drawable
  9. Android操作JNI函数以及复杂对象传递

随机推荐

  1. 「Android」使用SAF打开指定目录
  2. Android(安卓)APP--建立简单的交互界面
  3. android手势识别总结
  4. Android(安卓)显示刷新频率的实现代码
  5. android欢迎界面并执行任务
  6. Error:Error convertingbytecodetodex:Ca
  7. 第三方应用放在/system/preloadapp/下,开
  8. android历史版本对应的api等级
  9. Android(安卓)解决Toast的延时显示问题
  10. SMS Library in Android