Commit 5ab3ffcc by Maurits van Beusekom

Implement API to request permissions on Android

parent afe7f77d
......@@ -2,9 +2,11 @@ package com.baseflow.permissionhandler
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Build
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.util.Log
import com.baseflow.permissionhandler.data.PermissionGroup
......@@ -14,267 +16,388 @@ import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.Registrar
class PermissionHandlerPlugin(private val registrar: Registrar, private var requestedPermissions: MutableList<String>? = null): MethodCallHandler {
class PermissionHandlerPlugin(private val registrar: Registrar, private var requestedPermissions: MutableList<String>? = null) : MethodCallHandler {
private var mRequestResults = mutableMapOf<PermissionGroup, PermissionStatus>()
private var mResult: Result? = null
companion object {
@JvmStatic private val logTag = "permissions_handler"
companion object {
const val permissionCode = 25
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "flutter.baseflow.com/permissions/methods")
channel.setMethodCallHandler(PermissionHandlerPlugin(registrar))
@JvmStatic
private val mLogTag = "permissions_handler"
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "flutter.baseflow.com/permissions/methods")
val instance = PermissionHandlerPlugin(registrar)
channel.setMethodCallHandler(instance)
registrar.addRequestPermissionsResultListener(PluginRegistry.RequestPermissionsResultListener { id, permissions, grantResults ->
if (id == permissionCode) {
instance.handlePermissionsRequest(permissions, grantResults)
return@RequestPermissionsResultListener true
}
return@RequestPermissionsResultListener false
})
}
@JvmStatic
fun parseManifestName(permission: String): PermissionGroup {
when (permission) {
Manifest.permission.READ_CALENDAR,
Manifest.permission.WRITE_CALENDAR ->
return PermissionGroup.CALENDAR
Manifest.permission.CAMERA ->
return PermissionGroup.CAMERA
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS,
Manifest.permission.GET_ACCOUNTS ->
return PermissionGroup.CONTACTS
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION ->
return PermissionGroup.LOCATION
Manifest.permission.RECORD_AUDIO ->
return PermissionGroup.MICROPHONE
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CALL_PHONE,
Manifest.permission.READ_CALL_LOG,
Manifest.permission.WRITE_CALL_LOG,
Manifest.permission.ADD_VOICEMAIL,
Manifest.permission.USE_SIP,
Manifest.permission.PROCESS_OUTGOING_CALLS ->
return PermissionGroup.PHONE
Manifest.permission.BODY_SENSORS ->
return PermissionGroup.SENSORS
Manifest.permission.SEND_SMS,
Manifest.permission.RECEIVE_SMS,
Manifest.permission.READ_SMS,
Manifest.permission.RECEIVE_WAP_PUSH,
Manifest.permission.RECEIVE_MMS ->
return PermissionGroup.SMS
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE ->
return PermissionGroup.STORAGE
}
return PermissionGroup.UNKNOWN
}
}
@JvmStatic
fun parseManifestName(permission: String) : PermissionGroup
{
when (permission) {
Manifest.permission.READ_CALENDAR,
Manifest.permission.WRITE_CALENDAR ->
return PermissionGroup.CALENDAR
Manifest.permission.CAMERA ->
return PermissionGroup.CAMERA
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS,
Manifest.permission.GET_ACCOUNTS ->
return PermissionGroup.CONTACTS
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION ->
return PermissionGroup.LOCATION
Manifest.permission.RECORD_AUDIO ->
return PermissionGroup.MICROPHONE
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CALL_PHONE,
Manifest.permission.READ_CALL_LOG,
Manifest.permission.WRITE_CALL_LOG,
Manifest.permission.ADD_VOICEMAIL,
Manifest.permission.USE_SIP,
Manifest.permission.PROCESS_OUTGOING_CALLS ->
return PermissionGroup.PHONE
Manifest.permission.BODY_SENSORS ->
return PermissionGroup.SENSORS
Manifest.permission.SEND_SMS,
Manifest.permission.RECEIVE_SMS,
Manifest.permission.READ_SMS,
Manifest.permission.RECEIVE_WAP_PUSH,
Manifest.permission.RECEIVE_MMS ->
return PermissionGroup.SMS
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE ->
return PermissionGroup.STORAGE
}
return PermissionGroup.UNKNOWN
override fun onMethodCall(call: MethodCall, result: Result) {
when {
call.method == "checkPermissionStatus" -> {
val permission = Codec.decodePermissionGroup(call.arguments)
val permissionStatus = checkPermissionStatus(permission)
handleSuccess(permissionStatus, result)
}
call.method == "requestPermissions" -> {
if (mResult != null) {
result.error(
"ERROR_ALREADY_REQUESTED_PERMISSIONS",
"A request for permissions is already running, please wait for it to finish before doing another request (note that you can request multiple permissions at the same time).",
null)
}
mResult = result
val permissions = Codec.decodePermissionGroups(call.arguments)
requestPermissions(permissions)
}
call.method == "openAppSettings" -> {
val isOpen = openAppSettings()
result.success(isOpen)
}
else -> result.notImplemented()
}
}
private fun checkPermissionStatus(permission: PermissionGroup): PermissionStatus {
val names = getManifestNames(permission)
if (names == null) {
Log.d(mLogTag, "No android specific permissions needed for: $permission")
return PermissionStatus.GRANTED
}
//if no permissions were found then there is an issue and permission is not set in Android manifest
if (names.count() == 0) {
Log.d(mLogTag, "No permissions found in manifest for: $permission")
return PermissionStatus.UNKNOWN
}
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return PermissionStatus.UNKNOWN
}
val targetsMOrHigher = context.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.M
for (name in names) {
if (targetsMOrHigher && ContextCompat.checkSelfPermission(context, name) != PackageManager.PERMISSION_GRANTED) {
return PermissionStatus.DENIED
}
}
return PermissionStatus.GRANTED
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "checkPermissionStatus") {
val permission = Codec.decodePermissionGroup(call.arguments)
checkPermissionStatus(permission, result)
} else {
result.notImplemented()
private fun requestPermissions(permissions: Array<PermissionGroup>) {
if (registrar.activity() == null) {
Log.d(mLogTag, "Unable to detect current Activity.")
for (permission in permissions) {
mRequestResults[permission] = PermissionStatus.UNKNOWN
}
processResult()
return
}
val permissionsToRequest = mutableListOf<String>()
for (permission in permissions) {
val permissionStatus = checkPermissionStatus(permission)
if (permissionStatus != PermissionStatus.GRANTED) {
val names = getManifestNames(permission)
//check to see if we can find manifest names
//if we can't add as unknown and continue
if (names == null || names.isEmpty()) {
if (!mRequestResults.containsKey(permission)) {
mRequestResults[permission] = PermissionStatus.UNKNOWN
}
continue
}
names.let { permissionsToRequest.addAll(it) }
} else {
if (!mRequestResults.containsKey(permission)) {
mRequestResults[permission] = PermissionStatus.GRANTED
}
}
}
ActivityCompat.requestPermissions(
registrar.activity(),
permissionsToRequest.toTypedArray(),
permissionCode)
}
}
private fun checkPermissionStatus(permission: PermissionGroup, result: Result)
{
val names = getManifestNames(permission)
private fun handlePermissionsRequest(permissions: Array<String>, grantResults: IntArray) {
if (mResult == null) {
return
}
for (i in permissions.indices) {
val permission = parseManifestName(permissions[i])
if (permission == PermissionGroup.UNKNOWN)
continue
if (permission == PermissionGroup.MICROPHONE) {
if (!mRequestResults.containsKey(PermissionGroup.SPEECH)) {
mRequestResults[PermissionGroup.SPEECH] = grantResults[i].toPermissionStatus()
}
} else if (permission == PermissionGroup.LOCATION) {
if (!mRequestResults.containsKey(PermissionGroup.LOCATION_ALWAYS)) {
mRequestResults[PermissionGroup.LOCATION_ALWAYS] = grantResults[i].toPermissionStatus()
}
if (!mRequestResults.containsKey(PermissionGroup.LOCATION_WHEN_IN_USE)) {
mRequestResults[PermissionGroup.LOCATION_WHEN_IN_USE] = grantResults[i].toPermissionStatus()
}
}
if (!mRequestResults.containsKey(permission)) {
mRequestResults[permission] = grantResults[i].toPermissionStatus()
}
if (names == null)
{
Log.d(logTag, "No android specific permissions needed for: $permission")
handleSuccess(PermissionStatus.GRANTED, result)
return
}
processResult()
}
//if no permissions were found then there is an issue and persmission is not set in Android manifest
if (names.count() == 0)
{
Log.d(logTag, "No permissions found in manifest for: $permission")
handleSuccess(PermissionStatus.UNKNOWN, result)
return
private fun Int.toPermissionStatus(): PermissionStatus {
return if (this == PackageManager.PERMISSION_GRANTED) PermissionStatus.GRANTED else PermissionStatus.DENIED
}
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null)
{
Log.d(logTag, "Unable to detect current Activity or App Context. Please ensure Plugin.CurrentActivity is installed in your Android project and your Application class is registering with Application.IActivityLifecycleCallbacks.")
handleSuccess(PermissionStatus.UNKNOWN, result)
return
private fun processResult() {
mResult?.success(Codec.encodePermissionRequestResult(mRequestResults))
mRequestResults.clear()
mResult = null
}
val targetsMOrHigher = context.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.M
private fun openAppSettings(): Boolean {
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return false
}
try {
var settingsIntent = Intent()
settingsIntent.action = android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
settingsIntent.addCategory(Intent.CATEGORY_DEFAULT)
settingsIntent.data = android.net.Uri.parse("package:" + context.packageName)
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
context.startActivity(settingsIntent)
for (name in names)
{
if (targetsMOrHigher && ContextCompat.checkSelfPermission(context, name) != PackageManager.PERMISSION_GRANTED) {
handleSuccess(PermissionStatus.DENIED, result)
return
}
return true
} catch(ex: Exception) {
return false
}
}
handleSuccess(PermissionStatus.GRANTED, result)
}
private fun getManifestNames(permission: PermissionGroup) : List<String>?
{
val permissionNames : MutableList<String> = mutableListOf()
when(permission) {
PermissionGroup.CALENDAR ->
{
if(hasPermissionInManifest(Manifest.permission.READ_CALENDAR))
permissionNames.add(Manifest.permission.READ_CALENDAR)
if(hasPermissionInManifest(Manifest.permission.WRITE_CALENDAR))
permissionNames.add(Manifest.permission.WRITE_CALENDAR)
}
PermissionGroup.CAMERA ->
{
if(hasPermissionInManifest(Manifest.permission.CAMERA))
permissionNames.add(Manifest.permission.CAMERA)
}
PermissionGroup.CONTACTS ->
{
if(hasPermissionInManifest(Manifest.permission.READ_CONTACTS))
permissionNames.add(Manifest.permission.READ_CONTACTS)
if(hasPermissionInManifest(Manifest.permission.WRITE_CONTACTS))
permissionNames.add(Manifest.permission.WRITE_CONTACTS)
if(hasPermissionInManifest(Manifest.permission.GET_ACCOUNTS))
permissionNames.add(Manifest.permission.GET_ACCOUNTS)
}
PermissionGroup.LOCATION_ALWAYS,
PermissionGroup.LOCATION_WHEN_IN_USE,
PermissionGroup.LOCATION ->
{
if(hasPermissionInManifest(Manifest.permission.ACCESS_COARSE_LOCATION))
permissionNames.add(Manifest.permission.ACCESS_COARSE_LOCATION)
if(hasPermissionInManifest(Manifest.permission.ACCESS_FINE_LOCATION))
permissionNames.add(Manifest.permission.ACCESS_FINE_LOCATION)
}
PermissionGroup.SPEECH,
PermissionGroup.MICROPHONE ->
{
if(hasPermissionInManifest(Manifest.permission.RECORD_AUDIO))
permissionNames.add(Manifest.permission.RECORD_AUDIO)
}
PermissionGroup.PHONE ->
{
if(hasPermissionInManifest(Manifest.permission.READ_PHONE_STATE))
permissionNames.add(Manifest.permission.READ_PHONE_STATE)
if(hasPermissionInManifest(Manifest.permission.CALL_PHONE))
permissionNames.add(Manifest.permission.CALL_PHONE)
if(hasPermissionInManifest(Manifest.permission.READ_CALL_LOG))
permissionNames.add(Manifest.permission.READ_CALL_LOG)
if(hasPermissionInManifest(Manifest.permission.WRITE_CALL_LOG))
permissionNames.add(Manifest.permission.WRITE_CALL_LOG)
if(hasPermissionInManifest(Manifest.permission.ADD_VOICEMAIL))
permissionNames.add(Manifest.permission.ADD_VOICEMAIL)
if(hasPermissionInManifest(Manifest.permission.USE_SIP))
permissionNames.add(Manifest.permission.USE_SIP)
if(hasPermissionInManifest(Manifest.permission.PROCESS_OUTGOING_CALLS))
permissionNames.add(Manifest.permission.PROCESS_OUTGOING_CALLS)
}
PermissionGroup.SENSORS -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
if (hasPermissionInManifest(Manifest.permission.BODY_SENSORS)) {
permissionNames.add(Manifest.permission.BODY_SENSORS)
}
private fun getManifestNames(permission: PermissionGroup): List<String>? {
val permissionNames: MutableList<String> = mutableListOf()
when (permission) {
PermissionGroup.CALENDAR -> {
if (hasPermissionInManifest(Manifest.permission.READ_CALENDAR))
permissionNames.add(Manifest.permission.READ_CALENDAR)
if (hasPermissionInManifest(Manifest.permission.WRITE_CALENDAR))
permissionNames.add(Manifest.permission.WRITE_CALENDAR)
}
PermissionGroup.CAMERA -> {
if (hasPermissionInManifest(Manifest.permission.CAMERA))
permissionNames.add(Manifest.permission.CAMERA)
}
PermissionGroup.CONTACTS -> {
if (hasPermissionInManifest(Manifest.permission.READ_CONTACTS))
permissionNames.add(Manifest.permission.READ_CONTACTS)
if (hasPermissionInManifest(Manifest.permission.WRITE_CONTACTS))
permissionNames.add(Manifest.permission.WRITE_CONTACTS)
if (hasPermissionInManifest(Manifest.permission.GET_ACCOUNTS))
permissionNames.add(Manifest.permission.GET_ACCOUNTS)
}
PermissionGroup.LOCATION_ALWAYS,
PermissionGroup.LOCATION_WHEN_IN_USE,
PermissionGroup.LOCATION -> {
if (hasPermissionInManifest(Manifest.permission.ACCESS_COARSE_LOCATION))
permissionNames.add(Manifest.permission.ACCESS_COARSE_LOCATION)
if (hasPermissionInManifest(Manifest.permission.ACCESS_FINE_LOCATION))
permissionNames.add(Manifest.permission.ACCESS_FINE_LOCATION)
}
PermissionGroup.SPEECH,
PermissionGroup.MICROPHONE -> {
if (hasPermissionInManifest(Manifest.permission.RECORD_AUDIO))
permissionNames.add(Manifest.permission.RECORD_AUDIO)
}
PermissionGroup.PHONE -> {
if (hasPermissionInManifest(Manifest.permission.READ_PHONE_STATE))
permissionNames.add(Manifest.permission.READ_PHONE_STATE)
if (hasPermissionInManifest(Manifest.permission.CALL_PHONE))
permissionNames.add(Manifest.permission.CALL_PHONE)
if (hasPermissionInManifest(Manifest.permission.READ_CALL_LOG))
permissionNames.add(Manifest.permission.READ_CALL_LOG)
if (hasPermissionInManifest(Manifest.permission.WRITE_CALL_LOG))
permissionNames.add(Manifest.permission.WRITE_CALL_LOG)
if (hasPermissionInManifest(Manifest.permission.ADD_VOICEMAIL))
permissionNames.add(Manifest.permission.ADD_VOICEMAIL)
if (hasPermissionInManifest(Manifest.permission.USE_SIP))
permissionNames.add(Manifest.permission.USE_SIP)
if (hasPermissionInManifest(Manifest.permission.PROCESS_OUTGOING_CALLS))
permissionNames.add(Manifest.permission.PROCESS_OUTGOING_CALLS)
}
PermissionGroup.SENSORS -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
if (hasPermissionInManifest(Manifest.permission.BODY_SENSORS)) {
permissionNames.add(Manifest.permission.BODY_SENSORS)
}
}
}
PermissionGroup.SMS -> {
if (hasPermissionInManifest(Manifest.permission.SEND_SMS))
permissionNames.add(Manifest.permission.SEND_SMS)
if (hasPermissionInManifest(Manifest.permission.RECEIVE_SMS))
permissionNames.add(Manifest.permission.RECEIVE_SMS)
if (hasPermissionInManifest(Manifest.permission.READ_SMS))
permissionNames.add(Manifest.permission.READ_SMS)
if (hasPermissionInManifest(Manifest.permission.RECEIVE_WAP_PUSH))
permissionNames.add(Manifest.permission.RECEIVE_WAP_PUSH)
if (hasPermissionInManifest(Manifest.permission.RECEIVE_MMS))
permissionNames.add(Manifest.permission.RECEIVE_MMS)
}
PermissionGroup.STORAGE -> {
if (hasPermissionInManifest(Manifest.permission.READ_EXTERNAL_STORAGE))
permissionNames.add(Manifest.permission.READ_EXTERNAL_STORAGE)
if (hasPermissionInManifest(Manifest.permission.WRITE_EXTERNAL_STORAGE))
permissionNames.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
else -> return null
}
}
PermissionGroup.SMS ->
{
if(hasPermissionInManifest(Manifest.permission.SEND_SMS))
permissionNames.add(Manifest.permission.SEND_SMS)
if(hasPermissionInManifest(Manifest.permission.RECEIVE_SMS))
permissionNames.add(Manifest.permission.RECEIVE_SMS)
if(hasPermissionInManifest(Manifest.permission.READ_SMS))
permissionNames.add(Manifest.permission.READ_SMS)
if(hasPermissionInManifest(Manifest.permission.RECEIVE_WAP_PUSH))
permissionNames.add(Manifest.permission.RECEIVE_WAP_PUSH)
if(hasPermissionInManifest(Manifest.permission.RECEIVE_MMS))
permissionNames.add(Manifest.permission.RECEIVE_MMS)
}
PermissionGroup.STORAGE ->
{
if(hasPermissionInManifest(Manifest.permission.READ_EXTERNAL_STORAGE))
permissionNames.add(Manifest.permission.READ_EXTERNAL_STORAGE)
if(hasPermissionInManifest(Manifest.permission.WRITE_EXTERNAL_STORAGE))
permissionNames.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
else -> return null
return permissionNames
}
return permissionNames
}
private fun hasPermissionInManifest(permission: String): Boolean {
try {
requestedPermissions?.let {
return it.any { r -> r.equals(permission, true) }
}
private fun hasPermissionInManifest(permission: String) : Boolean
{
try
{
requestedPermissions?.let {
return it.any { r -> r.equals(permission, true) }
}
val context: Context? = registrar.activity() ?: registrar.activeContext()
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return false
}
if (context == null)
{
Log.d(logTag, "Unable to detect current Activity or App Context. Please ensure Plugin.CurrentActivity is installed in your Android project and your Application class is registering with Application.IActivityLifecycleCallbacks.")
return false
}
val info: PackageInfo? = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
val info: PackageInfo? = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
if (info == null) {
Log.d(mLogTag, "Unable to get Package info, will not be able to determine permissions to request.")
return false
}
if(info == null)
{
Log.d(logTag, "Unable to get Package info, will not be able to determine permissions to request.")
return false
}
requestedPermissions = info.requestedPermissions.toMutableList()
requestedPermissions = info.requestedPermissions.toMutableList()
if (requestedPermissions == null) {
Log.d(mLogTag, "There are no requested permissions, please check to ensure you have marked permissions you want to request.")
return false
}
if (requestedPermissions == null)
{
Log.d(logTag, "There are no requested permissions, please check to ensure you have marked permissions you want to request.")
requestedPermissions?.let {
return it.any { r -> r.equals(permission, true) }
} ?: return false
} catch (ex: Exception) {
Log.d(mLogTag, "Unable to check manifest for permission: $ex")
}
return false
}
requestedPermissions?.let {
return it.any { r -> r.equals(permission, true) }
} ?: return false
}
catch(ex: Exception)
{
Log.d(logTag,"Unable to check manifest for permission: $ex")
}
return false
}
private fun handleSuccess(permissionStatus: PermissionStatus, result: Result) {
result.success(Codec.encodePermissionStatus(permissionStatus))
}
private fun handleSuccess(permissionStatus: PermissionStatus, result: Result?) {
result?.success(Codec.encodePermissionStatus(permissionStatus))
}
}
......@@ -3,10 +3,13 @@ package com.baseflow.permissionhandler.utils
import com.baseflow.permissionhandler.data.PermissionGroup
import com.baseflow.permissionhandler.data.PermissionStatus
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
class Codec {
companion object {
@JvmStatic val gsonDecoder : Gson = Gson()
@JvmStatic
private val gsonDecoder : Gson = GsonBuilder().enableComplexMapKeySerialization().create()
@JvmStatic
fun decodePermissionGroup(arguments: Any) : PermissionGroup {
......@@ -14,8 +17,21 @@ class Codec {
}
@JvmStatic
fun decodePermissionGroups(arguments: Any) : Array<PermissionGroup> {
var permissionGroupsType = object: TypeToken<Array<PermissionGroup>>() {}.type
return Codec.gsonDecoder.fromJson(arguments.toString(), permissionGroupsType)
}
@JvmStatic
fun encodePermissionStatus(permissionStatus: PermissionStatus) : String {
return gsonDecoder.toJson(permissionStatus)
}
@JvmStatic
fun encodePermissionRequestResult(permissionResults: Map<PermissionGroup, PermissionStatus>) : String {
val jsonString = gsonDecoder.toJson(permissionResults)
return jsonString
}
}
}
\ No newline at end of file
......@@ -20,6 +20,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
F83E7534C5D827024000AB4C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36F84C9A972D968241208A7F /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
......@@ -41,6 +42,7 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
36F84C9A972D968241208A7F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
......@@ -63,12 +65,21 @@
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
F83E7534C5D827024000AB4C /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1850378EF7B1AE3FA40E4F87 /* Frameworks */ = {
isa = PBXGroup;
children = (
36F84C9A972D968241208A7F /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
......@@ -89,6 +100,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
A2B39E4F789ABF9C57736776 /* Pods */,
1850378EF7B1AE3FA40E4F87 /* Frameworks */,
);
sourceTree = "<group>";
};
......@@ -123,6 +136,13 @@
name = "Supporting Files";
sourceTree = "<group>";
};
A2B39E4F789ABF9C57736776 /* Pods */ = {
isa = PBXGroup;
children = (
);
name = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
......@@ -130,12 +150,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
E8ED1A28A9A0730EDF0565B2 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
259652FD16940B446BA7C6C6 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
......@@ -197,6 +219,26 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
259652FD16940B446BA7C6C6 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/permission_handler/permission_handler.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/permission_handler.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
......@@ -225,6 +267,24 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
E8ED1A28A9A0730EDF0565B2 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
......
......@@ -4,4 +4,7 @@
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
......@@ -27,6 +27,13 @@ class _MyAppState extends State<MyApp> {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
permissionStatus = await PermissionHandler.checkPermissionStatus(PermissionGroup.calendar);
if(permissionStatus != PermissionStatus.granted){
var permissions = await PermissionHandler.requestPermissions([PermissionGroup.calendar]);
if(permissions.containsKey(PermissionGroup.calendar)) {
permissionStatus = permissions[PermissionGroup.calendar];
}
}
} on PlatformException {
permissionStatus = PermissionStatus.unknown;
}
......
......@@ -11,7 +11,22 @@ class PermissionHandler {
/// Returns a [Future] containing the current permission status for the supplied [PermissionGroup].
static Future<PermissionStatus> checkPermissionStatus(PermissionGroup permission) async {
final status = await _channel.invokeMethod('checkPermissionStatus', Codec.encodePermissionGroup(permission));
final status = await _channel.invokeMethod(
'checkPermissionStatus',
Codec.encodePermissionGroup(permission));
return Codec.decodePermissionStatus(status);
}
static Future<bool> openAppSettings() async =>
await _channel.invokeMethod("openAppSettings");
static Future<Map<PermissionGroup, PermissionStatus>> requestPermissions(List<PermissionGroup> permissions) async {
final jsonData = Codec.encodePermissionGroups(permissions);
final status = await _channel.invokeMethod(
'requestPermissions',
jsonData);
return Codec.decodePermissionRequestResult(status);
}
}
......@@ -8,10 +8,27 @@ class Codec {
return PermissionStatus.values.firstWhere((e) => e.toString().split('.').last == permission);
}
static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult(dynamic value) {
final jsonObject = json.decode(value);
final permissionResults = Map<PermissionGroup, PermissionStatus>();
jsonObject.forEach((key, value) {
final permissionGroup = PermissionGroup.values.firstWhere((e) => e.toString().split('.').last == key.toString());
final permissionStatus = PermissionStatus.values.firstWhere((e) => e.toString().split('.').last == value.toString());
permissionResults[permissionGroup] = permissionStatus;
});
return permissionResults;
}
static String encodePermissionGroup(PermissionGroup permissionGroup) =>
json.encode(_encodeEnum(permissionGroup));
static String encodePermissionGroups(List<PermissionGroup> permissions) =>
json.encode(permissions.map((p) => _encodeEnum(p)).toList());
static String _encodeEnum(dynamic value) {
return value.toString().split('.').last;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment