Commit 1c81b9a7 by Maurits van Beusekom Committed by GitHub

Merge pull request #2 from BaseflowIT/feature/android_should_show_rationale

Request to see if you should show a rationale for requesting permission (only for Android)
parents afe7f77d b3439372
......@@ -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,22 +16,38 @@ 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"
const val permissionCode = 25
@JvmStatic
private val mLogTag = "permissions_handler"
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "flutter.baseflow.com/permissions/methods")
channel.setMethodCallHandler(PermissionHandlerPlugin(registrar))
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
{
fun parseManifestName(permission: String): PermissionGroup {
when (permission) {
Manifest.permission.READ_CALENDAR,
......@@ -72,123 +90,272 @@ class PermissionHandlerPlugin(private val registrar: Registrar, private var requ
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "checkPermissionStatus") {
when {
call.method == "checkPermissionStatus" -> {
val permission = Codec.decodePermissionGroup(call.arguments)
checkPermissionStatus(permission, result)
} else {
result.notImplemented()
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 == "shouldShowRequestPermissionRationale" -> {
val permission = Codec.decodePermissionGroup(call.arguments)
result.success(shouldShowRequestPermissionRationale(permission))
}
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
private fun checkPermissionStatus(permission: PermissionGroup, result: Result)
for (name in names) {
if (targetsMOrHigher && ContextCompat.checkSelfPermission(context, name) != PackageManager.PERMISSION_GRANTED) {
return PermissionStatus.DENIED
}
}
return PermissionStatus.GRANTED
}
private fun shouldShowRequestPermissionRationale(permission: PermissionGroup) : Boolean {
val activity = registrar.activity()
if(activity == null)
{
Log.d(mLogTag, "Unable to detect current Activity.")
return false
}
val names = getManifestNames(permission)
// if isn't an android specific group then go ahead and return false;
if (names == null)
{
Log.d(logTag, "No android specific permissions needed for: $permission")
handleSuccess(PermissionStatus.GRANTED, result)
return
Log.d(mLogTag, "No android specific permissions needed for: $permission")
return false
}
//if no permissions were found then there is an issue and persmission is not set in Android manifest
if (names.count() == 0)
if (names.isEmpty())
{
Log.d(logTag, "No permissions found in manifest for: $permission")
handleSuccess(PermissionStatus.UNKNOWN, result)
return
Log.d(mLogTag,"No permissions found in manifest for: $permission no need to show request rationale")
return false
}
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null)
for(name in names)
{
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 ActivityCompat.shouldShowRequestPermissionRationale(activity, name)
}
return false
}
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 targetsMOrHigher = context.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.M
val permissionsToRequest = mutableListOf<String>()
for (permission in permissions) {
val permissionStatus = checkPermissionStatus(permission)
for (name in names)
{
if (targetsMOrHigher && ContextCompat.checkSelfPermission(context, name) != PackageManager.PERMISSION_GRANTED) {
handleSuccess(PermissionStatus.DENIED, result)
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 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()
}
handleSuccess(PermissionStatus.GRANTED, result)
if (!mRequestResults.containsKey(PermissionGroup.LOCATION_WHEN_IN_USE)) {
mRequestResults[PermissionGroup.LOCATION_WHEN_IN_USE] = grantResults[i].toPermissionStatus()
}
}
private fun getManifestNames(permission: PermissionGroup) : List<String>?
{
val permissionNames : MutableList<String> = mutableListOf()
if (!mRequestResults.containsKey(permission)) {
mRequestResults[permission] = grantResults[i].toPermissionStatus()
}
when(permission) {
PermissionGroup.CALENDAR ->
{
if(hasPermissionInManifest(Manifest.permission.READ_CALENDAR))
}
processResult()
}
private fun Int.toPermissionStatus(): PermissionStatus {
return if (this == PackageManager.PERMISSION_GRANTED) PermissionStatus.GRANTED else PermissionStatus.DENIED
}
private fun processResult() {
mResult?.success(Codec.encodePermissionRequestResult(mRequestResults))
mRequestResults.clear()
mResult = null
}
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
}
return try {
val 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)
true
} catch(ex: Exception) {
false
}
}
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))
if (hasPermissionInManifest(Manifest.permission.WRITE_CALENDAR))
permissionNames.add(Manifest.permission.WRITE_CALENDAR)
}
PermissionGroup.CAMERA ->
{
if(hasPermissionInManifest(Manifest.permission.CAMERA))
PermissionGroup.CAMERA -> {
if (hasPermissionInManifest(Manifest.permission.CAMERA))
permissionNames.add(Manifest.permission.CAMERA)
}
PermissionGroup.CONTACTS ->
{
if(hasPermissionInManifest(Manifest.permission.READ_CONTACTS))
PermissionGroup.CONTACTS -> {
if (hasPermissionInManifest(Manifest.permission.READ_CONTACTS))
permissionNames.add(Manifest.permission.READ_CONTACTS)
if(hasPermissionInManifest(Manifest.permission.WRITE_CONTACTS))
if (hasPermissionInManifest(Manifest.permission.WRITE_CONTACTS))
permissionNames.add(Manifest.permission.WRITE_CONTACTS)
if(hasPermissionInManifest(Manifest.permission.GET_ACCOUNTS))
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))
PermissionGroup.LOCATION -> {
if (hasPermissionInManifest(Manifest.permission.ACCESS_COARSE_LOCATION))
permissionNames.add(Manifest.permission.ACCESS_COARSE_LOCATION)
if(hasPermissionInManifest(Manifest.permission.ACCESS_FINE_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))
PermissionGroup.MICROPHONE -> {
if (hasPermissionInManifest(Manifest.permission.RECORD_AUDIO))
permissionNames.add(Manifest.permission.RECORD_AUDIO)
}
PermissionGroup.PHONE ->
{
if(hasPermissionInManifest(Manifest.permission.READ_PHONE_STATE))
PermissionGroup.PHONE -> {
if (hasPermissionInManifest(Manifest.permission.READ_PHONE_STATE))
permissionNames.add(Manifest.permission.READ_PHONE_STATE)
if(hasPermissionInManifest(Manifest.permission.CALL_PHONE))
if (hasPermissionInManifest(Manifest.permission.CALL_PHONE))
permissionNames.add(Manifest.permission.CALL_PHONE)
if(hasPermissionInManifest(Manifest.permission.READ_CALL_LOG))
if (hasPermissionInManifest(Manifest.permission.READ_CALL_LOG))
permissionNames.add(Manifest.permission.READ_CALL_LOG)
if(hasPermissionInManifest(Manifest.permission.WRITE_CALL_LOG))
if (hasPermissionInManifest(Manifest.permission.WRITE_CALL_LOG))
permissionNames.add(Manifest.permission.WRITE_CALL_LOG)
if(hasPermissionInManifest(Manifest.permission.ADD_VOICEMAIL))
if (hasPermissionInManifest(Manifest.permission.ADD_VOICEMAIL))
permissionNames.add(Manifest.permission.ADD_VOICEMAIL)
if(hasPermissionInManifest(Manifest.permission.USE_SIP))
if (hasPermissionInManifest(Manifest.permission.USE_SIP))
permissionNames.add(Manifest.permission.USE_SIP)
if(hasPermissionInManifest(Manifest.permission.PROCESS_OUTGOING_CALLS))
if (hasPermissionInManifest(Manifest.permission.PROCESS_OUTGOING_CALLS))
permissionNames.add(Manifest.permission.PROCESS_OUTGOING_CALLS)
}
PermissionGroup.SENSORS -> {
......@@ -199,30 +366,28 @@ class PermissionHandlerPlugin(private val registrar: Registrar, private var requ
}
}
PermissionGroup.SMS ->
{
if(hasPermissionInManifest(Manifest.permission.SEND_SMS))
PermissionGroup.SMS -> {
if (hasPermissionInManifest(Manifest.permission.SEND_SMS))
permissionNames.add(Manifest.permission.SEND_SMS)
if(hasPermissionInManifest(Manifest.permission.RECEIVE_SMS))
if (hasPermissionInManifest(Manifest.permission.RECEIVE_SMS))
permissionNames.add(Manifest.permission.RECEIVE_SMS)
if(hasPermissionInManifest(Manifest.permission.READ_SMS))
if (hasPermissionInManifest(Manifest.permission.READ_SMS))
permissionNames.add(Manifest.permission.READ_SMS)
if(hasPermissionInManifest(Manifest.permission.RECEIVE_WAP_PUSH))
if (hasPermissionInManifest(Manifest.permission.RECEIVE_WAP_PUSH))
permissionNames.add(Manifest.permission.RECEIVE_WAP_PUSH)
if(hasPermissionInManifest(Manifest.permission.RECEIVE_MMS))
if (hasPermissionInManifest(Manifest.permission.RECEIVE_MMS))
permissionNames.add(Manifest.permission.RECEIVE_MMS)
}
PermissionGroup.STORAGE ->
{
if(hasPermissionInManifest(Manifest.permission.READ_EXTERNAL_STORAGE))
PermissionGroup.STORAGE -> {
if (hasPermissionInManifest(Manifest.permission.READ_EXTERNAL_STORAGE))
permissionNames.add(Manifest.permission.READ_EXTERNAL_STORAGE)
if(hasPermissionInManifest(Manifest.permission.WRITE_EXTERNAL_STORAGE))
if (hasPermissionInManifest(Manifest.permission.WRITE_EXTERNAL_STORAGE))
permissionNames.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
else -> return null
......@@ -231,50 +396,43 @@ class PermissionHandlerPlugin(private val registrar: Registrar, private var requ
return permissionNames
}
private fun hasPermissionInManifest(permission: String) : Boolean
{
try
{
private fun hasPermissionInManifest(permission: String): Boolean {
try {
requestedPermissions?.let {
return it.any { r -> r.equals(permission, true) }
}
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.")
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return false
}
val info: PackageInfo? = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
if(info == null)
{
Log.d(logTag, "Unable to get Package info, will not be able to determine permissions to request.")
if (info == null) {
Log.d(mLogTag, "Unable to get Package info, will not be able to determine permissions to request.")
return false
}
requestedPermissions = info.requestedPermissions.toMutableList()
if (requestedPermissions == null)
{
Log.d(logTag, "There are no requested permissions, please check to ensure you have marked permissions you want to request.")
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
}
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")
} catch (ex: Exception) {
Log.d(mLogTag, "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>
......@@ -24,9 +24,21 @@ class _MyAppState extends State<MyApp> {
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
PermissionStatus permissionStatus;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
permissionStatus = await PermissionHandler.checkPermissionStatus(PermissionGroup.calendar);
if(permissionStatus != PermissionStatus.granted){
final shouldShowRationale = await PermissionHandler.shouldShowRequestPermissionRationale(PermissionGroup.calendar);
if(shouldShowRationale) {
var permissions = await PermissionHandler.requestPermissions([PermissionGroup.calendar]);
if(permissions.containsKey(PermissionGroup.calendar)) {
permissionStatus = permissions[PermissionGroup.calendar];
}
}
}
} on PlatformException {
permissionStatus = PermissionStatus.unknown;
}
......@@ -49,7 +61,15 @@ class _MyAppState extends State<MyApp> {
title: const Text('Plugin example app'),
),
body: new Center(
child: new Text('Running on: $_permissionStatus\n'),
child: new Column(
children: <Widget>[
new Text('Running on: $_permissionStatus\n'),
new RaisedButton(
child: new Text("Open settings"),
onPressed: () async => await PermissionHandler.openAppSettings(),
),
],
),
),
),
);
......
......@@ -11,7 +11,38 @@ 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);
}
/// Open the App settings page.
///
/// Returns [true] if the app settings page could be opened, otherwise [false] is returned.
static Future<bool> openAppSettings() async =>
await _channel.invokeMethod("openAppSettings");
/// Request the user for access to the supplied list of permissiongroups.
///
/// Returns a [Map] containing the status per requested permissiongroup.
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);
}
/// Request to see if you should show a rationale for requesting permission.
///
/// This method is only implemented on Android, calling this on iOS always
/// returns [false].
static Future<bool> shouldShowRequestPermissionRationale(PermissionGroup permission) async =>
await _channel.invokeMethod(
'shouldShowRequestPermissionRationale',
Codec.encodePermissionGroup(permission));
}
......@@ -9,9 +9,26 @@ 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