WebView是一个基于WebKit引擎、展现Web页面的控件,Android的WebView在低版本和高版本采用了不同的WebKit版本内核

基本使用

WebView的最简单的使用方式即是直接显示网页内容,首先别忘了添加网络权限

<uses-permission android:name="android.permission.INTERNET" />
  <WebView        android:id="@+id/webview"        android:layout_width="match_parent"        android:layout_height="match_parent" />
   webview.loadUrl("http://www.baidu.com")        webview.webViewClient = object : WebViewClient() {            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {                //在本WebView中直接显示网页                view.loadUrl(url)                return true            }        }

WebView常用方法

状态

webview.onResume() //激活WebView为活跃状态,能正常执行网页的响应 webview.onPause() //当页面被失去焦点被切换到后台不可见状态,执行webview.pauseTimers() //当应用程序(存在webview)被切换到后台时,这个方法针对的是全局的webview,它会暂停所有webview的布局显示、解析、延时,从而降低CPU功耗webview.resumeTimers() //恢复pauseTimers状态//销毁webview,先从父容器移除,再销毁father.removeView(webview)webview.destroy() 

前进或后退网页

//是否可以后退webview.canGoBack()//后退网页webview.goBack()//是否可以前进webview.canGoForward()//前进网页webview.goForward()//以当前的index为起始点前进或者后退到历史记录中指定的steps//如果steps为负数则为后退,正数则为前进webview.goBackOrForward(steps)

常见用法:在Activity中处理该Back键事件

  override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {        if ((keyCode == KEYCODE_BACK) && webview.canGoBack()) {            webview.goBack()            return true        }        return super.onKeyDown(keyCode, event)    }

清除缓存

//由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.webview.clearCache(true)//清除当前webview访问的历史记录webview.clearHistory()//这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据webview.clearFormData()

WebSettings类
作用:对WebView进行配置和管理
下面是一些常规设置

 val webSettings: WebSettings = webview.settings        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { //解决网页中图片显示不出问题            webSettings.mixedContentMode = WebSettings.LOAD_DEFAULT        }        webSettings.javaScriptEnabled = true //支持JS        webSettings.domStorageEnabled = true //支持DOM Storage        webSettings.defaultTextEncodingName = "utf-8" //设置编码格式        webSettings.pluginState = WebSettings.PluginState.ON// 支持插件        webSettings.loadsImagesAutomatically = true //支持自动加载图片        webSettings.setSupportZoom(true) //支持缩放,默认为true。是下面那个的前提。        webSettings.builtInZoomControls = true //设置内置的缩放控件。若为false,则该WebView不可缩放        webSettings.displayZoomControls = false //隐藏原生的缩放控件        webSettings.databaseEnabled = true // 数据库存储API是否可用        webSettings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN //WebView底层布局算法        webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //设置缓存,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。本地没有缓存时才从网络上获取        webSettings.allowFileAccess = true //设置可以访问文件        webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口        //设置自适应屏幕,两者合用        webSettings.useWideViewPort = true //将图片调整到适合WebView的大小        webSettings.loadWithOverviewMode = true // 缩放至屏幕的大小

WebViewClient类
作用:处理各种通知、请求事件
(1)shouldOverrideUrlLoading()
作用:打开网页时,不调用系统浏览器进行打开,而是在本WebView中直接显示
(2)onPageStarted()
作用:开始载入页面时调用此方法,在这里我们可以设定一个loading的页面,告诉用户程序正在等待网络响应
(3)onPageFinished()
作用:在页面加载结束时调用,我们可以关闭loading 条,切换程序动作
(4)onLoadResource()
作用:在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次
(5)onReceivedSslError()
作用:处理https请求,WebView默认是不处理https请求的,页面显示空白

 webview.webViewClient = object : WebViewClient() {            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {                //使用WebView加载显示url                view.loadUrl(url)                return true            }            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {                //设定加载开始的操作            }            override fun onPageFinished(view: WebView?, url: String?) {                //设定加载结束的操作            }            override fun onLoadResource(view: WebView?, url: String?) {                //设定加载资源的操作            }            override fun onReceivedError(                view: WebView?,                errorCode: Int,                description: String?,                failingUrl: String?            ) {                when (errorCode) {                    HttpStatus.NOT_FOUND -> view!!.loadUrl("file:///android_assets/error_handle.html")                }            }            override fun onReceivedSslError(                view: WebView?,                handler: SslErrorHandler?,                error: SslError?            ) {                // 接受所有网站的证书,忽略SSL错误,执行访问网页                handler?.proceed()//                handler?.cancel() //表示挂起连接,为默认方式//                handler?.handleMessage(msg!!) //可做其他处理            }        }

WebChromeClient类
作用:辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等
(1)onProgressChanged()
作用:获得网页的加载进度并显示
(2)onReceivedTitle()
作用:获取Web页中的标题

      webview.webChromeClient = object : WebChromeClient() {            override fun onProgressChanged(view: WebView?, newProgress: Int) {                if (newProgress < 100)                    progressbar.text = "${newProgress}%"                else                    progressbar.text = "100%"            }            override fun onReceivedTitle(view: WebView?, title: String?) {                title_text.text = title            }        }

WebView与JS的交互

Android通过WebView调用 JS 代码

注意:JS代码调用一定要在 onPageFinished() 回调之后才能调用,否则不会调用

(1)通过WebView的loadUrl()

        // 先载入JS代码        webview.loadUrl(url)        // 调用javascript的callJS()方法,注意调用的JS方法名要对应上        webview.loadUrl("javascript:callJS()")

(2)通过WebView的evaluateJavascript()
该方法比第一种方法效率更高、使用更简洁。因为该方法的执行不会使页面刷新,而第一种方法(loadUrl)会,该方法在Android 4.4 后才可使用,不过现在的安卓版本都在4.4以上了,所以这点不用在意了。如果需要返回值的话,请务必使用这个方法

  webview.evaluateJavascript("javascript:callJS()", object : ValueCallback<String> {            override fun onReceiveValue(p0: String?) {                //此处为 js 返回的结果            }        })

JS通过WebView调用 Android 代码
(1)通过WebView的addJavascriptInterface()进行对象映射

    //定义一个内部类    inner class AndroidJSInterFace{        // 定义JS需要调用的方法,被JS调用的方法必须加入@JavascriptInterface注解        @JavascriptInterface        fun hello(msg: String?) {            runOnUiThread{                title_text.text=msg            }        }    }
        //AndroidJSInterFace类对象映射到js的test对象        webview.addJavascriptInterface(AndroidJSInterFace(), "test") 

(2)在Android通过WebViewClient复写shouldOverrideUrlLoading()

     webview.webViewClient = object : WebViewClient() {            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {                // 根据协议的参数,判断是否是所需要的url                // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)                //假如约定好的传入进来的url = "js://webview?arg1=111&arg2=222"                val uri = Uri.parse(url)                if (uri.scheme == "js" && uri.authority == "webview") {                    // 执行JS所需要调用的逻辑                    Log.d("TestLog", "js调用了Android的方法")                    // 也可以在协议上带有参数并传递到Android上                    val collection = uri.queryParameterNames                }                return true            }        }

如果JS想要得到Android方法的返回值,只能通过 WebView 的 loadUrl ()去执行 JS 方法把返回值传递回去,相关的代码如下:

 webview.loadUrl("javascript:returnResult($result)")

(3)通过 WebChromeClient 的onJsAlert()、onJsConfirm() 、onJsPrompt() 方法回调拦截JS对话框alert()、confirm()、prompt()消息

常用的拦截是:拦截 JS的prompt()方法
因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活,而alert()没有返回值,confirm()只能返回两种状态(确定 / 取消)两个值

     webview.webChromeClient = object : WebChromeClient() {            override fun onJsPrompt(                view: WebView?,                url: String?,                message: String?,                defaultValue: String?,                result: JsPromptResult?            ): Boolean { //输入框                // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)                //假定传入进来的需要拦截的 url = "js://webview?arg1=111&arg2=222"                val uri = Uri.parse(message)                if (uri.scheme == "js" && uri.authority == "webview") {                    // 执行JS所需要调用的逻辑                    Log.d("WebviewTest", "js调用了Android的方法")                    // 可以在协议上带有参数并传递到Android上                    val collection = uri.queryParameterNames                    //参数result:代表消息框的返回值(输入值)                    result!!.confirm("js调用了Android的方法成功啦")                    return true                }                return super.onJsPrompt(view, url, message, defaultValue, result)            }            override fun onJsAlert(                view: WebView?,                url: String?,                message: String?,                result: JsResult?            ): Boolean { //警告框                return super.onJsAlert(view, url, message, result)            }            override fun onJsConfirm(                view: WebView?,                url: String?,                message: String?,                result: JsResult?            ): Boolean { //确认框                return super.onJsConfirm(view, url, message, result)            }        }

WebView调起系统相机和相册

(1)初始化需要的变量

    private var uploadMessageAboveL: ValueCallback<Array<Uri>>? = null    private var cameraFielPath: String? = null    private var uploadMessage: ValueCallback<Uri>? = null
   webview.webChromeClient = object :WebChromeClient(){            override fun onShowFileChooser(                webView: WebView?,                filePathCallback: ValueCallback<Array<Uri>>?,                fileChooserParams: FileChooserParams?            ): Boolean {                uploadMessageAboveL = filePathCallback                openImageChooserActivity()                return true            }            // For Android < 3.0            fun openFileChooser(valueCallback: ValueCallback<Uri>) {                uploadMessage = valueCallback                openImageChooserActivity()            }        }
    // 2.回调方法触发本地选择文件    private fun openImageChooserActivity() {        //拍照        val imageStorageDir = File(            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),            "heart_image"        )        if (!imageStorageDir.exists()) {            imageStorageDir.mkdirs()        }        cameraFielPath = imageStorageDir.toString() + File.separator + "IMG_" + System.currentTimeMillis()            .toString() + ".jpg"        val file = File(cameraFielPath)        //需要显示应用的意图列表,这个list的顺序和选择菜单上的图标顺序是相关的,请注意。        val cameraIntents: MutableList<Intent> = ArrayList()        val captureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)        val packageManager: PackageManager = packageManager        //获取手机里所有注册相机接收意图的应用程序,放到意图列表里(无他相机,美颜相机等第三方相机)        val listCam: List<ResolveInfo> = packageManager.queryIntentActivities(captureIntent, 0)        for (res in listCam) {            val packageName: String = res.activityInfo.packageName            val i = Intent(captureIntent)            i.component = ComponentName(res.activityInfo.packageName, res.activityInfo.name)            i.setPackage(packageName)            i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file))            cameraIntents.add(i)        }        //相册        val i = Intent(Intent.ACTION_GET_CONTENT)        i.action = Intent.ACTION_PICK        i.type = "image/*"        val chooserIntent = Intent.createChooser(i, "选择")        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toTypedArray())        startActivityForResult(            chooserIntent,            101        )    }
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {        super.onActivityResult(requestCode, resultCode, data)        if (requestCode == 101) {            val result = if (data == null || resultCode != Activity.RESULT_OK) null else data.data            if (uploadMessageAboveL != null) {                onActivityResultAboveL(requestCode, resultCode, data)            } else if (uploadMessage != null) {                uploadMessage?.onReceiveValue(result)                uploadMessage = null            }            if (resultCode != RESULT_OK) {                //这里uploadMessage跟uploadMessageAboveL在不同系统版本下分别持有了                //WebView对象,在用户取消文件选择器的情况下,需给onReceiveValue传null返回值                //否则WebView在未收到返回值的情况下,无法进行任何操作,文件选择器会失效                if (uploadMessage != null) {                    uploadMessage?.onReceiveValue(null)                    uploadMessage = null                } else if (uploadMessageAboveL != null) {                    uploadMessageAboveL?.onReceiveValue(null)                    uploadMessageAboveL = null                }            }        }    }
    // 4. 选择内容回调到Html页面    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    fun onActivityResultAboveL(requestCode: Int, resultCode: Int, intent: Intent?) {        if (requestCode != 101 || uploadMessageAboveL == null)            return        var results = arrayOf<Uri>()        var result: Uri? = null        if (resultCode == Activity.RESULT_OK) {            if (intent != null) {                var dataString = intent.dataString                var clipData = intent.clipData                if (clipData != null) {                    for (i in 0 until clipData.itemCount) {                        var itemAt = clipData.getItemAt(i)                        results[i] = itemAt.uri                    }                }                if (dataString != null) {                    results = arrayOf<Uri>(Uri.parse(dataString))                }                uploadMessageAboveL?.onReceiveValue(results)                uploadMessageAboveL = null            } else { //                if (result == null && File(cameraFielPath).exists()) {                    result = Uri.fromFile(File(cameraFielPath))                }                uploadMessageAboveL?.onReceiveValue(arrayOf(result!!))                uploadMessageAboveL = null            }        }    }

WebView响应下载点击事件

 webview.setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->            val uri = Uri.parse(url)            val intent = Intent(Intent.ACTION_VIEW, uri)            startActivity(intent)        }

更多相关文章

  1. Activity类的runOnUiThread方法
  2. 我的javaSE学习笔记
  3. android之数据库和Content Provider(二)
  4. android 面试经典(4)
  5. Android进程间通讯——AIDL
  6. android Camera api1和api2学习笔记
  7. Android之AppWidgetProvider
  8. Android音频数据传输
  9. 调用android系统相机拍照并保存图片

随机推荐

  1. 【Android】NDK中log输出方法
  2. Android:多分辨率适配
  3. Android(安卓)Studio 使用svn/git添加ign
  4. Android之XML序列化和解析
  5. android 获取应用程序包名,图标,入口Activi
  6. ContentProvider原理分析二 MediaProvide
  7. Android开发之通知栏
  8. Android(安卓)EditText输入最大长度限制
  9. Android(安卓)Studio将程序中的文言生成
  10. Unity3D 与Android(安卓)相互传递消息