feat: 添加相机捕获功能,更新 H5ShellPage 以支持媒体播放设置
This commit is contained in:
@@ -10,6 +10,7 @@ import android.graphics.drawable.BitmapDrawable
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.provider.MediaStore
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
@@ -29,6 +30,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
private val MAX_BRANDING_ICON_SIZE = 192
|
private val MAX_BRANDING_ICON_SIZE = 192
|
||||||
private val FILE_PICKER_REQUEST_CODE = 4201
|
private val FILE_PICKER_REQUEST_CODE = 4201
|
||||||
private var pendingFilePickerResult: MethodChannel.Result? = null
|
private var pendingFilePickerResult: MethodChannel.Result? = null
|
||||||
|
private var pendingCameraCaptureUri: Uri? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
||||||
// 华为/荣耀/OPPO 等国产设备:在任意网络请求之前同步安装 Conscrypt,修复 SSL 握手失败(无 GMS 时系统 SSL 实现不完整)
|
// 华为/荣耀/OPPO 等国产设备:在任意网络请求之前同步安装 Conscrypt,修复 SSL 握手失败(无 GMS 时系统 SSL 实现不完整)
|
||||||
@@ -116,7 +118,8 @@ class MainActivity : FlutterActivity() {
|
|||||||
"pickFiles" -> {
|
"pickFiles" -> {
|
||||||
val acceptTypes = call.argument<List<String>>("acceptTypes") ?: emptyList()
|
val acceptTypes = call.argument<List<String>>("acceptTypes") ?: emptyList()
|
||||||
val allowMultiple = call.argument<Boolean>("allowMultiple") ?: false
|
val allowMultiple = call.argument<Boolean>("allowMultiple") ?: false
|
||||||
openNativeFilePicker(acceptTypes, allowMultiple, result)
|
val capture = call.argument<Boolean>("capture") ?: false
|
||||||
|
openNativeFilePicker(acceptTypes, allowMultiple, capture, result)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
result.notImplemented()
|
result.notImplemented()
|
||||||
@@ -134,7 +137,20 @@ class MainActivity : FlutterActivity() {
|
|||||||
return
|
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>())
|
result.success(emptyList<String>())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -164,6 +180,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
private fun openNativeFilePicker(
|
private fun openNativeFilePicker(
|
||||||
acceptTypes: List<String>,
|
acceptTypes: List<String>,
|
||||||
allowMultiple: Boolean,
|
allowMultiple: Boolean,
|
||||||
|
capture: Boolean,
|
||||||
result: MethodChannel.Result
|
result: MethodChannel.Result
|
||||||
) {
|
) {
|
||||||
if (pendingFilePickerResult != null) {
|
if (pendingFilePickerResult != null) {
|
||||||
@@ -172,6 +189,10 @@ class MainActivity : FlutterActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val mimeTypes = normalizeMimeTypes(acceptTypes)
|
val mimeTypes = normalizeMimeTypes(acceptTypes)
|
||||||
|
if (capture && openNativeCapture(mimeTypes, result)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||||
addCategory(Intent.CATEGORY_OPENABLE)
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
type = when (mimeTypes.size) {
|
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> {
|
private fun normalizeMimeTypes(acceptTypes: List<String>): List<String> {
|
||||||
val mimeTypes = linkedSetOf<String>()
|
val mimeTypes = linkedSetOf<String>()
|
||||||
acceptTypes
|
acceptTypes
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
|||||||
unawaited(
|
unawaited(
|
||||||
platformController.setOnShowFileSelector(_handleAndroidFileSelection),
|
platformController.setOnShowFileSelector(_handleAndroidFileSelection),
|
||||||
);
|
);
|
||||||
|
unawaited(platformController.setMediaPlaybackRequiresUserGesture(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +221,7 @@ class _H5ShellPageState extends State<H5ShellPage> {
|
|||||||
{
|
{
|
||||||
'acceptTypes': params.acceptTypes,
|
'acceptTypes': params.acceptTypes,
|
||||||
'allowMultiple': params.mode == FileSelectorMode.openMultiple,
|
'allowMultiple': params.mode == FileSelectorMode.openMultiple,
|
||||||
|
'capture': params.isCaptureEnabled,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return result ?? <String>[];
|
return result ?? <String>[];
|
||||||
|
|||||||
Reference in New Issue
Block a user