webview上传图片开发部分代码记录

这两天在开发公司的一个自营商城的功能,需要配合前端的H5的开发。
中间涉及到webview的图片选择上传的功能,在这里做一下记录。
使用了Kotlin进行的开发,如有看不懂的可以评论回复。
1.图片上传会涉及到图片选择和拍照功能。相关代码如下:

//拍照代码
 private fun openCamera() {
        imagePaths = FileManager.imageCacheDir().absolutePath + "${System.currentTimeMillis()}.jpg"
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            doTakePhotoIn7()
        } else {
            var intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            // 必须确保文件夹路径存在,否则拍照后无法完成回调
            var vFile = File(imagePaths)
            if (!vFile.exists()) {
                vFile.mkdirs()
            } else {
                if (vFile.exists()) {
                    vFile.delete()
                }
            }
            cameraUri = Uri.fromFile(vFile)
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri)
            startActivityForResult(intent, Short.MAX_VALUE / 3);
        }
    }
//选择图片
    private fun toChoicePic() {
        var i = Intent(action)
        i?.addCategory(Intent.CATEGORY_OPENABLE)
        i?.type = "image/*"
        startActivityForResult(Intent.createChooser(i, "Image Chooser"), Short.MAX_VALUE / 2)
    }

2.webview的相关处理:

webView.webChromeClient = object : WebChromeClient() {
            private var mView: View? = null

            /**
             * 全屏处理
             */
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                super.onShowCustomView(view, callback)
                val parent = webView.parent as ViewGroup
                parent.removeView(webView)
                // 设置背景色为黑色
                view?.setBackgroundColor(Color.BLACK)
                parent.addView(view)
                mView = view
                setFullScreen()
            }

            /**
             * 退出全屏
             */
            override fun onHideCustomView() {
                super.onHideCustomView()
                if (mView != null) {
                    val parent = mView?.parent as ViewGroup
                    parent.removeView(mView)
                    parent.addView(webView)
                    mView = null
                    quitFullScreen()
                }
            }

            // For Android < 3.0
            fun openFileChooser(valueCallback: ValueCallback) {
                openFileChooser(valueCallback, "", "")
            }

            // For Android  >= 3.0
            fun openFileChooser(valueCallback: ValueCallback, acceptType: String) {
                openFileChooser(valueCallback, acceptType, "")
            }

            //For Android  >= 4.1
            fun openFileChooser(valueCallback: ValueCallback, acceptType: String, capture: String) {
                if (uploadMessage != null) {
                    uploadMessage = null
                }
                uploadMessage = valueCallback;
                toselectPicture()
            }

            override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback>?, fileChooserParams: FileChooserParams?): Boolean {
                if (uploadMessageAboveL != null) {
                    uploadMessageAboveL = null
                }
                uploadMessageAboveL = filePathCallback;
                toselectPicture()
                return true
            }
        }

3.因为图片要求在1M以内,所以需要对图片进行相关压缩处理:

 /**
     * 对图片进行压缩处理
     */
    private fun toCompressPic(srcPath: String?): Bitmap {
        val newOpts = BitmapFactory.Options()
        // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true
        var bitmap = BitmapFactory.decodeFile(srcPath, newOpts)// 此时返回bm为空

        newOpts.inJustDecodeBounds = false
        val w = newOpts.outWidth
        val h = newOpts.outHeight
        // 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        val hh = 800f// 这里设置高度为800f
        val ww = 480f// 这里设置宽度为480f
        // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        var be = 1// be=1表示不缩放
        if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
            be = (newOpts.outWidth / ww).toInt()
        } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放
            be = (newOpts.outHeight / hh).toInt()
        }
        if (be <= 0)
            be = 1
        newOpts.inSampleSize = be// 设置缩放比例
        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeFile(srcPath, newOpts)
        return compressImage(bitmap)// 压缩好比例大小后再进行质量压缩
    }

    private fun compressImage(image: Bitmap): Bitmap {
        var baos = ByteArrayOutputStream()
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        var options = 100;
        while (baos.toByteArray().size / 1024 > 1024) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();// 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
            options -= 10;// 每次都减少10
        }
        var isBm = ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
        var bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
        return bitmap;
    }

4.相关压缩过程中需要涉及到Uri与文件地址之间的转换,方式如下:

   /**
     * 功能简述:4.4及以上获取图片的方法
     * 功能详细描述:
     * 注意:
     * @param context
     * @param uri
     * @return
     */
    @RequiresApi(Build.VERSION_CODES.KITKAT)
    @TargetApi(Build.VERSION_CODES.KITKAT)
    fun getPath(context: Context, uri: Uri): String? {

        val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT

        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
                val type = split[0]

                if ("primary".equals(type, ignoreCase = true)) {
                    return "${Environment.getExternalStorageDirectory()}/${split[1]}"
                }
            } else if (isDownloadsDocument(uri)) {

                val id = DocumentsContract.getDocumentId(uri)
                val contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))

                return getDataColumn(context, contentUri, null, null)
            } else if (isMediaDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
                val type = split[0]

                var contentUri: Uri? = null
                if ("image" == type) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                } else if ("video" == type) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                } else if ("audio" == type) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                }

                val selection = "_id=?"
                val selectionArgs = arrayOf(split[1])

                return getDataColumn(context, contentUri, selection, selectionArgs)
            }// MediaProvider
            // DownloadsProvider
        } else if ("content".equals(uri.scheme, ignoreCase = true)) {

            // Return the remote address
            return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null)

        } else if ("file".equals(uri.scheme, ignoreCase = true)) {
            return uri.path
        }// File
        // MediaStore (and general)

        return null
    }

    fun getDataColumn(context: Context, uri: Uri?, selection: String?,
                      selectionArgs: Array?): String? {

        var cursor: Cursor? = null
        val column = "_data"
        val projection = arrayOf(column)

        try {
            cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
            if (cursor != null && cursor!!.moveToFirst()) {
                val index = cursor!!.getColumnIndexOrThrow(column)
                return cursor!!.getString(index)
            }
        } finally {
            if (cursor != null)
                cursor!!.close()
        }
        return null
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    fun isExternalStorageDocument(uri: Uri): Boolean {
        return "com.android.externalstorage.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    fun isDownloadsDocument(uri: Uri): Boolean {
        return "com.android.providers.downloads.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    fun isMediaDocument(uri: Uri): Boolean {
        return "com.android.providers.media.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    fun isGooglePhotosUri(uri: Uri): Boolean {
        return "com.google.android.apps.photos.content" == uri.authority
    }

    /**
     * Gets the content:// URI  from the given corresponding path to a file
     * @param context
     * @param imageFile
     * @return content Uri
     */
    fun getImageContentUri(context: Context, imageFile: File): Uri? {
        var filePath = imageFile.absolutePath
        var cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                Array(1) { MediaStore.Images.Media._ID },
                MediaStore.Images.Media.DATA + "=? ",
                Array(1) { filePath }, null);
        if (cursor != null && cursor.moveToFirst()) {
            var id = cursor.getInt(cursor
                    .getColumnIndex(MediaStore.MediaColumns._ID));
            var baseUri = Uri.parse("content://media/external/images/media");
            return Uri.withAppendedPath(baseUri, "" + id);
        } else {
            if (imageFile.exists()) {
                var values = ContentValues()
                values.put(MediaStore.Images.Media.DATA, filePath);
                return context.contentResolver.insert(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                return null
            }
        }
    }

5.onActivityResult方法内容如下:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (Short.MAX_VALUE / 2 == requestCode) {
            if (Activity.RESULT_OK == resultCode) {
                if (uploadMessageAboveL != null) { // 5.0 以上
                    onActivityResultAboveL(requestCode, resultCode, data)
                } else if (uploadMessage != null) { // 5.0 以下
                    uploadMessage?.onReceiveValue(Uri.parse((data?.getSerializableExtra(PictureSelector.KEY_SELECTED_IMAGE) as? Image)?.path))
                    uploadMessage = null
                }
            }
        } else {
            refreshPhotoList(imagePaths)//刷新相册,防止取不到图片
            var afterUri = Uri.parse(MediaStore.Images.Media.insertImage(
                    context.contentResolver, toCompressPic(imagePaths), null, null))
            if (uploadMessageAboveL != null && afterUri != null) { // 5.0 以上
                uploadMessageAboveL?.onReceiveValue(Array(1) { afterUri!! })
                uploadMessageAboveL = null
            } else if (uploadMessage != null) { // 5.0 以下
                uploadMessage?.onReceiveValue(afterUri)
                uploadMessage = null
            } else {
                cancelSelect()
            }
        }
        if (Activity.RESULT_CANCELED == resultCode) {
            cancelSelect()
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    fun onActivityResultAboveL(requestCode: Int, resultCode: Int, data: Intent?) {
        var rest: Array? = null
        if (data != null) {
            var dataString = data.dataString
            var clipData = data.clipData
            if (clipData != null) {
                rest = Array(clipData.itemCount) { Uri.parse("") }
                for (i in 0 until clipData.itemCount) {
                    var item = clipData.getItemAt(i)
                    rest[i] = item.uri
                }
            }
            if (dataString != null) {
                //将Uri获取绝对地址
                var contentToPath = getPath(context, Uri.parse(dataString))
                //将选定图片进行压缩之后保存到相册并返回对应的uri
                var afterUri = Uri.parse(MediaStore.Images.Media.insertImage(
                        context.contentResolver, toCompressPic(contentToPath), null, null))
                //通过对应的uri获取压缩之后的绝对地址路径
                var path2 = getPath(context, afterUri)
                //刷新相册
                refreshPhotoList(path2)
                //将绝对地址路径转换成content://形式的Uri路径
                var finalContentPath = getImageContentUri(context, File(path2))
                if (finalContentPath != null)
                    rest = Array(1) { finalContentPath!! }
            }
        }
        uploadMessageAboveL?.onReceiveValue(rest)
        uploadMessageAboveL = null
    }

   /**
     * 获取照片结束后
     */
    private fun refreshPhotoList(path:String?) {
        var f = File(path)
        addImageGallery(f)
    }

    /** 解决拍照或保存图片到相册后在相册中找不到的问题 */
    private fun addImageGallery(file: File) {
        var values = ContentValues()
        values.put(MediaStore.Images.Media.DATA, file.absolutePath)
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        context.contentResolver.insert(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
    }

    /**
     * 注意:取消选取图片必须调用此方法,否则第二次选择会失效
     * 处理重复选取图片问题
     */
    private fun cancelSelect() {
        if (uploadMessageAboveL != null) {
            uploadMessageAboveL?.onReceiveValue(null)
            uploadMessageAboveL = null
        }
        if (uploadMessage != null) {
            uploadMessage?.onReceiveValue(null)
            uploadMessage = null
        }
    }

你可能感兴趣的:(webview上传图片开发部分代码记录)