Skip to content

Commit

Permalink
Merge pull request #2 from BaseflowIT/feature/android_should_show_rat…
Browse files Browse the repository at this point in the history
…ionale

Request to see if you should show a rationale for requesting permission (only for Android)
  • Loading branch information
mvanbeusekom committed Jul 23, 2018
2 parents afe7f77 + b343937 commit 1c81b9a
Show file tree
Hide file tree
Showing 8 changed files with 539 additions and 234 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,35 @@ 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 {
return Codec.gsonDecoder.fromJson(arguments.toString(), PermissionGroup::class.java)
}

@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
}
}
}
Binary file modified example/android/.idea/caches/build_file_checksums.ser
Binary file not shown.
60 changes: 60 additions & 0 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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>"; };
Expand All @@ -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 = (
Expand All @@ -89,6 +100,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
A2B39E4F789ABF9C57736776 /* Pods */,
1850378EF7B1AE3FA40E4F87 /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -123,19 +136,28 @@
name = "Supporting Files";
sourceTree = "<group>";
};
A2B39E4F789ABF9C57736776 /* Pods */ = {
isa = PBXGroup;
children = (
);
name = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
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 = (
);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down
3 changes: 3 additions & 0 deletions example/ios/Runner.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 21 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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(),
),
],
),
),
),
);
Expand Down
33 changes: 32 additions & 1 deletion lib/permission_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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));

}
17 changes: 17 additions & 0 deletions lib/utils/codec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 1c81b9a

Please sign in to comment.