feat: 添加相机捕获功能,更新 H5ShellPage 以支持媒体播放设置
This commit is contained in:
@@ -10,6 +10,7 @@ import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.MediaStore
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import androidx.core.content.FileProvider
|
||||
@@ -29,6 +30,7 @@ class MainActivity : FlutterActivity() {
|
||||
private val MAX_BRANDING_ICON_SIZE = 192
|
||||
private val FILE_PICKER_REQUEST_CODE = 4201
|
||||
private var pendingFilePickerResult: MethodChannel.Result? = null
|
||||
private var pendingCameraCaptureUri: Uri? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
||||
// 华为/荣耀/OPPO 等国产设备:在任意网络请求之前同步安装 Conscrypt,修复 SSL 握手失败(无 GMS 时系统 SSL 实现不完整)
|
||||
@@ -116,7 +118,8 @@ class MainActivity : FlutterActivity() {
|
||||
"pickFiles" -> {
|
||||
val acceptTypes = call.argument<List<String>>("acceptTypes") ?: emptyList()
|
||||
val allowMultiple = call.argument<Boolean>("allowMultiple") ?: false
|
||||
openNativeFilePicker(acceptTypes, allowMultiple, result)
|
||||
val capture = call.argument<Boolean>("capture") ?: false
|
||||
openNativeFilePicker(acceptTypes, allowMultiple, capture, result)
|
||||
}
|
||||
else -> {
|
||||
result.notImplemented()
|
||||
@@ -134,7 +137,20 @@ class MainActivity : FlutterActivity() {
|
||||
return
|
||||
}
|
||||
|
||||
if (resultCode != Activity.RESULT_OK || data == null) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
pendingCameraCaptureUri = null
|
||||
result.success(emptyList<String>())
|
||||
return
|
||||
}
|
||||
|
||||
pendingCameraCaptureUri?.let { uri ->
|
||||
pendingCameraCaptureUri = null
|
||||
grantPickedFileReadPermission(uri)
|
||||
result.success(listOf(uri.toString()))
|
||||
return
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
result.success(emptyList<String>())
|
||||
return
|
||||
}
|
||||
@@ -164,6 +180,7 @@ class MainActivity : FlutterActivity() {
|
||||
private fun openNativeFilePicker(
|
||||
acceptTypes: List<String>,
|
||||
allowMultiple: Boolean,
|
||||
capture: Boolean,
|
||||
result: MethodChannel.Result
|
||||
) {
|
||||
if (pendingFilePickerResult != null) {
|
||||
@@ -172,6 +189,10 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
|
||||
val mimeTypes = normalizeMimeTypes(acceptTypes)
|
||||
if (capture && openNativeCapture(mimeTypes, result)) {
|
||||
return
|
||||
}
|
||||
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = when (mimeTypes.size) {
|
||||
@@ -199,6 +220,50 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun openNativeCapture(
|
||||
mimeTypes: List<String>,
|
||||
result: MethodChannel.Result
|
||||
): Boolean {
|
||||
pendingCameraCaptureUri = null
|
||||
val captureVideo = mimeTypes.isNotEmpty() &&
|
||||
mimeTypes.all { it.startsWith("video/") }
|
||||
val intent = if (captureVideo) {
|
||||
Intent(MediaStore.ACTION_VIDEO_CAPTURE)
|
||||
} else {
|
||||
Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
|
||||
val outputUri = createCameraCaptureUri(".jpg")
|
||||
pendingCameraCaptureUri = outputUri
|
||||
putExtra(MediaStore.EXTRA_OUTPUT, outputUri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
}
|
||||
}
|
||||
|
||||
pendingFilePickerResult = result
|
||||
return try {
|
||||
startActivityForResult(intent, FILE_PICKER_REQUEST_CODE)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
pendingFilePickerResult = null
|
||||
pendingCameraCaptureUri = null
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCameraCaptureUri(extension: String): Uri {
|
||||
val directory = externalCacheDir ?: cacheDir
|
||||
val file = File.createTempFile(
|
||||
"camera-capture-${System.currentTimeMillis()}",
|
||||
extension,
|
||||
directory
|
||||
)
|
||||
return FileProvider.getUriForFile(
|
||||
this,
|
||||
"${packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
}
|
||||
|
||||
private fun normalizeMimeTypes(acceptTypes: List<String>): List<String> {
|
||||
val mimeTypes = linkedSetOf<String>()
|
||||
acceptTypes
|
||||
|
||||
@@ -204,6 +204,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
unawaited(
|
||||
platformController.setOnShowFileSelector(_handleAndroidFileSelection),
|
||||
);
|
||||
unawaited(platformController.setMediaPlaybackRequiresUserGesture(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +221,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
||||
{
|
||||
'acceptTypes': params.acceptTypes,
|
||||
'allowMultiple': params.mode == FileSelectorMode.openMultiple,
|
||||
'capture': params.isCaptureEnabled,
|
||||
},
|
||||
);
|
||||
return result ?? <String>[];
|
||||
|
||||
Reference in New Issue
Block a user