fix importing data on Android

This commit is contained in:
2024-11-13 18:55:25 +08:00
parent 856ad82c55
commit d34c7c3806
3 changed files with 85 additions and 10 deletions

View File

@@ -10,7 +10,6 @@ import android.view.KeyEvent
import android.Manifest import android.Manifest
import android.os.Environment import android.os.Environment
import android.provider.Settings import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
@@ -34,6 +33,8 @@ class MainActivity : FlutterActivity() {
private val storageRequestCode = 0x10 private val storageRequestCode = 0x10
private var storagePermissionRequest: ((Boolean) -> Unit)? = null private var storagePermissionRequest: ((Boolean) -> Unit)? = null
private val selectFileCode = 0x11
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == pickDirectoryCode) { if (requestCode == pickDirectoryCode) {
@@ -59,6 +60,41 @@ class MainActivity : FlutterActivity() {
storagePermissionRequest?.invoke(Environment.isExternalStorageManager()) storagePermissionRequest?.invoke(Environment.isExternalStorageManager())
} }
storagePermissionRequest = null storagePermissionRequest = null
} else if (requestCode == selectFileCode) {
if (resultCode != Activity.RESULT_OK) {
result.success(null)
return
}
val uri = data?.data
if (uri == null) {
result.success(null)
return
}
val contentResolver = context.contentResolver
val file = DocumentFile.fromSingleUri(context, uri)
if (file == null) {
result.success(null)
return
}
val fileName = file.name
if (fileName == null) {
result.success(null)
return
}
// copy file to cache directory
val cacheDir = context.cacheDir
val newFile = File(cacheDir, fileName)
val inputStream = contentResolver.openInputStream(uri)
if (inputStream == null) {
result.success(null)
return
}
val outputStream = FileOutputStream(newFile)
inputStream.copyTo(outputStream)
inputStream.close()
outputStream.close()
// send file path to flutter
result.success(newFile.absolutePath)
} }
} }
@@ -112,6 +148,12 @@ class MainActivity : FlutterActivity() {
res.success(result) res.success(result)
} }
} }
val selectFileChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "venera/select_file")
selectFileChannel.setMethodCallHandler { _, res ->
openFile()
result = res
}
} }
private fun getProxy(): String { private fun getProxy(): String {
@@ -223,6 +265,13 @@ class MainActivity : FlutterActivity() {
storagePermissionRequest = null storagePermissionRequest = null
} }
} }
fun openFile() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "*/*"
startActivityForResult(intent, selectFileCode)
}
} }
class VolumeListen{ class VolumeListen{

View File

@@ -1,5 +1,3 @@
import 'dart:typed_data';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
class FileType { class FileType {
@@ -7,6 +5,14 @@ class FileType {
final String mime; final String mime;
const FileType(this.ext, this.mime); const FileType(this.ext, this.mime);
static FileType fromExtension(String ext) {
if(ext.startsWith('.')) {
ext = ext.substring(1);
}
var mime = lookupMimeType('no-file.$ext');
return FileType(".$ext", mime ?? 'application/octet-stream');
}
} }
FileType detectFileType(List<int> data) { FileType detectFileType(List<int> data) {

View File

@@ -9,6 +9,7 @@ import 'package:venera/utils/ext.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:share_plus/share_plus.dart' as s; import 'package:share_plus/share_plus.dart' as s;
import 'package:file_selector/file_selector.dart' as file_selector; import 'package:file_selector/file_selector.dart' as file_selector;
import 'package:venera/utils/file_type.dart';
export 'dart:io'; export 'dart:io';
export 'dart:typed_data'; export 'dart:typed_data';
@@ -126,7 +127,8 @@ Future<void> copyDirectory(Directory source, Directory destination) async {
} }
} }
Future<void> copyDirectoryIsolate(Directory source, Directory destination) async { Future<void> copyDirectoryIsolate(
Directory source, Directory destination) async {
await Isolate.run(() { await Isolate.run(() {
copyDirectory(source, destination); copyDirectory(source, destination);
}); });
@@ -196,14 +198,32 @@ class IOSDirectoryPicker {
} }
Future<file_selector.XFile?> selectFile({required List<String> ext}) async { Future<file_selector.XFile?> selectFile({required List<String> ext}) async {
var extensions = App.isMacOS || App.isIOS ? null : ext;
if (App.isAndroid) {
for (var e in ext) {
var fileType = FileType.fromExtension(e);
if (fileType.mime == "application/octet-stream") {
extensions = null;
break;
}
}
}
file_selector.XTypeGroup typeGroup = file_selector.XTypeGroup( file_selector.XTypeGroup typeGroup = file_selector.XTypeGroup(
label: 'files', label: 'files',
extensions: App.isMacOS || App.isIOS ? null : ext, extensions: extensions,
); );
final file_selector.XFile? file = await file_selector.openFile( file_selector.XFile? file;
if (extensions == null && App.isAndroid) {
const selectFileChannel = MethodChannel("venera/select_file");
var filePath = await selectFileChannel.invokeMethod("selectFile");
if (filePath == null) return null;
file = file_selector.XFile(filePath);
} else {
file = await file_selector.openFile(
acceptedTypeGroups: <file_selector.XTypeGroup>[typeGroup], acceptedTypeGroups: <file_selector.XTypeGroup>[typeGroup],
); );
if (file == null) return null; if (file == null) return null;
}
if (!ext.contains(file.path.split(".").last)) { if (!ext.contains(file.path.split(".").last)) {
App.rootContext.showMessage(message: "Invalid file type"); App.rootContext.showMessage(message: "Invalid file type");
return null; return null;