mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 18:38:48 +01:00
Handle android permission request on dart side
This commit is contained in:
parent
80689fa431
commit
1cf2e565ba
5 changed files with 242 additions and 1 deletions
18
app/lib/mobile/android/permission_util.dart
Normal file
18
app/lib/mobile/android/permission_util.dart
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:nc_photos/stream_extension.dart';
|
||||||
|
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
|
||||||
|
|
||||||
|
Future<Map<String, int>> requestPermissionsForResult(
|
||||||
|
List<String> permissions) async {
|
||||||
|
Map<String, int>? result;
|
||||||
|
final resultFuture = Permission.stream
|
||||||
|
.whereType<PermissionRequestResult>()
|
||||||
|
.first
|
||||||
|
.then((ev) => result = ev.grantResults);
|
||||||
|
await Permission.request(permissions);
|
||||||
|
await resultFuture;
|
||||||
|
_log.info("[requestPermissionsForResult] Result: $result");
|
||||||
|
return result!;
|
||||||
|
}
|
||||||
|
|
||||||
|
final _log = Logger("mobile.android.permission_util");
|
|
@ -11,7 +11,8 @@ import io.flutter.plugin.common.MethodChannel
|
||||||
import io.flutter.plugin.common.PluginRegistry
|
import io.flutter.plugin.common.PluginRegistry
|
||||||
|
|
||||||
class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
||||||
PluginRegistry.ActivityResultListener {
|
PluginRegistry.ActivityResultListener,
|
||||||
|
PluginRegistry.RequestPermissionsResultListener {
|
||||||
companion object {
|
companion object {
|
||||||
const val ACTION_SHOW_IMAGE_PROCESSOR_RESULT =
|
const val ACTION_SHOW_IMAGE_PROCESSOR_RESULT =
|
||||||
K.ACTION_SHOW_IMAGE_PROCESSOR_RESULT
|
K.ACTION_SHOW_IMAGE_PROCESSOR_RESULT
|
||||||
|
@ -81,6 +82,19 @@ class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
||||||
contentUriMethodChannel.setMethodCallHandler(
|
contentUriMethodChannel.setMethodCallHandler(
|
||||||
ContentUriChannelHandler(flutterPluginBinding.applicationContext)
|
ContentUriChannelHandler(flutterPluginBinding.applicationContext)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
permissionChannelHandler =
|
||||||
|
PermissionChannelHandler(flutterPluginBinding.applicationContext)
|
||||||
|
permissionChannel = EventChannel(
|
||||||
|
flutterPluginBinding.binaryMessenger,
|
||||||
|
PermissionChannelHandler.EVENT_CHANNEL
|
||||||
|
)
|
||||||
|
permissionChannel.setStreamHandler(permissionChannelHandler)
|
||||||
|
permissionMethodChannel = MethodChannel(
|
||||||
|
flutterPluginBinding.binaryMessenger,
|
||||||
|
PermissionChannelHandler.METHOD_CHANNEL
|
||||||
|
)
|
||||||
|
permissionMethodChannel.setMethodCallHandler(permissionChannelHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetachedFromEngine(
|
override fun onDetachedFromEngine(
|
||||||
|
@ -94,30 +108,39 @@ class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
||||||
mediaStoreMethodChannel.setMethodCallHandler(null)
|
mediaStoreMethodChannel.setMethodCallHandler(null)
|
||||||
imageProcessorMethodChannel.setMethodCallHandler(null)
|
imageProcessorMethodChannel.setMethodCallHandler(null)
|
||||||
contentUriMethodChannel.setMethodCallHandler(null)
|
contentUriMethodChannel.setMethodCallHandler(null)
|
||||||
|
permissionMethodChannel.setMethodCallHandler(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||||
mediaStoreChannelHandler.onAttachedToActivity(binding)
|
mediaStoreChannelHandler.onAttachedToActivity(binding)
|
||||||
|
permissionChannelHandler.onAttachedToActivity(binding)
|
||||||
pluginBinding = binding
|
pluginBinding = binding
|
||||||
binding.addActivityResultListener(this)
|
binding.addActivityResultListener(this)
|
||||||
|
binding.addRequestPermissionsResultListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onReattachedToActivityForConfigChanges(
|
override fun onReattachedToActivityForConfigChanges(
|
||||||
binding: ActivityPluginBinding
|
binding: ActivityPluginBinding
|
||||||
) {
|
) {
|
||||||
mediaStoreChannelHandler.onReattachedToActivityForConfigChanges(binding)
|
mediaStoreChannelHandler.onReattachedToActivityForConfigChanges(binding)
|
||||||
|
permissionChannelHandler.onReattachedToActivityForConfigChanges(binding)
|
||||||
pluginBinding = binding
|
pluginBinding = binding
|
||||||
binding.addActivityResultListener(this)
|
binding.addActivityResultListener(this)
|
||||||
|
binding.addRequestPermissionsResultListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetachedFromActivity() {
|
override fun onDetachedFromActivity() {
|
||||||
mediaStoreChannelHandler.onDetachedFromActivity()
|
mediaStoreChannelHandler.onDetachedFromActivity()
|
||||||
|
permissionChannelHandler.onDetachedFromActivity()
|
||||||
pluginBinding?.removeActivityResultListener(this)
|
pluginBinding?.removeActivityResultListener(this)
|
||||||
|
pluginBinding?.removeRequestPermissionsResultListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetachedFromActivityForConfigChanges() {
|
override fun onDetachedFromActivityForConfigChanges() {
|
||||||
mediaStoreChannelHandler.onDetachedFromActivityForConfigChanges()
|
mediaStoreChannelHandler.onDetachedFromActivityForConfigChanges()
|
||||||
|
permissionChannelHandler.onDetachedFromActivityForConfigChanges()
|
||||||
pluginBinding?.removeActivityResultListener(this)
|
pluginBinding?.removeActivityResultListener(this)
|
||||||
|
pluginBinding?.removeRequestPermissionsResultListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(
|
override fun onActivityResult(
|
||||||
|
@ -141,6 +164,27 @@ class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(
|
||||||
|
requestCode: Int, permissions: Array<String>, grantResults: IntArray
|
||||||
|
): Boolean {
|
||||||
|
return try {
|
||||||
|
when (requestCode) {
|
||||||
|
K.PERMISSION_REQUEST_CODE -> {
|
||||||
|
permissionChannelHandler.onRequestPermissionsResult(
|
||||||
|
requestCode, permissions, grantResults
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.e(
|
||||||
|
TAG, "Failed while onActivityResult, requestCode=$requestCode"
|
||||||
|
)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var pluginBinding: ActivityPluginBinding? = null
|
private var pluginBinding: ActivityPluginBinding? = null
|
||||||
|
|
||||||
private lateinit var lockChannel: MethodChannel
|
private lateinit var lockChannel: MethodChannel
|
||||||
|
@ -151,7 +195,10 @@ class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
||||||
private lateinit var mediaStoreMethodChannel: MethodChannel
|
private lateinit var mediaStoreMethodChannel: MethodChannel
|
||||||
private lateinit var imageProcessorMethodChannel: MethodChannel
|
private lateinit var imageProcessorMethodChannel: MethodChannel
|
||||||
private lateinit var contentUriMethodChannel: MethodChannel
|
private lateinit var contentUriMethodChannel: MethodChannel
|
||||||
|
private lateinit var permissionChannel: EventChannel
|
||||||
|
private lateinit var permissionMethodChannel: MethodChannel
|
||||||
|
|
||||||
private lateinit var lockChannelHandler: LockChannelHandler
|
private lateinit var lockChannelHandler: LockChannelHandler
|
||||||
private lateinit var mediaStoreChannelHandler: MediaStoreChannelHandler
|
private lateinit var mediaStoreChannelHandler: MediaStoreChannelHandler
|
||||||
|
private lateinit var permissionChannelHandler: PermissionChannelHandler
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
package com.nkming.nc_photos.plugin
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||||
|
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||||
|
import io.flutter.plugin.common.EventChannel
|
||||||
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
import io.flutter.plugin.common.PluginRegistry
|
||||||
|
|
||||||
|
class PermissionChannelHandler(context: Context) :
|
||||||
|
MethodChannel.MethodCallHandler, EventChannel.StreamHandler, ActivityAware,
|
||||||
|
PluginRegistry.RequestPermissionsResultListener {
|
||||||
|
companion object {
|
||||||
|
const val EVENT_CHANNEL = "${K.LIB_ID}/permission"
|
||||||
|
const val METHOD_CHANNEL = "${K.LIB_ID}/permission_method"
|
||||||
|
|
||||||
|
private const val TAG = "PermissionChannelHandler"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||||
|
activity = binding.activity
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReattachedToActivityForConfigChanges(
|
||||||
|
binding: ActivityPluginBinding
|
||||||
|
) {
|
||||||
|
activity = binding.activity
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromActivity() {
|
||||||
|
activity = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromActivityForConfigChanges() {
|
||||||
|
activity = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(
|
||||||
|
requestCode: Int, permissions: Array<String>, grantResults: IntArray
|
||||||
|
): Boolean {
|
||||||
|
return if (requestCode == K.PERMISSION_REQUEST_CODE) {
|
||||||
|
eventSink?.success(buildMap {
|
||||||
|
put("event", "RequestPermissionsResult")
|
||||||
|
put(
|
||||||
|
"grantResults",
|
||||||
|
permissions.zip(grantResults.toTypedArray()).toMap()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
|
||||||
|
eventSink = events
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCancel(arguments: Any?) {
|
||||||
|
eventSink = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
when (call.method) {
|
||||||
|
"request" -> {
|
||||||
|
try {
|
||||||
|
request(call.argument("permissions")!!, result)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
result.error("systemException", e.toString(), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"hasWriteExternalStorage" -> {
|
||||||
|
try {
|
||||||
|
result.success(
|
||||||
|
PermissionUtil.hasWriteExternalStorage(context)
|
||||||
|
)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
result.error("systemException", e.toString(), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"hasReadExternalStorage" -> {
|
||||||
|
try {
|
||||||
|
result.success(
|
||||||
|
PermissionUtil.hasReadExternalStorage(context)
|
||||||
|
)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
result.error("systemException", e.toString(), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun request(
|
||||||
|
permissions: List<String>, result: MethodChannel.Result
|
||||||
|
) {
|
||||||
|
if (activity == null) {
|
||||||
|
result.error("systemException", "Activity is not ready", null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
PermissionUtil.request(activity!!, *permissions.toTypedArray())
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val context = context
|
||||||
|
private var activity: Activity? = null
|
||||||
|
private var eventSink: EventChannel.EventSink? = null
|
||||||
|
}
|
|
@ -7,3 +7,4 @@ export 'src/lock.dart';
|
||||||
export 'src/media_store.dart';
|
export 'src/media_store.dart';
|
||||||
export 'src/native_event.dart';
|
export 'src/native_event.dart';
|
||||||
export 'src/notification.dart';
|
export 'src/notification.dart';
|
||||||
|
export 'src/permission.dart';
|
||||||
|
|
62
plugin/lib/src/permission.dart
Normal file
62
plugin/lib/src/permission.dart
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// ignore_for_file: constant_identifier_names
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:nc_photos_plugin/src/k.dart' as k;
|
||||||
|
|
||||||
|
class Permission {
|
||||||
|
static const READ_EXTERNAL_STORAGE =
|
||||||
|
"android.permission.READ_EXTERNAL_STORAGE";
|
||||||
|
static const WRITE_EXTERNAL_STORAGE =
|
||||||
|
"android.permission.WRITE_EXTERNAL_STORAGE";
|
||||||
|
|
||||||
|
static Future<void> request(List<String> permissions) =>
|
||||||
|
_methodChannel.invokeMethod("request", <String, dynamic>{
|
||||||
|
"permissions": permissions,
|
||||||
|
});
|
||||||
|
|
||||||
|
static Future<bool> hasWriteExternalStorage() async {
|
||||||
|
return (await _methodChannel
|
||||||
|
.invokeMethod<bool>("hasWriteExternalStorage"))!;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool> hasReadExternalStorage() async {
|
||||||
|
return (await _methodChannel.invokeMethod<bool>("hasReadExternalStorage"))!;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream get stream => _eventStream;
|
||||||
|
|
||||||
|
static late final _eventStream =
|
||||||
|
_eventChannel.receiveBroadcastStream().map((event) {
|
||||||
|
if (event is Map) {
|
||||||
|
switch (event["event"]) {
|
||||||
|
case _eventRequestPermissionsResult:
|
||||||
|
return PermissionRequestResult(
|
||||||
|
(event["grantResults"] as Map).cast<String, int>());
|
||||||
|
|
||||||
|
default:
|
||||||
|
_log.shout("[_eventStream] Unknown event: ${event["event"]}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static const _eventChannel = EventChannel("${k.libId}/permission");
|
||||||
|
static const _methodChannel = MethodChannel("${k.libId}/permission_method");
|
||||||
|
|
||||||
|
static const _eventRequestPermissionsResult = "RequestPermissionsResult";
|
||||||
|
|
||||||
|
static final _log = Logger("plugin.permission.Permission");
|
||||||
|
}
|
||||||
|
|
||||||
|
class PermissionRequestResult {
|
||||||
|
static const granted = 0;
|
||||||
|
static const denied = -1;
|
||||||
|
|
||||||
|
const PermissionRequestResult(this.grantResults);
|
||||||
|
|
||||||
|
final Map<String, int> grantResults;
|
||||||
|
}
|
Loading…
Reference in a new issue