当前位置:首页 » 《随便一记》 » 正文

H5获取手机相机或相册图片两种方式-Android通过webview传递多张照片给H5

25 人参与  2024年02月28日 14:41  分类 : 《随便一记》  评论

点击全文阅读


需求目的: 手机机通过webView展示H5网页,在特殊场景下,需要使用相机拍照或者从相册获取照片,上传后台。

完整流程效果: 如下图
H5调用相机相册使用组件库方式流程

一、H5界面样例代码

使用html文件格式,文件直接打开就可以展示布局;一会在andriod webview中直接加载

<!DOCTYPE html><html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Document</title></head><div id="app">    <h1>alllalalallalal 默认会被覆盖</h1></div><template id="why">    <div>        <h2>{{message}}</h2>        <h2>{{counter}}</h2>        <button @click="increment">+1</button>        <button @click="decrement">-1</button>        <h1 style="text-align: center;">{{ title }}</h1>        <div>            <h2 style="text-align: center;">android选中照片H5展示</h2>            <!--HTML5提供了<input type="file">元素来实现选取文件的功能,在WebView表现为调用onShowFileChooser-->            <input accept="image/*" capture="camera" ref="imgFile" type="file" multiple                   @change="previewFiles">            <div id="preview">                <img v-for="imgSrc in imageSources" :src="imgSrc" :key="imgSrc"                     style="max-width: 100px; max-height: 100px; margin: 10px;">            </div>        </div>    </div></template><body><!-- 引入 Vue 3 的 CDN 资源网络加载不了 --><!-- <script src="https://unpkg.com/vue@next"></script> --><!-- 引入 Vue 3 的 CDN 资源,本地引用 --><script src="vue3.2.12global.js"></script><script>        Vue.createApp({            template: '#why',            data: function () {                return {                    message: "功能开发中,敬请期待!",                    counter: 100,                    pictureSelectorContent: "相机选择结果:",                    imageSources: [] // 存储图片的数据URL                }            },            // 在你的 Vue 组件中处理 Webview 传递的数据            mounted() {                // 设置全局函数,用于接收 WebView 调用                // window.pictureSelectorResult = this.pictureSelectorResult;            },            methods: {                increment() {                    this.counter++;                    console.log("点击了+1");                },                decrement() {                    this.counter--;                    consloe.log("点击了-1");                },                startPictureSelector() {                    window.android.startPictureSelector();                },                previewFiles() {                    const files = this.$refs.imgFile.files;                    this.imageSources = [];                    for (let i = 0; i < files.length; i++) {                        const file = files[i];                        const reader = new FileReader();                        reader.onload = (e) => {                            this.imageSources.push(e.target.result);                        };                        reader.readAsDataURL(file);                    }                },            },        }).mount("#app")</script><style>        h1 {            font-size: 80px;            font-weight: bold;            margin-bottom: 20px;        }        h2 {            font-size: 20px;            font-weight: bold;            color: #C8EFD4;        }        h3 {            font-size: 10px;            font-weight: bold;            color: #C8EFD4;        }        button1 {            font-size: 60px;            padding: 10px 20px;            background-color: #007bff;            color: #fff;            border: none;            border-radius: 4px;            cursor: pointer;            margin-bottom: 20px;            margin-top: 20px;            text-align: center;            /* 将文字水平居中显示 */            display: flex;            /* 将按钮设置为flex容器 */            align-items: center;            /* 将文字在垂直方向上居中显示 */        }</style></body></html>

上述代码是前端代码,使用vue3框架展示一个基础 加减demo界面(不重要的冗余),以及 一个打开文件的按钮以及展示图片
在这里插入图片描述

其中HTML5提供了元素来实现选取文件的功能,当在WebView表现为调用onShowFileChooser后,回调图片uri列表一一获取并展示

二、Android打开相机以及相册的两种方式

方式一:android 原生方式

实际效果和流程示图
在这里插入图片描述

1.android界面逻辑代码
这边使用的是kotlin语言,使用的fragment界面展示,使用binding加载了布局,以及声明了webview组件,在webview上导入html链接,使本地H5界面展示

class VisitorFragment : Fragment() {    private lateinit var binding: FragmentVisitorBinding    lateinit var mActivity: Activity    private lateinit var mRoot: View    companion object {        const val TAG = "VisitorFragment"    }    private var mWebViewUrl: String = "file:///android_asset/vue_android_demo.html"    var mAppName = MainApplication.instance.configuration.BASE_APP_LOGIN_IDENTITY    var mSystemName = WebViewConstant.DEFAULT_SYSTEM_NAME    private var mVisitorAndroidJs: VisitorAndroidJs = VisitorAndroidJs(this)    private var mWebView: WebView? = null    var mAndroidId: String = WebViewConstant.DEFAULT_DEVICE_SIGN    var mApiKey: String = WebViewConstant.DEFAULT_API_KEY    //回传H5时使用的对象    private var mUploadCallback: ValueCallback<Array<Uri>>? = null    //拍照传递的路径uri    private var mImageUri: Uri? = null    /**     * onCreate方法是Activity生命周期的第一个回调方法     * ,当Activity被创建时被调用。     * 在这个方法中,你可以进行一些初始化的操作,比如设置布局、绑定控件、初始化数据等。     *     * @param savedInstanceState If the fragment is being re-created from     * a previous saved state, this is the state.     */    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        binding = FragmentVisitorBinding.inflate(layoutInflater)        mRoot = binding.root        //记录        val viewModel = ViewModelProvider(requireActivity())[DashboardViewModel::class.java]        viewModel.setFragment(this)        LogUtils.d(TAG, "onCreate")    }    /**     * onCreateView方法是Fragment生命周期的回调方法,     * 当Fragment创建并绘制其用户界面时被调用。     * 在这个方法中,你可以通过返回一个View对象来定义Fragment的用户界面。     * 它常用于加载布局文件、查找和初始化控件等操作。     *     * @return     */    override fun onCreateView(        inflater: LayoutInflater,        container: ViewGroup?,        savedInstanceState: Bundle?    ): View {        LogUtils.d(TAG, "onCreateView")        initView(mRoot, layoutInflater, null)        return mRoot    }    fun initView(parent: View?, inflater: LayoutInflater?, container: ViewGroup?) {        //设置当前fragment        mAndroidId = DeviceUtils.getUniqueId(mActivity)        initWebView()        mWebView?.loadUrl(mWebViewUrl)        //弹出展示链接        showToast("${getString(R.string.current_develop_environment)}$mWebViewUrl")        initData()    }    override fun onAttach(context: Context) {        super.onAttach(context)        mActivity = context as Activity    }    /**     * @param msg 内容     */    fun showToast(msg: String?) {        val activity: Activity? = activity        activity?.runOnUiThread {            Toast.makeText(                activity,                msg,                Toast.LENGTH_SHORT            ).show()        }    }    private fun initData() {    }    override fun onResume() {        super.onResume()        LogUtils.d(TAG, "onResume")    }    @SuppressLint("SetJavaScriptEnabled")    private fun initWebView() {        LogUtils.d(TAG, "initWebView")        mWebView = binding.mainWebView        mWebView?.requestFocus()        mWebView?.isHorizontalScrollBarEnabled = false        mWebView?.isVerticalScrollBarEnabled = false        val setting = mWebView?.settings        setting?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW;        setting?.javaScriptEnabled = true        //用于开启或禁用其 DOM(文档对象模型)存储功能,浏览器缓存这些数据        setting?.domStorageEnabled = true        //允许访问文件,默认允许        setting?.allowFileAccess = true        //设置不,会引起webView重新不急,默认NARROW_COLUMNS        setting?.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS        //自动缩放        setting?.setSupportZoom(true)        setting?.builtInZoomControls = true        //自适应屏幕        setting?.useWideViewPort = true        setting?.loadWithOverviewMode = true        //支持多窗口        setting?.setSupportMultipleWindows(true)        setting?.setAppCacheEnabled(true)        setting?.domStorageEnabled = true        //定位        setting?.setGeolocationEnabled(true)        //优先使用缓存数据,在缓存数据不存在的情况下才去获取网络数据        setting?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK        setting?.savePassword = false        //设置js接口        mVisitorAndroidJs.let { mWebView?.addJavascriptInterface(it, "android") }        //页面不跳转浏览器        mWebView?.webViewClient = object : WebViewClient() {            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {                LogUtils.d(TAG, "url: $url")                view.loadUrl(url)                return true            }            override fun shouldInterceptRequest(                view: WebView,                request: WebResourceRequest            ): WebResourceResponse? {                var uri = request.url                var path = uri.path                LogUtils.d(TAG, "uri: $uri, path: $path")                return super.shouldInterceptRequest(view, request)            }        }        //webView官方打开文件选取方法onShowFileChooser,把网页回传文件        mWebView?.webChromeClient = object : WebChromeClient() {            //API >=21(android 5.0.1)回调此方法            override fun onShowFileChooser(                webView: WebView?,                filePathCallback: ValueCallback<Array<Uri>>?,                fileChooserParams: FileChooserParams?            ): Boolean {                mUploadCallback = filePathCallback                //使用拍照或者打开文件                mImageUri = ChoosePhotoFile.takePhoto(mActivity)                //设置false会IllegalStateException: Duplicate showFileChooser result                return true            }        }    }    fun onActivityResultResponse(requestCode: Int, resultCode: Int, intent: Intent?) {        LogUtils.d(            TAG,            "onActivityResultResponse requestCode $requestCode, resultCode:$resultCode"        )        // 扫描二维码/条码回传        if (requestCode == ScanCodeUtils.REQUEST_CODE_SCAN && resultCode == Activity.RESULT_OK) {            LogUtils.d(TAG, "onActivityResultResponse ${intent?.extras}")            if (intent == null) {                //弹出展示链接                showToast("扫描结果为空")                return            }            //传递给js,格式是"scanCodeResult('${data.extras}')",其中单引号很重要,可能导致js script error            //codedContent是组件中定义的参数名            setEvaluateJavascript("scanCodeResult('${intent.getStringExtra("codedContent")}')")        } else if (requestCode == ChoosePhotoFile.REQUEST_CODE) {            //拍照,界面跳回后,结果文件的使用            ChoosePhotoFile.takeActivityResult(requestCode, intent, mUploadCallback, mImageUri)        }    }    @Override    override fun onDestroy() {        //防止更新dialog内存泄漏        super.onDestroy()    }    /**     * 登录成功后跳转     */    open fun loginSuccessJump() {    }    /**     * 给网页传值     * 传递给js,格式是"scanCodeResult('${data.extras}')"     * 其中单引号很重要,可能导致js script error     */    private fun setEvaluateJavascript(jspMethodAndValue: String) {        LogUtils.d(            TAG,            "setEvaluateJavascript mWebView ${mWebView}, jspMethodAndValue $jspMethodAndValue"        )        mWebView?.evaluateJavascript(jspMethodAndValue, ValueCallback<String>() {            LogUtils.d(TAG, "给网页传值为: $jspMethodAndValue")        })    }}

android layout布局

<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <WebView        android:id="@+id/main_web_view"        android:layout_width="match_parent"        android:layout_height="match_parent" /></androidx.constraintlayout.widget.ConstraintLayout>

2.获取照片的主要思路是两个方法:

webView官方打开文件选取方法onShowFileChooser,把网页回传文件
        //webView官方打开文件选取方法onShowFileChooser,把网页回传文件        mWebView?.webChromeClient = object : WebChromeClient() {            //API >=21(android 5.0.1)回调此方法            override fun onShowFileChooser(                webView: WebView?,                filePathCallback: ValueCallback<Array<Uri>>?,                fileChooserParams: FileChooserParams?            ): Boolean {                mUploadCallback = filePathCallback                //使用拍照或者打开文件                mImageUri = ChoosePhotoFile.takePhoto(mActivity)                //设置false会IllegalStateException: Duplicate showFileChooser result                return true            }        }
拍照或者相册选中后界面跳回后,使用ValueCallback<Array>回传
    fun onActivityResultResponse(requestCode: Int, resultCode: Int, intent: Intent?) {        LogUtils.d(            TAG,            "onActivityResultResponse requestCode $requestCode, resultCode:$resultCode"        ) if (requestCode == ChoosePhotoFile.REQUEST_CODE) {            //拍照或者相册选中后界面跳回后,结果文件的使用            ChoosePhotoFile.takeActivityResult(requestCode, intent, mUploadCallback, mImageUri)        }    }
以上onActivityResultResponse方法需要在actvity onActivityResult方法中使用
(因为我这里是activity嵌套fragment的,如果直接在activity使用webview就不需我这太麻烦)
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {        super.onActivityResult(requestCode, resultCode, data)        LogUtils.d(            TAG,            "onActivityResult requestCode11 $requestCode, resultCode:$resultCode"        )        //设置当前fragment        val fragment = mDashboardViewModel.fragment.value        Log.d(TAG, "fragment: $fragment")        Log.d(TAG, "fragment.isResumed: ${fragment?.isResumed}")        //界面返回时VisitorFragment还没有Resumed        if (fragment is VisitorFragment) {            val visitorFragment: VisitorFragment = fragment            visitorFragment.onActivityResultResponse(requestCode, resultCode, data)        }    }

3.打开相机和相册的工具类

object ChoosePhotoFile {    private const val TAG = "ChoosePhotoFile"    const val REQUEST_CODE: Int = 12345    fun takePhoto(activity: Activity): Uri {        //相机可以访问的公共位置才能存储,获取时需要读取文件权限        val file: String =            Environment.getExternalStorageDirectory()                .toString() + File.separator + Environment.DIRECTORY_PICTURES + File.separator        val fileName = "Image_${SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())}.jpg"        val realFile = File(file, fileName)        val imageUri = Uri.fromFile(realFile)        LogUtils.d(TAG, "realFile:$realFile, imageUri: $imageUri")        // 拍照后获取图片需要文件权限,界面跳转直接拿文件不需要权限        //检查申请读文件权限        CheckPermissionUtils.requestPermissions(            activity,            arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA)        )        //调起相机,拍一张照片        val captureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)        captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)        //调起相册,取一张照片        val photoIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)        //选择方式,拍照或者相册        val chooserIntent = Intent.createChooser(photoIntent, "Image Chooser")        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf<Parcelable>(captureIntent))        activity.startActivityForResult(chooserIntent, REQUEST_CODE)        return imageUri    }    /**     * H5针对从拍照或者相册中选中的图片做处理     * @param imageUri 拍照返回的数据,     */    fun takeActivityResult(        requestCode: Int,        intent: Intent?,        filePathCallback: ValueCallback<Array<Uri>>?,        imageUri: Uri?    ) {        if (requestCode == REQUEST_CODE) {            //从相册获取,返回的intent            if (intent != null && intent.data != null) {                var uri: Uri = intent.data as Uri                LogUtils.d(TAG, "file uri: $uri")                filePathCallback?.onReceiveValue(arrayOf<Uri>(uri))            } else {                //从拍照中获取图片,已经返回的imageUri                LogUtils.d(TAG, "take photo imageUri: $imageUri")                if (imageUri != null) {                    filePathCallback?.onReceiveValue(arrayOf<Uri>(imageUri))                } else {                    filePathCallback?.onReceiveValue(null)                }            }        }    }}
方式二:使用android 组件库是实现-朋友圈获取照片功能

实际效果和流程示图
在这里插入图片描述
1.获取照片的主要思路是两个方法-替换

webView官方打开文件选取方法onShowFileChooser,把网页回传文件
        //webView官方打开文件选取方法onShowFileChooser,把网页回传文件        mWebView?.webChromeClient = object : WebChromeClient() {            //API >=21(android 5.0.1)回调此方法            override fun onShowFileChooser(                webView: WebView?,                filePathCallback: ValueCallback<Array<Uri>>?,                fileChooserParams: FileChooserParams?            ): Boolean {                mUploadCallback = filePathCallback                //使用拍照或者打开文件//                mImageUri = ChoosePhotoFile.takePhoto(mActivity)                //模拟微信朋友圈获取照片模式                LogUtils.d(TAG,"onShowFileChooser")                PictureSelectorUtils.startPictureSelector(mActivity)                //设置false会IllegalStateException: Duplicate showFileChooser result                return true            }        }
拍照或者相册选中后界面跳回后,使用ValueCallback<Array>回传
    fun onActivityResultResponse(requestCode: Int, resultCode: Int, intent: Intent?) {        LogUtils.d(            TAG,            "onActivityResultResponse requestCode $requestCode, resultCode:$resultCode"        ) if (requestCode == PictureSelectorUtils.REQUEST_PICTURE_SELECTOR) {            LogUtils.d(TAG, "onActivityResultResponse REQUEST_PICTURE_SELECTOR")            PictureSelectorUtils.takeActivityResult(requestCode, intent, mUploadCallback)        }    }

2.打开相机和相册的工具类

object PictureSelectorUtils {    const val REQUEST_PICTURE_SELECTOR = 10012    const val TAG = "PictureSelectorUtils"    fun startPictureSelector(activity: Activity) {        LogUtils.d(TAG, "startPictureSelector")        // 拍照后获取图片需要文件权限,界面跳转直接拿文件不需要权限        //检查申请读文件权限//        CheckPermissionUtils.requestPermissions(//            activity,//            arrayOf(//                Manifest.permission.CAMERA,//                Manifest.permission.READ_EXTERNAL_STORAGE,//                Manifest.permission.WRITE_EXTERNAL_STORAGE//            )//        )        //插件里自带了静态权限以及权限校验        PictureSelector.create(activity).openGallery(PictureMimeType.ofImage())            .imageEngine(GlideEngine) // Please refer to the Demo GlideEngine.java            .isWeChatStyle(true) // 是否开启微信图片选择风格            .selectionMode(PictureConfig.MULTIPLE).forResult(REQUEST_PICTURE_SELECTOR)    }    fun getPictures(data: Intent): MutableList<Uri> {        val selectList = PictureSelector.obtainMultipleResult(data)        LogUtils.d(TAG, "getPicture selectList: $selectList")        // 将照片路径转换成 Uri 列表        val imageUris: MutableList<Uri> = ArrayList()        if (selectList.isEmpty()) {            LogUtils.d(TAG, "getPicture selectList isEmpty")            return imageUris        }        for (imagePath in selectList) {            var path = imagePath.path            LogUtils.d(TAG, "path: $path")            val uri = Uri.parse(path)            LogUtils.d(TAG, "uri: $uri")            imageUris.add(uri)        }        LogUtils.d(TAG, "imageUris: ${imageUris.toString()}")        return imageUris    }    /**     * H5针对从文件钟选中的图片做处理     */    fun takeActivityResult(        requestCode: Int,        intent: Intent?,        filePathCallback: ValueCallback<Array<Uri>>?,    ) {        if (requestCode == REQUEST_PICTURE_SELECTOR) {            val selectList = PictureSelector.obtainMultipleResult(intent)            LogUtils.d(TAG, "getPicture selectList: $selectList")            // 将照片路径转换成 Uri 列表            val imageUris: MutableList<Uri> = ArrayList()            if (selectList.isEmpty()) {                LogUtils.d(TAG, "getPicture selectList isEmpty")                filePathCallback?.onReceiveValue(null)                return            }            for (imagePath in selectList) {                var path = imagePath.path                LogUtils.d(TAG, "path: $path")                val uri = Uri.parse(path)                LogUtils.d(TAG, "uri: $uri")                imageUris.add(uri)            }            LogUtils.d(TAG, "imageUris: ${imageUris.toString()}")            filePathCallback?.onReceiveValue(imageUris.toTypedArray())        }    }}

其中使用第三方组件库-实现类似朋友圈获取照片的样式,需要引入一下依赖

    //照片获取类微信朋友圈    implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'

拍照后获取图片需要文件权限,界面跳转直接拿文件不需要权限,且第三方插件库里自带了静态权限以及权限请求

3.我完整的代码——类似朋友圈获取界面逻辑

class VisitorFragment : Fragment() {    private lateinit var binding: FragmentVisitorBinding    lateinit var mActivity: Activity    private lateinit var mRoot: View    companion object {        const val TAG = "VisitorFragment"    }    private var mWebViewUrl: String = "file:///android_asset/vue_android_demo.html"    var mAppName = MainApplication.instance.configuration.BASE_APP_LOGIN_IDENTITY    var mSystemName = WebViewConstant.DEFAULT_SYSTEM_NAME    private var mVisitorAndroidJs: VisitorAndroidJs = VisitorAndroidJs(this)    private var mWebView: WebView? = null    var mAndroidId: String = WebViewConstant.DEFAULT_DEVICE_SIGN    var mApiKey: String = WebViewConstant.DEFAULT_API_KEY    //回传H5时使用的对象    private var mUploadCallback: ValueCallback<Array<Uri>>? = null    //拍照传递的路径uri    private var mImageUri: Uri? = null    /**     * onCreate方法是Activity生命周期的第一个回调方法     * ,当Activity被创建时被调用。     * 在这个方法中,你可以进行一些初始化的操作,比如设置布局、绑定控件、初始化数据等。     *     * @param savedInstanceState If the fragment is being re-created from     * a previous saved state, this is the state.     */    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        binding = FragmentVisitorBinding.inflate(layoutInflater)        mRoot = binding.root        //记录        val viewModel = ViewModelProvider(requireActivity())[DashboardViewModel::class.java]        viewModel.setFragment(this)        LogUtils.d(TAG, "onCreate")    }    /**     * onCreateView方法是Fragment生命周期的回调方法,     * 当Fragment创建并绘制其用户界面时被调用。     * 在这个方法中,你可以通过返回一个View对象来定义Fragment的用户界面。     * 它常用于加载布局文件、查找和初始化控件等操作。     *     * @return     */    override fun onCreateView(        inflater: LayoutInflater,        container: ViewGroup?,        savedInstanceState: Bundle?    ): View {        LogUtils.d(TAG, "onCreateView")        initView(mRoot, layoutInflater, null)        return mRoot    }    fun initView(parent: View?, inflater: LayoutInflater?, container: ViewGroup?) {        //设置当前fragment        mAndroidId = DeviceUtils.getUniqueId(mActivity)        initWebView()        mWebView?.loadUrl(mWebViewUrl)        //弹出展示链接        showToast("${getString(R.string.current_develop_environment)}$mWebViewUrl")        initData()    }    override fun onAttach(context: Context) {        super.onAttach(context)        mActivity = context as Activity    }    /**     * @param msg 内容     */    fun showToast(msg: String?) {        val activity: Activity? = activity        activity?.runOnUiThread {            Toast.makeText(                activity,                msg,                Toast.LENGTH_SHORT            ).show()        }    }    private fun initData() {    }    override fun onResume() {        super.onResume()        LogUtils.d(TAG, "onResume")    }    @SuppressLint("SetJavaScriptEnabled")    private fun initWebView() {        LogUtils.d(TAG, "initWebView")        mWebView = binding.mainWebView        mWebView?.requestFocus()        mWebView?.isHorizontalScrollBarEnabled = false        mWebView?.isVerticalScrollBarEnabled = false        val setting = mWebView?.settings        setting?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW;        setting?.javaScriptEnabled = true        //用于开启或禁用其 DOM(文档对象模型)存储功能,浏览器缓存这些数据        setting?.domStorageEnabled = true        //允许访问文件,默认允许        setting?.allowFileAccess = true        //设置不,会引起webView重新不急,默认NARROW_COLUMNS        setting?.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS        //自动缩放        setting?.setSupportZoom(true)        setting?.builtInZoomControls = true        //自适应屏幕        setting?.useWideViewPort = true        setting?.loadWithOverviewMode = true        //支持多窗口        setting?.setSupportMultipleWindows(true)        setting?.setAppCacheEnabled(true)        setting?.domStorageEnabled = true        //定位        setting?.setGeolocationEnabled(true)        //优先使用缓存数据,在缓存数据不存在的情况下才去获取网络数据        setting?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK        setting?.savePassword = false        //设置js接口        mVisitorAndroidJs.let { mWebView?.addJavascriptInterface(it, "android") }        //页面不跳转浏览器        mWebView?.webViewClient = object : WebViewClient() {            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {                LogUtils.d(TAG, "url: $url")                view.loadUrl(url)                return true            }            override fun shouldInterceptRequest(                view: WebView,                request: WebResourceRequest            ): WebResourceResponse? {                var uri = request.url                var path = uri.path                LogUtils.d(TAG, "uri: $uri, path: $path")                return super.shouldInterceptRequest(view, request)            }        }        //webView官方打开文件选取方法onShowFileChooser,把网页回传文件        mWebView?.webChromeClient = object : WebChromeClient() {            //API >=21(android 5.0.1)回调此方法            override fun onShowFileChooser(                webView: WebView?,                filePathCallback: ValueCallback<Array<Uri>>?,                fileChooserParams: FileChooserParams?            ): Boolean {                mUploadCallback = filePathCallback                //使用拍照或者打开文件//                mImageUri = ChoosePhotoFile.takePhoto(mActivity)                //模拟微信朋友圈获取照片模式                LogUtils.d(TAG,"onShowFileChooser")                PictureSelectorUtils.startPictureSelector(mActivity)                //设置false会IllegalStateException: Duplicate showFileChooser result                return true            }        }    }    fun onActivityResultResponse(requestCode: Int, resultCode: Int, intent: Intent?) {        LogUtils.d(            TAG,            "onActivityResultResponse requestCode $requestCode, resultCode:$resultCode"        )        // 扫描二维码/条码回传        if (requestCode == ScanCodeUtils.REQUEST_CODE_SCAN && resultCode == Activity.RESULT_OK) {            LogUtils.d(TAG, "onActivityResultResponse ${intent?.extras}")            if (intent == null) {                //弹出展示链接                showToast("扫描结果为空")                return            }            //传递给js,格式是"scanCodeResult('${data.extras}')",其中单引号很重要,可能导致js script error            //codedContent是组件中定义的参数名            setEvaluateJavascript("scanCodeResult('${intent.getStringExtra("codedContent")}')")//        } else if (requestCode == ChoosePhotoFile.REQUEST_CODE) {//            //拍照,界面跳回后,结果文件的使用//            ChoosePhotoFile.takeActivityResult(requestCode, intent, mUploadCallback, mImageUri)        } else if (requestCode == PictureSelectorUtils.REQUEST_PICTURE_SELECTOR) {            LogUtils.d(TAG, "onActivityResultResponse REQUEST_PICTURE_SELECTOR")            PictureSelectorUtils.takeActivityResult(requestCode, intent, mUploadCallback)        }    }    @Override    override fun onDestroy() {        //防止更新dialog内存泄漏        super.onDestroy()    }    /**     * 登录成功后跳转     */    open fun loginSuccessJump() {    }    /**     * 给网页传值     * 传递给js,格式是"scanCodeResult('${data.extras}')"     * 其中单引号很重要,可能导致js script error     */    private fun setEvaluateJavascript(jspMethodAndValue: String) {        LogUtils.d(            TAG,            "setEvaluateJavascript mWebView ${mWebView}, jspMethodAndValue $jspMethodAndValue"        )        mWebView?.evaluateJavascript(jspMethodAndValue, ValueCallback<String>() {            LogUtils.d(TAG, "给网页传值为: $jspMethodAndValue")        })    }}

三、总结一下

H5调用公共获取图片文件方法,在android手机端,H5主要依赖Webview,这边在webview声明并重写该方法onShowFileChooser使用工具类打开相机或相册,可以两种方式安卓原生方式或者利用第三方组件库方式选中图片,返回uri列表给H5H5收到uri照片列表,并且使用前端方式展示

创造价值,乐哉分享!


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/70974.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1