Jetpack Compose - WebView 使用方法

6,963 阅读2分钟

🤔没有太多重要的知识点,主要是提供给大家在Compose中webView如何使用,主要是给一些『🙈不会用的童鞋』看的

1.初始化android.webkit下面的WebViewClient,WebChromeClient

val webViewChromeClient = object:WebChromeClient(){
        override fun onProgressChanged(view: WebView?, newProgress: Int) {
            super.onProgressChanged(view, newProgress)
        }
    }
val webViewClient = object: WebViewClient(){
  //复写一些方法
  ......
}

2.AndroidView内的factory返回WebView

AndroidView(modifier = modifier,factory = { ctx ->
        WebView(ctx).apply {
            this.webViewClient = webViewClient
            this.webChromeClient = webViewChromeClient
            loadUrl(url)
            //省略其他设置.....
        }
    })

3.创建一个CustomWebView的Compose方法

@Composable
fun CustomWebView(modifier: Modifier = Modifier,
                  //网络请求地址
                  url:String,
                  //自己处理返回事件
                  onBack: (webView:WebView?) -> Unit,
                  //自己选择是否接收,网页地址加载进度回调
                  onProgressChange: (progress:Int)->Unit = {},
                  //自己选择是否设置自己的WebSettings配置
                  initSettings: (webSettings:WebSettings?) -> Unit = {},
                  //自己选择是否处理onReceivedError回调事件
                  onReceivedError: (error: WebResourceError?) -> Unit = {})
 

4.CustomWebView内部实现:

  • WebChromeClient()复写:onProgressChanged(),回调onProgressChange(50)
  • WebViewClient()复写shouldOverrideUrlLoading(),onReceivedError()等
  • 创建一个BackHandler,用于回调onBack(webView)

👇👇最终CustomWebView的实现代码如下👇👇:

@Composable
fun CustomWebView(modifier: Modifier = Modifier,
                  url:String,
                  onBack: (webView:WebView?) -> Unit,
                  onProgressChange: (progress:Int)->Unit = {},
                  initSettings: (webSettings:WebSettings?) -> Unit = {},
                  onReceivedError: (error: WebResourceError?) -> Unit = {}){
    val webViewChromeClient = object:WebChromeClient(){
        override fun onProgressChanged(view: WebView?, newProgress: Int) {
            //回调网页内容加载进度
            onProgressChange(newProgress)
            super.onProgressChanged(view, newProgress)
        }
    }
    val webViewClient = object: WebViewClient(){
        override fun onPageStarted(view: WebView?, url: String?, 
            favicon: Bitmap?) {
            super.onPageStarted(view, url, favicon)
            onProgressChange(-1)
        }
        override fun onPageFinished(view: WebView?, url: String?) {
            super.onPageFinished(view, url)
            onProgressChange(100)
        }
        override fun shouldOverrideUrlLoading(
            view: WebView?,
            request: WebResourceRequest?
        ): Boolean {
            if(null == request?.url) return false
            val showOverrideUrl = request.url.toString()
            try {
                if (!showOverrideUrl.startsWith("http://")
                    && !showOverrideUrl.startsWith("https://")) {
                    //处理非http和https开头的链接地址
                    Intent(Intent.ACTION_VIEW, Uri.parse(showOverrideUrl)).apply {
                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        view?.context?.applicationContext?.startActivity(this)
                    }
                    return true
                }
            }catch (e:Exception){
                //没有安装和找到能打开(「xxxx://openlink.cc....」、「weixin://xxxxx」等)协议的应用
                return true
            }
            return super.shouldOverrideUrlLoading(view, request)
        }

        override fun onReceivedError(
            view: WebView?,
            request: WebResourceRequest?,
            error: WebResourceError?
        ) {
            super.onReceivedError(view, request, error)
            //自行处理....
            onReceivedError(error)
        }
    }
    var webView:WebView? = null
    val coroutineScope = rememberCoroutineScope()
    AndroidView(modifier = modifier,factory = { ctx ->
        WebView(ctx).apply {
            this.webViewClient = webViewClient
            this.webChromeClient = webViewChromeClient
            //回调webSettings供调用方设置webSettings的相关配置
            initSettings(this.settings)
            webView = this
            loadUrl(url)
        }
    })
    BackHandler {
        coroutineScope.launch {
            //自行控制点击了返回按键之后,关闭页面还是返回上一级网页
            onBack(webView)
        }
    }
}

5.CustomWebView调用方法如下:

onProgressChange: (progress:Int)、 initSettings: (webSettings:WebSettings?)、 onReceivedError: (error: WebResourceError?) 这三个回调都是可选的,按需使用

var rememberWebProgress: Int by remember { mutableStateOf(-1)}
//用Box包裹一下CustomWebView和LinearProgressIndicator
//这样打开网页顶部就可以显示加载的进度了
CustomWebView(modifier = Modifier.fillMaxSize(),
              url = "https://www.baidu.com/",
               onProgressChange = {progress ->
                  rememberWebProgress = progress
               },
               initSettings = {settings->
                    settings?.apply {
                      //支持js交互
                      javaScriptEnabled = true
                      //....
                    }
                }, onBack = { webView ->
                     //可根据需求处理此处
                     if (webView?.canGoBack() == true) {
                         //返回上一级页面
                         webView.goBack()
                      } else {
                         //关闭activity
                         finish()
                      }
                 },onReceivedError = {
                      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            Log.d(TAG,">>>>>>${it?.description}")
                       }
                 })
                 
LinearProgressIndicator(
        progress = rememberWebProgress * 1.0F / 100F,
        color = Color.Red,
        modifier = Modifier
              .fillMaxWidth()
              .height(if (rememberWebProgress == 100) 0.dp else 5.dp))

6.完整代码和调用方法(前往Github查看)

CustomWebView.kt