webview选择图片、拍照、选择视频、录像、选择文件

86 阅读2分钟
open class BaseWebChromeClient(
    var activity: FragmentActivity? = null,
    val fragment: Fragment? = null,
) : WebChromeClient() {
    private var mFilePathCallback: ValueCallback<Array<Uri>>? = null
    private var imageUri: Uri? = null
    override fun onShowFileChooser(
        webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?
    ): Boolean {
        filePathCallback ?: return false
        if (mFilePathCallback != null) {
            mFilePathCallback = null
        }
        mFilePathCallback = filePathCallback
        val acceptTypes = fileChooserParams?.acceptTypes ?: emptyArray()
        val isVideoType = acceptTypes.any { it.contains("video") }
        val isImageType = acceptTypes.any { it.contains("image") }
        LogUtil.i("onShowFileChooser", "isVideoType:$isVideoType ,isImageType:$isImageType ")
        val fileType = when {
            isVideoType && isImageType -> arrayListOf("选择图片", "拍照", "选择视频", "录制视频")
            isVideoType -> arrayListOf("选择视频", "录制视频")
            isImageType -> arrayListOf("选择图片", "拍照")
            else -> arrayListOf("选择文件")
        }
        showMediaChoiceDialog(fileType)
        return true
    }

    private fun showMediaChoiceDialog(arrayListOf: ArrayList<String>) {
        val bottomItemDialog = BottomItemPicDialog(arrayListOf, "请选择", listener = {
            when (it) {
                "选择图片" -> openFileChooseProcess("image/*", "图片选择")
                "选择视频" -> openFileChooseProcess("video/*", "视频选择")
                "选择文件" -> openFileChooseProcess("*/*", "文件选择")
                "拍照" -> captureImageFromCamera()
                "录制视频" -> captureVideoFromCamera()
            }
        }, onCancel = {
            mFilePathCallback?.onReceiveValue(null)
            mFilePathCallback = null
        })
        activity?.showFragmentDialog(bottomItemDialog)
    }

    override fun onPermissionRequest(request: PermissionRequest?) {
        request?.grant(request.resources)
    }

    private fun openFileChooseProcess(typeStr: String, titleStr: String) {
        val i = Intent(Intent.ACTION_GET_CONTENT)
        i.addCategory(Intent.CATEGORY_OPENABLE)
        i.type = typeStr
        if (fragment != null) {
            fragment.startActivityForResult(
                Intent.createChooser(i, titleStr), Constants.OPEN_FILE_CHOOSE_REQUEST_CODE
            )
        } else activity?.startActivityForResult(
            Intent.createChooser(i, titleStr), Constants.OPEN_FILE_CHOOSE_REQUEST_CODE
        )
    }

    /**
     * 拍照
     */
    private fun captureImageFromCamera(): Boolean {
        var cacheDir: File? = null
        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            cacheDir = File(CommonModule.getContext().externalCacheDir, "images")
        }
        if (cacheDir == null) {
            cacheDir = File(CommonModule.getContext().cacheDir, "images")
        }
        if (!cacheDir.exists()) {
            cacheDir.mkdirs()
        }
        val outFile = File(cacheDir, System.currentTimeMillis().toString() + ".jpg")
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { //如果api大于Android api23 要替换获取文件Uri方式
            //此方法第二个参数authority的值要用项目中的值来替换,可网上找Android 7.0 FileProvider相关介绍
            imageUri = FileProvider.getUriForFile(
                CommonModule.getContext(), CommonModule.getContext().packageName + ".fileProvider", outFile
            )

            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
            intent.addFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
            )
        } else {
            imageUri = Uri.fromFile(outFile)
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
            intent.addCategory(Intent.CATEGORY_DEFAULT)
        }
        if (ContextCompat.checkSelfPermission(
                CommonModule.getContext(), Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
                CommonModule.getContext(), Manifest.permission.READ_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED
        ) { //有相机权限
            startCameraForResult(intent)
        } else {
            activity?.requestPermissions(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, denied = {
                mFilePathCallback?.onReceiveValue(null)
                mFilePathCallback = null
            }, block = {
                startCameraForResult(intent)
                LogUtils.e("相机权限申请成功")
            })
        }
        return false
    }

    private fun startCameraForResult(intent: Intent) {
        try {
            val packageManager: PackageManager? = CommonModule.getContext().packageManager
            if (packageManager?.let { intent.resolveActivity(it) } != null) {

                if (fragment != null) {
                    fragment.startActivityForResult(
                        intent, Constants.REQUEST_CODE_RECORDER_IMAGE
                    )
                } else activity?.startActivityForResult(
                    intent, Constants.REQUEST_CODE_RECORDER_IMAGE
                )
            }
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            mFilePathCallback?.onReceiveValue(null)
            mFilePathCallback = null
        }
    }

    /**
     * 录制视频
     */
    private fun captureVideoFromCamera() {
        var cacheDir: File? = null
        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            cacheDir = File(CommonModule.getContext().externalCacheDir, "video")
        }
        if (cacheDir == null) {
            cacheDir = File(CommonModule.getContext().cacheDir, "video")
        }
        if (!cacheDir.exists()) {
            cacheDir.mkdirs()
        }
        val outFile = File(cacheDir, System.currentTimeMillis().toString() + ".mp4")
        val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { //如果api大于Android api23 要替换获取文件Uri方式
            //此方法第二个参数authority的值要用项目中的值来替换,可网上找Android 7.0 FileProvider相关介绍
            val uri = FileProvider.getUriForFile(
                CommonModule.getContext(), CommonModule.getContext().packageName + ".fileProvider", outFile
            )

            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) //加入flag
        } else {
            val uri = Uri.fromFile(outFile)
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
            intent.addCategory(Intent.CATEGORY_DEFAULT)
        }
        //调系统相机拍摄视频需要用到相机权限,先判断有没有这个权限
        if (ContextCompat.checkSelfPermission(
                CommonModule.getContext(), Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
                CommonModule.getContext(), Manifest.permission.READ_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
                CommonModule.getContext(), Manifest.permission.RECORD_AUDIO
            ) == PackageManager.PERMISSION_GRANTED
        ) { //有相机权限
            startVideoForResult(intent)
        } else {
            activity?.requestPermissions(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO, denied = {
                mFilePathCallback?.onReceiveValue(null)
                mFilePathCallback = null
            }, block = {
                startVideoForResult(intent)
                LogUtils.e("相机权限申请成功")
            })
        }
    }

    private fun startVideoForResult(intent: Intent) {
        try {
            val packageManager: PackageManager? = CommonModule.getContext().packageManager
            if (packageManager?.let { intent.resolveActivity(it) } != null) {
                if (fragment != null) {
                    fragment.startActivityForResult(
                        intent, Constants.OPEN_FILE_CHOOSE_REQUEST_CODE
                    )
                } else activity?.startActivityForResult(
                    intent, Constants.OPEN_FILE_CHOOSE_REQUEST_CODE
                )
            }
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            mFilePathCallback?.onReceiveValue(null)
            mFilePathCallback = null
        }
    }

    fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        //将拍摄的照片或者视频回调给H5
        if (mFilePathCallback == null) {
            return
        }
        when (resultCode) {
            Activity.RESULT_OK -> {
                if (requestCode == Constants.OPEN_FILE_CHOOSE_REQUEST_CODE) {
                    // 从data Intent中获取Uri
                    val result = if (data == null || data.data == null) {
                        arrayOfNulls<Uri>(0)
                    } else {
                        data.clipData?.let { clipData ->
                            Array(clipData.itemCount) { i ->
                                clipData.getItemAt(i).uri
                            }
                        } ?: arrayOf(data.data!!)
                    }

                    mFilePathCallback!!.onReceiveValue(result)
                } else if (requestCode == Constants.REQUEST_CODE_RECORDER_IMAGE) {
                    val uri = imageUri //拍照片data不会返回uri,用之前暂存下的
                    mFilePathCallback?.onReceiveValue(arrayOf(uri ?: Uri.parse("")))
                }
                mFilePathCallback = null
            }

            Activity.RESULT_CANCELED -> {
                mFilePathCallback!!.onReceiveValue(null)
                mFilePathCallback = null
            }
        }
    }
}