Web拍照在Android内的WebView中实现

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

1|0一 权限处理


`

<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" />

`

2|0二 设置 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 }

`

3|0三 实现 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 } } }

`

4|0四 处理 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|05. 创建图片文件(这里创建文件保存路径为私有目录路径导致返回给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" } }

`

6|0完整代码


`

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) } } }

`


__EOF__

本文作者朝闻道-夕可死
本文链接https://www.cnblogs.com/zhaowendao233/p/18393036.html
关于博主:编程小萌新一名,希望从今天开始慢慢提高,一步步走向技术的高峰!
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   朝闻道-夕可死  阅读(200)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示