Compose实现webView文件选择

最近在用compose重构公司的主要APP,由于compose的一些独特设计理念,开发中也遇到很多问题,大多数甚至网上找不到相关资料,只好自己查阅有些晦涩难懂的官方文档,摸索着解决,并记录下来,有需要的可以提供参考。

以前实现webView文件选择都是用Activity.startActivityForResult 和 onActivityResult回调,但是这两个方法由于存在安全问题,现在官方准备弃用,不推荐使用了,推荐使用registerForActivityResult 和 ActivityResultLauncher.lauch()方法来实现

一、compose中使用webView

这部分内容不是本篇文章重点,就不展开介绍了,可以参考网上其他文章,例如:Jetpack Compose - WebView 使用方法,或者直接看wanAndroid大佬的compose版wanAndroid的源码,文章地址:Compose+MVI+Navigation实现wanAndroid客户端,结构非常清楚

二、配置webSettings

注意要开启javaScriptEnabled

	@SuppressLint("SetJavaScriptEnabled")
    private fun setWebSettings() {
        val webSettings = webView.settings
        //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
        webSettings.javaScriptEnabled = true
        //设置自适应屏幕,两者合用
        webSettings.useWideViewPort = true //将图片调整到适合webview的大小
        webSettings.loadWithOverviewMode = true // 缩放至屏幕的大小
        //缩放操作
        webSettings.setSupportZoom(true) //支持缩放,默认为true。是下面那个的前提。
        webSettings.builtInZoomControls = true //设置内置的缩放控件。若为false,则该WebView不可缩放
        webSettings.displayZoomControls = false //隐藏原生的缩放控件

        webSettings.domStorageEnabled = true // 开启 DOM storage API 功能

        //其他细节操作
        webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //关闭webview中缓存
        webSettings.allowFileAccess = true //设置可以访问文件
        webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口
        webSettings.loadsImagesAutomatically = true //支持自动加载图片
        webSettings.defaultTextEncodingName = "UTF-8"//设置编码格式
    }

三、配置WebViewChromeClient

注意:重写onShowFileChooser()方法,该方法在Android5.0以前还有两个老版本,但是我项目minSDK > 23所以就重写这一个版本就好了

	private var uploadMessageAboveL: ValueCallback<Array<Uri>>? = null
	
	inner class ProgressWebViewChromeClient : WebChromeClient() {
        override fun onProgressChanged(view: WebView?, newProgress: Int) {
            super.onProgressChanged(view, newProgress)
            progressBar.progress = newProgress
        }

        override fun onReceivedTitle(view: WebView?, title: String?) {
            super.onReceivedTitle(view, title)
        }

        override fun onShowFileChooser(
            webView: WebView?,
            filePathCallback: ValueCallback<Array<Uri>>?,
            fileChooserParams: FileChooserParams?
        ): Boolean {
            uploadMessageAboveL = filePathCallback
            MyApp.imageResultLauncher.launch("image/*")
            return true
        }
    }

四、注册ResultLauncher

我是在Application中创建和持有,在Activity的onCreate中注册

由于框架结构性能等原因,compose推荐只有一个Activity,我的项目中因为需要集成微信登陆,所以只有一个WxEntryActivity作为主Activity

@HiltAndroidApp
class MyApp: Application() {

    companion object {
        @SuppressLint("StaticFieldLeak")
        lateinit var CONTEXT: Context

        //创建ActivityResultLauncher,用于接收onActivityResult的回调信息
        lateinit var imageResultLauncher: ActivityResultLauncher<String>

        //将ActivityResultLauncher的回调信息传递给MutableLiveData,并在web组件中监听该LiveData
        val imageResult: MutableLiveData<List<Uri>> = MutableLiveData()

    }

    override fun onCreate() {
        super.onCreate()
        CONTEXT = this
    }
}
@AndroidEntryPoint
class WXEntryActivity : ComponentActivity() {

    companion object {
        const val TAG = "WXEntryActivity"

        //因为只有这一个Activity,所以可以作为全局的lifeCycleOwner
        lateinit var instant: WXEntryActivity
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ...
        }
        instant = this

        //注册图片选择器
        imageResultLauncher = registerForActivityResult(ActivityResultContracts.GetMultipleContents()) {
            //获取到了图片,传递给LiveData
            LogUtils.i("WXEntryActivity", "resultLauncher: $it")
            imageResult.value = it
        }
    }
}

五、创建result的LiveData或者flow来设置(发送)和观察(接受)数据

在上一步代码中可以看到,我也是在Application中创建和持有imageResult这个LiveData

然后在注册的图片选择器结果回调中更新数据

最后在webViewCtrl中监听数据变化,并调用uploadMessageAboveL 的 onReceiveValue 回调。其中uploadMessageAboveL 是啥不清楚的见第三步,在onShowFileChooser中将filePathCallBack引用给它

	private fun initObserver() {
        LogUtils.d("WebViewCtrl", "initObserver")
        MyApp.imageResult.observe(WXEntryActivity.instant){
            LogUtils.d("WebViewCtrl", "observe: $it")
            uploadMessageAboveL?.onReceiveValue(it.toTypedArray())
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值