mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
fix android method channel
This commit is contained in:
@@ -1,19 +1,27 @@
|
|||||||
package com.github.wgh136.venera
|
package com.github.wgh136.venera
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.Manifest
|
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import android.provider.DocumentsContract
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import androidx.activity.result.ActivityResultCallback
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
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
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import dev.flutter.packages.file_selector_android.FileUtils
|
||||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.EventChannel
|
import io.flutter.plugin.common.EventChannel
|
||||||
@@ -21,17 +29,43 @@ import io.flutter.plugin.common.MethodChannel
|
|||||||
import io.flutter.plugins.GeneratedPluginRegistrant
|
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.lang.Exception
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
class MainActivity : FlutterFragmentActivity() {
|
class MainActivity : FlutterFragmentActivity() {
|
||||||
var volumeListen = VolumeListen()
|
var volumeListen = VolumeListen()
|
||||||
var listening = false
|
var listening = false
|
||||||
|
|
||||||
private lateinit var result: MethodChannel.Result
|
|
||||||
|
|
||||||
private val storageRequestCode = 0x10
|
private val storageRequestCode = 0x10
|
||||||
private var storagePermissionRequest: ((Boolean) -> Unit)? = null
|
private var storagePermissionRequest: ((Boolean) -> Unit)? = null
|
||||||
|
|
||||||
|
private val nextLocalRequestCode = AtomicInteger()
|
||||||
|
|
||||||
|
private fun <I, O> startContractForResult(
|
||||||
|
contract: ActivityResultContract<I, O>,
|
||||||
|
input: I,
|
||||||
|
callback: ActivityResultCallback<O>
|
||||||
|
) {
|
||||||
|
val key = "activity_rq_for_result#${nextLocalRequestCode.getAndIncrement()}"
|
||||||
|
val registry = activityResultRegistry
|
||||||
|
var launcher: ActivityResultLauncher<I>? = null
|
||||||
|
val observer = object : LifecycleEventObserver {
|
||||||
|
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||||
|
if (Lifecycle.Event.ON_DESTROY == event) {
|
||||||
|
launcher?.unregister()
|
||||||
|
lifecycle.removeObserver(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lifecycle.addObserver(observer)
|
||||||
|
val newCallback = ActivityResultCallback<O> {
|
||||||
|
launcher?.unregister()
|
||||||
|
lifecycle.removeObserver(observer)
|
||||||
|
callback.onActivityResult(it)
|
||||||
|
}
|
||||||
|
launcher = registry.register(key, contract, newCallback)
|
||||||
|
launcher.launch(input)
|
||||||
|
}
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
GeneratedPluginRegistrant.registerWith(flutterEngine)
|
GeneratedPluginRegistrant.registerWith(flutterEngine)
|
||||||
MethodChannel(
|
MethodChannel(
|
||||||
@@ -53,24 +87,21 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
"getDirectoryPath" -> {
|
"getDirectoryPath" -> {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||||
val launcher =
|
startContractForResult(ActivityResultContracts.StartActivityForResult(), intent) { activityResult ->
|
||||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
|
if (activityResult.resultCode != Activity.RESULT_OK) {
|
||||||
if (activityResult.resultCode != Activity.RESULT_OK) {
|
res.success(null)
|
||||||
result.success(null)
|
return@startContractForResult
|
||||||
}
|
|
||||||
val pickedDirectoryUri = activityResult.data?.data
|
|
||||||
if (pickedDirectoryUri == null)
|
|
||||||
result.success(null)
|
|
||||||
else
|
|
||||||
Thread {
|
|
||||||
try {
|
|
||||||
result.success(onPickedDirectory(pickedDirectoryUri))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
result.error("Failed to Copy Files", e.toString(), null)
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
}
|
||||||
launcher.launch(intent)
|
val pickedDirectoryUri = activityResult.data?.data
|
||||||
|
if (pickedDirectoryUri == null)
|
||||||
|
res.success(null)
|
||||||
|
else
|
||||||
|
try {
|
||||||
|
res.success(onPickedDirectory(pickedDirectoryUri))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
res.error("Failed to Copy Files", e.toString(), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> res.notImplemented()
|
else -> res.notImplemented()
|
||||||
@@ -104,8 +135,7 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
|
|
||||||
val selectFileChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "venera/select_file")
|
val selectFileChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "venera/select_file")
|
||||||
selectFileChannel.setMethodCallHandler { _, res ->
|
selectFileChannel.setMethodCallHandler { _, res ->
|
||||||
openFile()
|
openFile(res)
|
||||||
result = res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,13 +168,24 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
|
|
||||||
/// copy the directory to tmp directory, return copied directory
|
/// copy the directory to tmp directory, return copied directory
|
||||||
private fun onPickedDirectory(uri: Uri): String {
|
private fun onPickedDirectory(uri: Uri): String {
|
||||||
val contentResolver = contentResolver
|
if (!hasStoragePermission()) {
|
||||||
var tmp = cacheDir
|
// dart:io cannot access the directory without permission.
|
||||||
tmp = File(tmp, "getDirectoryPathTemp")
|
// so we need to copy the directory to cache directory
|
||||||
tmp.mkdir()
|
val contentResolver = contentResolver
|
||||||
copyDirectory(contentResolver, uri, tmp)
|
var tmp = cacheDir
|
||||||
|
tmp = File(tmp, "getDirectoryPathTemp")
|
||||||
|
tmp.mkdir()
|
||||||
|
Thread {
|
||||||
|
copyDirectory(contentResolver, uri, tmp)
|
||||||
|
}.start()
|
||||||
|
|
||||||
return tmp.absolutePath
|
return tmp.absolutePath
|
||||||
|
} else {
|
||||||
|
val docId = DocumentsContract.getTreeDocumentId(uri)
|
||||||
|
val split: Array<String?> = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
return if ((split.size >= 2) && (split[1] != null)) split[1]!!
|
||||||
|
else File.separator
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyDirectory(resolver: ContentResolver, srcUri: Uri, destDir: File) {
|
private fun copyDirectory(resolver: ContentResolver, srcUri: Uri, destDir: File) {
|
||||||
@@ -165,6 +206,20 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun hasStoragePermission(): Boolean {
|
||||||
|
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
|
ContextCompat.checkSelfPermission(
|
||||||
|
this,
|
||||||
|
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
|
) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
|
||||||
|
this,
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
|
) == PackageManager.PERMISSION_GRANTED
|
||||||
|
} else {
|
||||||
|
Environment.isExternalStorageManager()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun requestStoragePermission(result: (Boolean) -> Unit) {
|
private fun requestStoragePermission(result: (Boolean) -> Unit) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
val readPermission = ContextCompat.checkSelfPermission(
|
val readPermission = ContextCompat.checkSelfPermission(
|
||||||
@@ -196,10 +251,9 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
||||||
intent.addCategory("android.intent.category.DEFAULT")
|
intent.addCategory("android.intent.category.DEFAULT")
|
||||||
intent.data = Uri.parse("package:$packageName")
|
intent.data = Uri.parse("package:$packageName")
|
||||||
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { _ ->
|
startContractForResult(ActivityResultContracts.StartActivityForResult(), intent){ _ ->
|
||||||
result(Environment.isExternalStorageManager())
|
result(Environment.isExternalStorageManager())
|
||||||
}
|
}
|
||||||
launcher.launch(intent)
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
@@ -223,29 +277,40 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openFile() {
|
private fun openFile(result: MethodChannel.Result) {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
intent.type = "*/*"
|
intent.type = "*/*"
|
||||||
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
|
startContractForResult(ActivityResultContracts.StartActivityForResult(), intent){ activityResult ->
|
||||||
if (activityResult.resultCode != Activity.RESULT_OK) {
|
if (activityResult.resultCode != Activity.RESULT_OK) {
|
||||||
result.success(null)
|
result.success(null)
|
||||||
|
return@startContractForResult
|
||||||
}
|
}
|
||||||
val uri = activityResult.data?.data
|
val uri = activityResult.data?.data
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
result.success(null)
|
result.success(null)
|
||||||
return@registerForActivityResult
|
return@startContractForResult
|
||||||
}
|
}
|
||||||
val contentResolver = contentResolver
|
val contentResolver = contentResolver
|
||||||
val file = DocumentFile.fromSingleUri(this, uri)
|
val file = DocumentFile.fromSingleUri(this, uri)
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
result.success(null)
|
result.success(null)
|
||||||
return@registerForActivityResult
|
return@startContractForResult
|
||||||
}
|
}
|
||||||
val fileName = file.name
|
val fileName = file.name
|
||||||
if (fileName == null) {
|
if (fileName == null) {
|
||||||
result.success(null)
|
result.success(null)
|
||||||
return@registerForActivityResult
|
return@startContractForResult
|
||||||
|
}
|
||||||
|
if(hasStoragePermission()) {
|
||||||
|
try {
|
||||||
|
val filePath = FileUtils.getPathFromUri(this, uri)
|
||||||
|
result.success(filePath)
|
||||||
|
return@startContractForResult
|
||||||
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// copy file to cache directory
|
// copy file to cache directory
|
||||||
val cacheDir = cacheDir
|
val cacheDir = cacheDir
|
||||||
@@ -253,7 +318,7 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
val inputStream = contentResolver.openInputStream(uri)
|
val inputStream = contentResolver.openInputStream(uri)
|
||||||
if (inputStream == null) {
|
if (inputStream == null) {
|
||||||
result.success(null)
|
result.success(null)
|
||||||
return@registerForActivityResult
|
return@startContractForResult
|
||||||
}
|
}
|
||||||
val outputStream = FileOutputStream(newFile)
|
val outputStream = FileOutputStream(newFile)
|
||||||
inputStream.copyTo(outputStream)
|
inputStream.copyTo(outputStream)
|
||||||
@@ -262,7 +327,6 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
// send file path to flutter
|
// send file path to flutter
|
||||||
result.success(newFile.absolutePath)
|
result.success(newFile.absolutePath)
|
||||||
}
|
}
|
||||||
launcher.launch(intent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user