Web拍照在Android内的WebView中实现

使用Android Studio开发的一个应用内的webview页面需要拍照上传功能
因为我对安卓开发不太熟悉所以借助gpt的力量获得了这些代码但其中有一些问题需要修正

一 权限处理

`

<uses-feature
    android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

`

二 设置 WebView 允许文件访问和 JavaScript

`

val webView: WebView = findViewById(R.id.webview)
val webSettings = webView.settings
webSettings.javaScriptEnabled = true
webSettings.allowFileAccess = true
webSettings.domStorageEnabled = true
webSettings.allowContentAccess = true

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}

`

三 实现 WebChromeClient 处理文件选择

`

    webView.webChromeClient = object : WebChromeClient() {
        override fun onShowFileChooser(
            webView: WebView,
            filePathCallback: ValueCallback<Array<Uri>>,
            fileChooserParams: FileChooserParams
        ): Boolean {
            if (mFilePathCallback != null) {
                mFilePathCallback?.onReceiveValue(null)
            }
            mFilePathCallback = filePathCallback

            val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            takePictureIntent.resolveActivity(packageManager)?.let {
                var photoFile: File? = null
                try {
                    photoFile = createImageFile()
                    takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath)
                } catch (ex: IOException) {
                    Log.e("WebView", "Image file creation failed", ex)
                }
                if (photoFile != null) {
                    mCameraPhotoPath = "file:" + photoFile.absolutePath
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile))
                }
            }

            val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT).apply {
                addCategory(Intent.CATEGORY_OPENABLE)
                type = "image/*"
            }

            val intentArray = takePictureIntent?.let { arrayOf(it) } ?: arrayOf<Intent>()

            val chooserIntent = Intent(Intent.ACTION_CHOOSER).apply {
                putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
                putExtra(Intent.EXTRA_TITLE, "Image Chooser")
                putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
            }

            startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE)
            return true
        }
    }
}

`

四 处理 onActivityResult 返回的结果

`

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == INPUT_FILE_REQUEST_CODE && mFilePathCallback != null) {
        val results: Array<Uri>? = when {
            resultCode != Activity.RESULT_OK -> null
            data == null -> mCameraPhotoPath?.let { arrayOf(Uri.parse(it)) }
            else -> data.dataString?.let { arrayOf(Uri.parse(it)) }
        }

        mFilePathCallback?.onReceiveValue(results)
        mFilePathCallback = null
    } else {
        super.onActivityResult(requestCode, resultCode, data)
    }
}

`

5. 创建图片文件(这里创建文件保存路径为私有目录路径导致返回给WebView的值为null, 改为公共路径之后就可以了)

`

@Throws(IOException::class)
private fun createImageFile(): File {
    val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
    val imageFileName = "JPEG_" + timeStamp + "_"
    val storageDir: File = getExternalFilesDir(Environment.DIRECTORY_PICTURES) ?: throw IOException("Failed to get storage directory")

    return File.createTempFile(imageFileName, ".jpg", storageDir).apply {
        mCameraPhotoPath = absolutePath
    }
}
//修改后
@Throws(IOException::class)
private fun createImageFile(): File {
    val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
    val storageDir: File = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
    return File.createTempFile("JPEG_${timeStamp}_", ".jpg", storageDir).apply {
        mCameraPhotoPath = "file:$absolutePath"
    }
}

`

完整代码

`

class MyWebViewActivity : AppCompatActivity() {

private var mFilePathCallback: ValueCallback<Array<Uri>>? = null
private var mCameraPhotoPath: String? = null
private val INPUT_FILE_REQUEST_CODE = 1
private val CAMERA_PERMISSION_REQUEST_CODE = 2

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val webView: WebView = findViewById(R.id.webview)
    val webSettings = webView.settings
    webSettings.javaScriptEnabled = true
    webSettings.allowFileAccess = true
    webSettings.domStorageEnabled = true
    webSettings.allowContentAccess = true

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
    }

    webView.webChromeClient = object : WebChromeClient() {
        override fun onShowFileChooser(
            webView: WebView,
            filePathCallback: ValueCallback<Array<Uri>>,
            fileChooserParams: FileChooserParams
        ): Boolean {
            if (mFilePathCallback != null) {
                mFilePathCallback?.onReceiveValue(null)
            }
            mFilePathCallback = filePathCallback

            val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            takePictureIntent.resolveActivity(packageManager)?.let {
                var photoFile: File? = null
                try {
                    photoFile = createImageFile()
                    takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath)
                } catch (ex: IOException) {
                    Log.e("WebView", "Image file creation failed", ex)
                }
                if (photoFile != null) {
                    mCameraPhotoPath = "file:" + photoFile.absolutePath
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile))
                }
            }

            val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT).apply {
                addCategory(Intent.CATEGORY_OPENABLE)
                type = "image/*"
            }

            val intentArray = takePictureIntent?.let { arrayOf(it) } ?: arrayOf<Intent>()

            val chooserIntent = Intent(Intent.ACTION_CHOOSER).apply {
                putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
                putExtra(Intent.EXTRA_TITLE, "Image Chooser")
                putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
            }

            startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE)
            return true
        }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == INPUT_FILE_REQUEST_CODE && mFilePathCallback != null) {
        val results: Array<Uri>? = when {
            resultCode != Activity.RESULT_OK -> null
            data == null -> mCameraPhotoPath?.let { arrayOf(Uri.parse(it)) }
            else -> data.dataString?.let { arrayOf(Uri.parse(it)) }
        }

        mFilePathCallback?.onReceiveValue(results)
        mFilePathCallback = null
    } else {
        super.onActivityResult(requestCode, resultCode, data)
    }
}

@Throws(IOException::class)
private fun createImageFile(): File {
    val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
    val storageDir: File = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
    return File.createTempFile("JPEG_${timeStamp}_", ".jpg", storageDir).apply {
        mCameraPhotoPath = "file:$absolutePath"
    }
}

private fun requestCameraPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), CAMERA_PERMISSION_REQUEST_CODE)
    }
}
}

`

posted @ 2024-09-02 17:01  朝闻道-夕可死  阅读(18)  评论(0编辑  收藏  举报