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