Commit 05a0191c by Maurits van Beusekom

Merge branch 'develop'

parents 2612cf36 bf128819
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 06b979c4d5e1b499745422269f01a00341257058
channel: master
project_type: plugin
# Specify analysis options.
#
# Until there are meta linter rules, each desired lint must be explicitly enabled.
# See: https://github.com/dart-lang/linter/issues/288
#
# For a list of lints, see: http://dart-lang.github.io/linter/lints/
# See the configuration guide for more
# https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer
#
# There are other similar analysis options files in the flutter repos,
# which should be kept in sync with this file:
#
# - analysis_options.yaml (this file)
# - packages/flutter/lib/analysis_options_user.yaml
# - https://github.com/flutter/plugins/blob/master/analysis_options.yaml
# - https://github.com/flutter/engine/blob/master/analysis_options.yaml
#
# This file contains the analysis options used by Flutter tools, such as IntelliJ,
# Android Studio, and the `flutter analyze` command.
analyzer: analyzer:
strong-mode: strong-mode:
implicit-dynamic: false implicit-dynamic: false
errors: errors:
# treat missing required parameters as a warning (not a hint)
missing_required_param: warning missing_required_param: warning
# treat missing returns as a warning (not a hint)
missing_return: warning missing_return: warning
# allow having TODOs in the code
todo: ignore todo: ignore
# Ignore analyzer hints for updating pubspecs when using Future or
# Stream and not importing dart:async
# Please see https://github.com/flutter/flutter/pull/24528 for details.
#sdk_version_async_exported_from_core: ignore
exclude:
- 'bin/cache/**'
# the following two are relative to the stocks example and the flutter package respectively
# see https://github.com/dart-lang/sdk/issues/28463
- 'lib/i18n/stock_messages_*.dart'
- 'lib/src/http/**'
linter: linter:
rules: rules:
# these rules are documented on and in the same order as
# the Dart Lint rules page to make maintenance easier
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
- always_declare_return_types - always_declare_return_types
- always_put_control_body_on_new_line - always_put_control_body_on_new_line
# - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219
- always_require_non_null_named_parameters - always_require_non_null_named_parameters
- always_specify_types - always_specify_types
- annotate_overrides - annotate_overrides
# - avoid_annotating_with_dynamic # conflicts with always_specify_types
- avoid_as - avoid_as
# - avoid_bool_literals_in_conditional_expressions # not yet tested
# - avoid_catches_without_on_clauses # we do this commonly
# - avoid_catching_errors # we do this commonly
- avoid_classes_with_only_static_members - avoid_classes_with_only_static_members
# - avoid_double_and_int_checks # only useful when targeting JS runtime
- avoid_empty_else - avoid_empty_else
- avoid_field_initializers_in_const_classes - avoid_field_initializers_in_const_classes
- avoid_function_literals_in_foreach_calls - avoid_function_literals_in_foreach_calls
# - avoid_implementing_value_types # not yet tested
- avoid_init_to_null - avoid_init_to_null
# - avoid_js_rounded_ints # only useful when targeting JS runtime
- avoid_null_checks_in_equality_operators - avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters # not yet tested
# - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356)
- avoid_relative_lib_imports - avoid_relative_lib_imports
- avoid_renaming_method_parameters - avoid_renaming_method_parameters
- avoid_return_types_on_setters - avoid_return_types_on_setters
# - avoid_returning_null # there are plenty of valid reasons to return null
# - avoid_returning_null_for_future # not yet tested
- avoid_returning_null_for_void - avoid_returning_null_for_void
# - avoid_returning_this # there are plenty of valid reasons to return this
# - avoid_setters_without_getters # not yet tested
# - avoid_shadowing_type_parameters # not yet tested
# - avoid_single_cascade_in_expression_statements # not yet tested
- avoid_slow_async_io - avoid_slow_async_io
- avoid_types_as_parameter_names - avoid_types_as_parameter_names
# - avoid_types_on_closure_parameters # conflicts with always_specify_types
- avoid_unused_constructor_parameters - avoid_unused_constructor_parameters
- avoid_void_async - avoid_void_async
- await_only_futures - await_only_futures
- camel_case_types - camel_case_types
- cancel_subscriptions - cancel_subscriptions
# - cascade_invocations # not yet tested
# - close_sinks # not reliable enough
# - comment_references # blocked on https://github.com/flutter/flutter/issues/20765
# - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204
- control_flow_in_finally - control_flow_in_finally
# - curly_braces_in_flow_control_structures # not yet tested
- directives_ordering - directives_ordering
- empty_catches - empty_catches
- empty_constructor_bodies - empty_constructor_bodies
- empty_statements - empty_statements
# - file_names # not yet tested
- flutter_style_todos - flutter_style_todos
- hash_and_equals - hash_and_equals
- implementation_imports - implementation_imports
# - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811
- iterable_contains_unrelated_type - iterable_contains_unrelated_type
# - join_return_with_assignment # not yet tested
- library_names - library_names
- library_prefixes - library_prefixes
# - lines_longer_than_80_chars # not yet tested
- list_remove_unrelated_type - list_remove_unrelated_type
# - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181
- no_adjacent_strings_in_list - no_adjacent_strings_in_list
- no_duplicate_case_values - no_duplicate_case_values
- non_constant_identifier_names - non_constant_identifier_names
# - null_closures # not yet tested
# - omit_local_variable_types # opposite of always_specify_types
# - one_member_abstracts # too many false positives
# - only_throw_errors # https://github.com/flutter/flutter/issues/5792
- overridden_fields - overridden_fields
- package_api_docs - package_api_docs
- package_names - package_names
- package_prefixed_library_names - package_prefixed_library_names
# - parameter_assignments # we do this commonly
- prefer_adjacent_string_concatenation - prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists - prefer_asserts_in_initializer_lists
- prefer_collection_literals
- prefer_conditional_assignment - prefer_conditional_assignment
- prefer_const_constructors - prefer_const_constructors
- prefer_const_constructors_in_immutables - prefer_const_constructors_in_immutables
- prefer_const_declarations - prefer_const_declarations
- prefer_const_literals_to_create_immutables - prefer_const_literals_to_create_immutables
# - prefer_constructors_over_static_methods # not yet tested
- prefer_contains - prefer_contains
- prefer_equal_for_default_values - prefer_equal_for_default_values
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
- prefer_final_fields - prefer_final_fields
- prefer_final_locals - prefer_final_locals
- prefer_foreach - prefer_foreach
# - prefer_function_declarations_over_variables # not yet tested
- prefer_generic_function_type_aliases - prefer_generic_function_type_aliases
- prefer_initializing_formals - prefer_initializing_formals
# - prefer_int_literals # not yet tested
# - prefer_interpolation_to_compose_strings # not yet tested
- prefer_is_empty - prefer_is_empty
- prefer_is_not_empty - prefer_is_not_empty
- prefer_iterable_whereType - prefer_iterable_whereType
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
- prefer_single_quotes - prefer_single_quotes
- prefer_typing_uninitialized_variables - prefer_typing_uninitialized_variables
- prefer_void_to_null - prefer_void_to_null
# - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml
- recursive_getters - recursive_getters
- slash_for_doc_comments - slash_for_doc_comments
- sort_constructors_first - sort_constructors_first
- sort_pub_dependencies - sort_pub_dependencies
- sort_unnamed_constructors_first - sort_unnamed_constructors_first
- super_goes_last
- test_types_in_equals - test_types_in_equals
- throw_in_finally - throw_in_finally
# - type_annotate_public_apis # subset of always_specify_types
- type_init_formals - type_init_formals
# - unawaited_futures # too many false positives
# - unnecessary_await_in_return # not yet tested
- unnecessary_brace_in_string_interps - unnecessary_brace_in_string_interps
- unnecessary_const - unnecessary_const
- unnecessary_getters_setters - unnecessary_getters_setters
# - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498
- unnecessary_new - unnecessary_new
- unnecessary_null_aware_assignments - unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators - unnecessary_null_in_if_null_operators
...@@ -170,10 +89,5 @@ linter: ...@@ -170,10 +89,5 @@ linter:
- unnecessary_statements - unnecessary_statements
- unnecessary_this - unnecessary_this
- unrelated_type_equality_checks - unrelated_type_equality_checks
# - use_function_type_syntax_for_parameters # not yet tested
- use_rethrow_when_possible - use_rethrow_when_possible
# - use_setters_to_change_properties # not yet tested - valid_regexps
# - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 \ No newline at end of file
# - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
- valid_regexps
# - void_checks # not yet tested
\ No newline at end of file
...@@ -2,15 +2,14 @@ group 'com.baseflow.permissionhandler' ...@@ -2,15 +2,14 @@ group 'com.baseflow.permissionhandler'
version '1.0-SNAPSHOT' version '1.0-SNAPSHOT'
buildscript { buildscript {
ext.kotlin_version = '1.3.0'
repositories { repositories {
google() google()
jcenter() jcenter()
maven { url 'https://maven.google.com' }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.0' classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
...@@ -22,14 +21,10 @@ rootProject.allprojects { ...@@ -22,14 +21,10 @@ rootProject.allprojects {
} }
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 28 compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
...@@ -40,8 +35,10 @@ android { ...@@ -40,8 +35,10 @@ android {
} }
dependencies { dependencies {
api 'androidx.core:core:1.0.1' implementation 'androidx.annotation:annotation:1.0.1'
implementation 'androidx.core:core:1.0.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.google.code.gson:gson:2.8.5"
} }
repositories {
google()
}
\ No newline at end of file
package com.baseflow.permissionhandler.data
import com.google.gson.annotations.SerializedName
enum class PermissionGroup {
@SerializedName("unknown")
UNKNOWN,
@SerializedName("calendar")
CALENDAR,
@SerializedName("camera")
CAMERA,
@SerializedName("contacts")
CONTACTS,
@SerializedName("location")
LOCATION,
@SerializedName("microphone")
MICROPHONE,
@SerializedName("phone")
PHONE,
@SerializedName("photos")
PHOTOS,
@SerializedName("reminders")
REMINDERS,
@SerializedName("sensors")
SENSORS,
@SerializedName("sms")
SMS,
@SerializedName("storage")
STORAGE,
@SerializedName("speech")
SPEECH,
@SerializedName("locationAlways")
LOCATION_ALWAYS,
@SerializedName("locationWhenInUse")
LOCATION_WHEN_IN_USE,
@SerializedName("mediaLibrary")
MEDIA_LIBRARY
}
\ No newline at end of file
package com.baseflow.permissionhandler.data
import com.google.gson.annotations.SerializedName
enum class PermissionStatus {
@SerializedName("unknown")
UNKNOWN,
@SerializedName("denied")
DENIED,
@SerializedName("disabled")
DISABLED,
@SerializedName("granted")
GRANTED,
}
\ No newline at end of file
package com.baseflow.permissionhandler.data
import com.google.gson.annotations.SerializedName
enum class ServiceStatus {
@SerializedName("unknown")
UNKNOWN,
@SerializedName("disabled")
DISABLED,
@SerializedName("enabled")
ENABLED,
@SerializedName("notApplicable")
NOT_APPLICABLE,
}
\ No newline at end of file
package com.baseflow.permissionhandler.utils
import com.baseflow.permissionhandler.data.PermissionGroup
import com.baseflow.permissionhandler.data.PermissionStatus
import com.baseflow.permissionhandler.data.ServiceStatus
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
class Codec {
companion object {
@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 encodeServiceStatus(serviceStatus: ServiceStatus) : String {
return gsonDecoder.toJson(serviceStatus)
}
@JvmStatic
fun encodePermissionRequestResult(permissionResults: Map<PermissionGroup, PermissionStatus>) : String {
val jsonString = gsonDecoder.toJson(permissionResults)
return jsonString
}
}
}
\ No newline at end of file
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store .DS_Store
.dart_tool/ .atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.vscode/
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.packages .packages
.pub-cache/
.pub/ .pub/
build/ build/
.flutter-plugins # Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
<component name="libraryTable"> <component name="libraryTable">
<library name="Dart SDK"> <library name="Dart SDK">
<CLASSES> <CLASSES>
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/async" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/async" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/collection" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/collection" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/convert" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/convert" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/core" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/core" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/developer" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/developer" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/html" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/html" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/io" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/io" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/isolate" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/isolate" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/math" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/math" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/mirrors" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/mirrors" />
<root url="file:///Users/maurits/Developer/flutter/bin/cache/dart-sdk/lib/typed_data" /> <root url="file:///Users/long1eu/IDE/flutter/bin/cache/dart-sdk/lib/typed_data" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
......
<component name="libraryTable"> <component name="libraryTable">
<library name="Flutter for Android"> <library name="Flutter for Android">
<CLASSES> <CLASSES>
<root url="jar:///Users/maurits/Developer/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar!/" /> <root url="jar:///Users/long1eu/IDE/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES /> <SOURCES />
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/permission_handler_example.iml" filepath="$PROJECT_DIR$/permission_handler_example.iml" /> <module fileurl="file://$PROJECT_DIR$/permission_handler_example.iml" filepath="$PROJECT_DIR$/permission_handler_example.iml" />
<module fileurl="file://$PROJECT_DIR$/permission_handler_example_android.iml" filepath="$PROJECT_DIR$/permission_handler_example_android.iml" /> <module fileurl="file://$PROJECT_DIR$/android/permission_handler_example_android.iml" filepath="$PROJECT_DIR$/android/permission_handler_example_android.iml" />
</modules> </modules>
</component> </component>
</project> </project>
...@@ -4,5 +4,7 @@ ...@@ -4,5 +4,7 @@
# This file should be version controlled and should not be manually edited. # This file should be version controlled and should not be manually edited.
version: version:
revision: c7ea3ca377e909469c68f2ab878a5bc53d3cf66b revision: 06b979c4d5e1b499745422269f01a00341257058
channel: beta channel: master
project_type: app
...@@ -4,5 +4,13 @@ Demonstrates how to use the permission_handler plugin. ...@@ -4,5 +4,13 @@ Demonstrates how to use the permission_handler plugin.
## Getting Started ## Getting Started
For help getting started with Flutter, view our online This project is a starting point for a Flutter application.
[documentation](https://flutter.io/).
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.io/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
*.iml
*.class
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
GeneratedPluginRegistrant.java
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>
connection.project.dir=..
eclipse.preferences.version=1
...@@ -11,29 +11,33 @@ if (flutterRoot == null) { ...@@ -11,29 +11,33 @@ if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
} }
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android { android {
compileSdkVersion 28 compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions { lintOptions {
disable 'InvalidPackage' disable 'InvalidPackage'
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.baseflow.permissionhandlerexample" applicationId "com.example.permissionhandlerexample"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 28 targetSdkVersion 28
versionCode 1 versionCode flutterVersionCode.toInteger()
versionName "1.0" versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
...@@ -47,11 +51,4 @@ android { ...@@ -47,11 +51,4 @@ android {
flutter { flutter {
source '../..' source '../..'
} }
\ No newline at end of file
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.permissionhandlerexample">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.baseflow.permissionhandlerexample"> xmlns:tools="http://schemas.android.com/tools"
package="com.example.permissionhandlerexample">
<!-- The INTERNET permission is required for development. Specifically,
flutter needs it to communicate with the running application <uses-permission android:name="android.permission.INTERNET" />
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_MMS" /> <uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" /> <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" /> <uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_SMS" /> <uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" /> <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SENSORS" /> <uses-permission android:name="android.permission.SENSORS" />
<uses-permission android:name="android.permission.BODY_SENSORS" /> <uses-permission android:name="android.permission.BODY_SENSORS" />
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="io.flutter.app.FlutterApplication"
android:icon="@mipmap/ic_launcher"
android:label="permission_handler_example" android:label="permission_handler_example"
android:icon="@mipmap/ic_launcher"> tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data <meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame" android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" /> android:value="true" />
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
</application> </application>
......
package com.example.permissionhandlerexample;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
package com.baseflow.permissionhandlerexample
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity(): FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.permissionhandlerexample">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
buildscript { buildscript {
ext.kotlin_version = '1.3.0'
repositories { repositories {
google() google()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.3.0' classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
......
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.enableJetifier=true
android.useAndroidX=true
\ No newline at end of file
#Wed Oct 10 08:31:26 CEST 2018 #Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
......
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/app.flx
/Flutter/app.zip
/Flutter/flutter_assets/
/Flutter/App.framework
/Flutter/Flutter.framework
/Flutter/Generated.xcconfig
/ServiceDefinitions.json
Pods/
.symlinks/
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"
FLUTTER_BUILD_MODE=debug
...@@ -4,6 +4,12 @@ ...@@ -4,6 +4,12 @@
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=') def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file) file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path if !File.exists? file_abs_path
...@@ -27,8 +33,6 @@ def parse_KV_file(file, separator='=') ...@@ -27,8 +33,6 @@ def parse_KV_file(file, separator='=')
end end
target 'Runner' do target 'Runner' do
use_frameworks!
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines. # referring to absolute paths on developers' machines.
system('rm -rf .symlinks') system('rm -rf .symlinks')
...@@ -60,7 +64,6 @@ post_install do |installer| ...@@ -60,7 +64,6 @@ post_install do |installer|
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
target.build_configurations.each do |config| target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO' config.build_settings['ENABLE_BITCODE'] = 'NO'
config.build_settings['SWIFT_VERSION'] = '4.2'
end end
end end
end end
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0940" LastUpgradeVersion = "0910"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
...@@ -45,6 +46,7 @@ ...@@ -45,6 +46,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
...@@ -65,7 +67,7 @@ ...@@ -65,7 +67,7 @@
</AdditionalOptions> </AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
......
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
...@@ -2,10 +2,6 @@ ...@@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>en</string> <string>en</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
...@@ -19,11 +15,11 @@ ...@@ -19,11 +15,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
...@@ -44,36 +40,36 @@ ...@@ -44,36 +40,36 @@
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>NSLocationWhenInUseUsageDescription</key> <key>NSLocationWhenInUseUsageDescription</key>
<string>Need location when in use</string> <string>Need location when in use</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Always and when in use!</string> <string>Always and when in use!</string>
<key>NSLocationUsageDescription</key> <key>NSLocationUsageDescription</key>
<string>Older devices need location.</string> <string>Older devices need location.</string>
<key>NSLocationAlwaysUsageDescription</key> <key>NSLocationAlwaysUsageDescription</key>
<string>Can I haz location always?</string> <string>Can I haz location always?</string>
<key>NSAppleMusicUsageDescription</key> <key>NSAppleMusicUsageDescription</key>
<string>Music!</string> <string>Music!</string>
<key>NSBluetoothPeripheralUsageDescription</key> <key>NSBluetoothPeripheralUsageDescription</key>
<string>bluetooth</string> <string>bluetooth</string>
<key>NSCalendarsUsageDescription</key> <key>NSCalendarsUsageDescription</key>
<string>Calendars</string> <string>Calendars</string>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>camera</string> <string>camera</string>
<key>NSContactsUsageDescription</key> <key>NSContactsUsageDescription</key>
<string>contacts</string> <string>contacts</string>
<key>kTCCServiceMediaLibrary</key> <key>kTCCServiceMediaLibrary</key>
<string>media</string> <string>media</string>
<key>NSMicrophoneUsageDescription</key> <key>NSMicrophoneUsageDescription</key>
<string>microphone</string> <string>microphone</string>
<key>NSMotionUsageDescription</key> <key>NSMotionUsageDescription</key>
<string>motion</string> <string>motion</string>
<key>NSPhotoLibraryUsageDescription</key> <key>NSPhotoLibraryUsageDescription</key>
<string>photos</string> <string>photos</string>
<key>NSRemindersUsageDescription</key> <key>NSRemindersUsageDescription</key>
<string>reminders</string> <string>reminders</string>
<key>NSSpeechRecognitionUsageDescription</key> <key>NSSpeechRecognitionUsageDescription</key>
<string>speech</string> <string>speech</string>
</dict> </dict>
</plist> </plist>
#import "GeneratedPluginRegistrant.h"
\ No newline at end of file
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
...@@ -9,40 +9,41 @@ class MyApp extends StatelessWidget { ...@@ -9,40 +9,41 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Plugin example app'), title: const Text('Plugin example app'),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: const Icon(Icons.settings), icon: const Icon(Icons.settings),
onPressed: () { onPressed: () {
PermissionHandler().openAppSettings().then((bool hasOpened) => PermissionHandler().openAppSettings().then((bool hasOpened) =>
debugPrint('App Settings opened: ' + hasOpened.toString())); debugPrint('App Settings opened: ' + hasOpened.toString()));
}, },
) )
], ],
),
body: Center(
child: ListView(
children: PermissionGroup.values
.where((PermissionGroup permission) {
if (Platform.isIOS) {
return permission != PermissionGroup.unknown &&
permission != PermissionGroup.phone &&
permission != PermissionGroup.sms &&
permission != PermissionGroup.storage;
} else {
return permission != PermissionGroup.unknown &&
permission != PermissionGroup.mediaLibrary &&
permission != PermissionGroup.photos &&
permission != PermissionGroup.reminders;
}
})
.map((PermissionGroup permission) =>
PermissionWidget(permission))
.toList()),
),
), ),
body: Center( );
child: ListView(
children: PermissionGroup.values
.where((PermissionGroup permission) {
if (Platform.isIOS) {
return permission != PermissionGroup.unknown &&
permission != PermissionGroup.phone &&
permission != PermissionGroup.sms &&
permission != PermissionGroup.storage;
} else {
return permission != PermissionGroup.unknown &&
permission != PermissionGroup.mediaLibrary &&
permission != PermissionGroup.photos &&
permission != PermissionGroup.reminders;
}
})
.map((PermissionGroup permission) =>
PermissionWidget(permission))
.toList()),
),
));
} }
} }
...@@ -120,16 +121,15 @@ class _PermissionState extends State<PermissionWidget> { ...@@ -120,16 +121,15 @@ class _PermissionState extends State<PermissionWidget> {
}); });
} }
void requestPermission(PermissionGroup permission) { Future<void> requestPermission(PermissionGroup permission) async {
final List<PermissionGroup> permissions = <PermissionGroup>[permission]; final List<PermissionGroup> permissions = <PermissionGroup>[permission];
final Future<Map<PermissionGroup, PermissionStatus>> requestFuture = final Map<PermissionGroup, PermissionStatus> permissionRequestResult =
PermissionHandler().requestPermissions(permissions); await PermissionHandler().requestPermissions(permissions);
requestFuture setState(() {
.then((Map<PermissionGroup, PermissionStatus> permissionRequestResult) { print(permissionRequestResult);
setState(() { _permissionStatus = permissionRequestResult[permission];
_permissionStatus = permissionRequestResult[permission]; print(_permissionStatus);
});
}); });
} }
} }
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android" name="Android">
<configuration>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="GEN_FOLDER_RELATIVE_PATH_APT" value="/android/gen" />
<option name="GEN_FOLDER_RELATIVE_PATH_AIDL" value="/android/gen" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/android/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/android/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/android/assets" />
<option name="LIBS_FOLDER_RELATIVE_PATH" value="/android/libs" />
<option name="PROGUARD_LOGS_FOLDER_RELATIVE_PATH" value="/android/proguard_logs" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/android">
<sourceFolder url="file://$MODULE_DIR$/android/app/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/android/gen" isTestSource="false" generated="true" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Flutter for Android" level="project" />
</component>
</module>
name: permission_handler_example name: permission_handler_example
description: Demonstrates how to use the permission_handler plugin. description: Demonstrates how to use the permission_handler plugin.
environment:
sdk: ">=2.0.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
dev_dependencies: dev_dependencies:
flutter_test:
sdk: flutter
permission_handler: permission_handler:
path: ../ path: ../
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter: flutter:
uses-material-design: true
# The following line ensures that the Material Icons font is \ No newline at end of file
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.io/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.io/custom-fonts/#from-packages
//
// Enums.h
// permission_handler
//
// Created by Razvan Lung on 15/02/2019.
//
typedef NS_ENUM(int, PermissionGroup) {
PermissionGroupCalendar = 0,
PermissionGroupCamera,
PermissionGroupContacts,
PermissionGroupLocation,
PermissionGroupLocationAlways,
PermissionGroupLocationWhenInUse,
PermissionGroupMediaLibrary,
PermissionGroupMicrophone,
PermissionGroupPhone,
PermissionGroupPhotos,
PermissionGroupReminders,
PermissionGroupSensors,
PermissionGroupSms,
PermissionGroupSpeech,
PermissionGroupStorage,
PermissionGroupUnknown,
};
typedef NS_ENUM(int, PermissionStatus) {
PermissionStatusDenied = 0,
PermissionStatusDisabled,
PermissionStatusGranted,
PermissionStatusRestricted,
PermissionStatusUnknown,
};
typedef NS_ENUM(int, ServiceStatus) {
ServiceStatusDisabled = 0,
ServiceStatusEnabled,
ServiceStatusNotApplicable,
ServiceStatusUnknown,
};
#import <Flutter/Flutter.h> #import <Flutter/Flutter.h>
#import "PermissionManager.h"
@interface PermissionHandlerPlugin : NSObject <FlutterPlugin> @interface PermissionHandlerPlugin : NSObject<FlutterPlugin>
- (instancetype)initWithPermissionManager:(PermissionManager *)permissionManager;
@end @end
#import "PermissionHandlerPlugin.h" #import "PermissionHandlerPlugin.h"
#import <permission_handler/permission_handler-Swift.h>
@implementation PermissionHandlerPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { @implementation PermissionHandlerPlugin {
[SwiftPermissionHandlerPlugin registerWithRegistrar:registrar]; PermissionManager *_Nonnull _permissionManager;
_Nullable FlutterResult _methodResult;
}
- (instancetype)initWithPermissionManager:(PermissionManager *)permissionManager {
self = [super init];
if (self) {
_permissionManager = permissionManager;
}
return self;
}
+ (void)registerWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar {
FlutterMethodChannel *channel = [FlutterMethodChannel
methodChannelWithName:@"flutter.baseflow.com/permissions/methods"
binaryMessenger:[registrar messenger]];
PermissionManager *permissionManager = [[PermissionManager alloc] initWithStrategyInstances];
PermissionHandlerPlugin *instance = [[PermissionHandlerPlugin alloc] initWithPermissionManager:permissionManager];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
if ([@"checkPermissionStatus" isEqualToString:call.method]) {
PermissionGroup permission = [Codec decodePermissionGroupFrom:call.arguments];
[PermissionManager checkPermissionStatus:permission result:result];
} else if ([@"checkServiceStatus" isEqualToString:call.method]) {
PermissionGroup permission = [Codec decodePermissionGroupFrom:call.arguments];
[PermissionManager checkServiceStatus:permission result:result];
} else if ([@"requestPermissions" isEqualToString:call.method]) {
if (_methodResult != nil) {
result([FlutterError errorWithCode:@"ERROR_ALREADY_REQUESTING_PERMISSIONS" message:@"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)." details:nil]);
}
_methodResult = result;
NSArray *permissions = [Codec decodePermissionGroupsFrom:call.arguments];
[_permissionManager
requestPermissions:permissions completion:^(NSDictionary *permissionRequestResults) {
if (self->_methodResult != nil) {
self->_methodResult(permissionRequestResults);
}
self->_methodResult = nil;
}];
} else if ([@"shouldShowRequestPermissionRationale" isEqualToString:call.method]) {
result(@false);
} else if ([@"openAppSettings" isEqualToString:call.method]) {
[PermissionManager openAppSettings:result];
} else {
result(FlutterMethodNotImplemented);
}
} }
@end @end
//
// PermissionManager.h
// permission_handler
//
// Created by Razvan Lung on 15/02/2019.
//
#import <Flutter/Flutter.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "AudioVideoPermissionStrategy.h"
#import "ContactPermissionStrategy.h"
#import "EventPermissionStrategy.h"
#import "LocationPermissionStrategy.h"
#import "MediaLibraryPermissionStrategy.h"
#import "PermissionStrategy.h"
#import "PhotoPermissionStrategy.h"
#import "SensorPermissionStrategy.h"
#import "SpeechPermissionStrategy.h"
#import "UnknownPermissionStrategy.h"
#import "Enums.h"
#import "Codec.h"
typedef void (^PermissionRequestCompletion)(NSDictionary *permissionRequestResults);
@interface PermissionManager : NSObject
- (instancetype)initWithStrategyInstances;
+ (void)checkPermissionStatus:(enum PermissionGroup)permission result:(FlutterResult)result;
+ (void)checkServiceStatus:(enum PermissionGroup)permission result:(FlutterResult)result;
+ (void)openAppSettings:(FlutterResult)result;
- (void)requestPermissions:(NSArray *)permissions completion:(PermissionRequestCompletion)completion;
@end
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "PermissionManager.h"
@implementation PermissionManager {
NSMutableArray <id <PermissionStrategy>> *_strategyInstances;
}
- (instancetype)initWithStrategyInstances {
self = [super init];
if (self) {
_strategyInstances = _strategyInstances = [[NSMutableArray alloc] init];
}
return self;
}
+ (void)checkPermissionStatus:(enum PermissionGroup)permission result:(FlutterResult)result {
id <PermissionStrategy> permissionStrategy = [PermissionManager createPermissionStrategy:permission];
PermissionStatus status = [permissionStrategy checkPermissionStatus:permission];
result([Codec encodePermissionStatus:status]);
}
+ (void)checkServiceStatus:(enum PermissionGroup)permission result:(FlutterResult)result {
id <PermissionStrategy> permissionStrategy = [PermissionManager createPermissionStrategy:permission];
ServiceStatus status = [permissionStrategy checkServiceStatus:permission];
result([Codec encodeServiceStatus:status]);
}
- (void)requestPermissions:(NSArray *)permissions completion:(PermissionRequestCompletion)completion {
NSMutableSet *requestQueue = [[NSMutableSet alloc] initWithArray:permissions];
NSMutableDictionary *permissionStatusResult = [[NSMutableDictionary alloc] init];
for (int i = 0; i < permissions.count; ++i) {
PermissionGroup value;
[permissions[i] getValue:&value];
PermissionGroup permission = value;
id <PermissionStrategy> permissionStrategy = [PermissionManager createPermissionStrategy:permission];
[_strategyInstances addObject:permissionStrategy];
[permissionStrategy requestPermission:permission completionHandler:^(PermissionStatus permissionStatus) {
permissionStatusResult[@(permission)] = @(permissionStatus);
[requestQueue removeObject:@(permission)];
[self->_strategyInstances removeObject:permissionStrategy];
if (requestQueue.count == 0) {
completion(permissionStatusResult);
return;
}
}];
}
}
+ (void)openAppSettings:(FlutterResult)result {
if (@available(iOS 10, *)) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]
options:[[NSDictionary alloc] init]
completionHandler:^(BOOL success) {
result([[NSNumber alloc] initWithBool:success]);
}];
} else if (@available(iOS 8.0, *)) {
BOOL success = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
result([[NSNumber alloc] initWithBool:success]);
} else {
result(@false);
}
}
+ (id)createPermissionStrategy:(PermissionGroup)permission {
switch (permission) {
case PermissionGroupCalendar:
return [EventPermissionStrategy new];
case PermissionGroupCamera:
return [AudioVideoPermissionStrategy new];
case PermissionGroupContacts:
return [ContactPermissionStrategy new];
case PermissionGroupLocation:
case PermissionGroupLocationAlways:
case PermissionGroupLocationWhenInUse:
return [[LocationPermissionStrategy alloc] initWithLocationManager];
case PermissionGroupMediaLibrary:
return [MediaLibraryPermissionStrategy new];
case PermissionGroupMicrophone:
return [AudioVideoPermissionStrategy new];
case PermissionGroupPhotos:
return [PhotoPermissionStrategy new];
case PermissionGroupReminders:
return [EventPermissionStrategy new];
case PermissionGroupSensors:
return [SensorPermissionStrategy new];
case PermissionGroupSpeech:
return [SpeechPermissionStrategy new];
default:
return [UnknownPermissionStrategy new];
}
}
@end
//
// PermissionManager.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import Flutter
import Foundation
import UIKit
import Swift
typealias PermissionRequestCompletion = (_ permissionRequestResults: [PermissionGroup:PermissionStatus]) -> ()
class PermissionManager: NSObject {
private var _strategyInstances: [ObjectIdentifier: PermissionStrategy] = [:]
static func checkPermissionStatus(permission: PermissionGroup, result: @escaping FlutterResult) {
let permissionStrategy = PermissionManager.createPermissionStrategy(permission: permission)
let permissionStatus = permissionStrategy.checkPermissionStatus(permission: permission)
result(Codec.encodePermissionStatus(permissionStatus: permissionStatus))
}
static func checkServiceStatus(permission: PermissionGroup, result: @escaping FlutterResult) {
let permissionStrategy = PermissionManager.createPermissionStrategy(permission: permission)
let serviceStatus = permissionStrategy.checkServiceStatus(permission: permission)
result(Codec.encodeServiceStatus(serviceStatus: serviceStatus))
}
func requestPermissions(permissions: [PermissionGroup], completion: @escaping PermissionRequestCompletion) {
var requestQueue = Set(permissions.map { $0 })
var permissionStatusResult: [PermissionGroup: PermissionStatus] = [:]
for permission in permissions {
let permissionStrategy = PermissionManager.createPermissionStrategy(permission: permission)
let identifier = ObjectIdentifier(permissionStrategy as AnyObject)
_strategyInstances[identifier] = permissionStrategy
permissionStrategy.requestPermission(permission: permission) { (permissionStatus: PermissionStatus) in
permissionStatusResult[permission] = permissionStatus
requestQueue.remove(permission)
self._strategyInstances.removeValue(forKey: ObjectIdentifier(permissionStrategy as AnyObject))
if requestQueue.count == 0 {
completion(permissionStatusResult)
return
}
}
}
}
static func openAppSettings(result: @escaping FlutterResult) {
if #available(iOS 8.0, *) {
if #available(iOS 10, *) {
guard let url = URL(string: UIApplication.openSettingsURLString),
UIApplication.shared.canOpenURL(url) else {
result(false)
return
}
let optionsKeyDictionary = [UIApplication.OpenExternalURLOptionsKey(rawValue: "universalLinksOnly"): NSNumber(value: true)]
UIApplication.shared.open(url, options: optionsKeyDictionary, completionHandler: { (success) in result(success) });
return
} else {
let success = UIApplication.shared.openURL(URL.init(string: UIApplication.openSettingsURLString)!)
result(success)
}
}
result(false)
}
private static func createPermissionStrategy(permission: PermissionGroup) -> PermissionStrategy {
switch permission {
case PermissionGroup.calendar:
return EventPermissionStrategy()
case PermissionGroup.camera:
return AudioVideoPermissionStrategy()
case PermissionGroup.contacts:
return ContactPermissionStrategy()
case PermissionGroup.location,
PermissionGroup.locationAlways,
PermissionGroup.locationWhenInUse:
return LocationPermissionStrategy()
case PermissionGroup.mediaLibrary:
return MediaLibraryPermissionStrategy()
case PermissionGroup.microphone:
return AudioVideoPermissionStrategy()
case PermissionGroup.photos:
return PhotoPermissionStrategy()
case PermissionGroup.reminders:
return EventPermissionStrategy()
case PermissionGroup.sensors:
return SensorPermissionStrategy()
case PermissionGroup.speech:
return SpeechPermissionStrategy()
default:
return UnknownPermissionStrategy()
}
}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
import CoreLocation
import CoreMotion
import EventKit
import Flutter
import Foundation
import Photos
import UIKit
public class SwiftPermissionHandlerPlugin: NSObject, FlutterPlugin {
private static let METHOD_CHANNEL_NAME = "flutter.baseflow.com/permissions/methods";
private let _permissionManager: PermissionManager = PermissionManager()
private var _methodResult: FlutterResult?
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())
let instance = SwiftPermissionHandlerPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "checkPermissionStatus" {
let permission: PermissionGroup = Codec.decodePermissionGroup(from: call.arguments)
PermissionManager.checkPermissionStatus(
permission: permission,
result: result)
} else if call.method == "checkServiceStatus" {
let permission: PermissionGroup = Codec.decodePermissionGroup(from: call.arguments)
PermissionManager.checkServiceStatus(
permission: permission,
result: result)
} else if call.method == "requestPermissions" {
if _methodResult != nil {
result(FlutterError(
code: "ERROR_ALREADY_REQUESTING_PERMISSIONS",
message: "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).",
details: nil))
}
_methodResult = result
let permissions: [PermissionGroup] = Codec.decodePermissionGroups(from: call.arguments)
_permissionManager.requestPermissions(permissions: permissions) {
(permissionRequestResults: [PermissionGroup:PermissionStatus]) in
if self._methodResult != nil {
self._methodResult!(Codec.encodePermissionRequestResult(permissionStatusResult: permissionRequestResults))
}
self._methodResult = nil
}
} else if call.method == "shouldShowRequestPermissionRationale" {
result(false)
} else if call.method == "openAppSettings" {
PermissionManager.openAppSettings(result: result)
} else {
result(FlutterMethodNotImplemented)
}
}
}
//
// PermissionGroup.swift
// permission_handler
//
// Created by Maurits van Beusekom on 25/07/2018.
//
import Foundation
enum PermissionGroup : String, Codable {
case calendar = "calendar"
case camera = "camera"
case contacts = "contacts"
case location = "location"
case locationAlways = "locationAlways"
case locationWhenInUse = "locationWhenInUse"
case mediaLibrary = "mediaLibrary"
case microphone = "microphone"
case phone = "phone"
case photos = "photos"
case reminders = "reminders"
case sensors = "sensors"
case sms = "sms"
case speech = "speech"
case storage = "storage"
}
//
// PermissionStatus.swift
// permission_handler
//
// Created by Maurits van Beusekom on 25/07/2018.
//
import Foundation
enum PermissionStatus : String, Codable {
case denied = "denied"
case disabled = "disabled"
case granted = "granted"
case restricted = "restricted"
case unknown = "unknown"
}
//
// ServiceStatus.swift
// permission_handler
//
// Created by Maurits van Beusekom on 12/02/2019.
//
import Foundation
enum ServiceStatus : String, Codable {
case disabled = "disabled"
case enabled = "enabled"
case notApplicable = "notApplicable"
case unknown = "unknown"
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#import "PermissionStrategy.h"
@interface AudioVideoPermissionStrategy : NSObject <PermissionStrategy>
@end
\ No newline at end of file
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "AudioVideoPermissionStrategy.h"
@implementation AudioVideoPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
if (permission == PermissionGroupCamera) {
return [AudioVideoPermissionStrategy permissionStatus:AVMediaTypeVideo];
} else if (permission == PermissionGroupMicrophone) {
return [AudioVideoPermissionStrategy permissionStatus:AVMediaTypeAudio];
}
return PermissionStatusUnknown;
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusNotApplicable;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
completionHandler(status);
return;
}
AVMediaType mediaType;
if (permission == PermissionGroupCamera) {
mediaType = AVMediaTypeVideo;
} else if (permission == PermissionGroupMicrophone) {
mediaType = AVMediaTypeAudio;
} else {
completionHandler(PermissionStatusUnknown);
return;
}
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusDenied);
}
}];
}
+ (PermissionStatus)permissionStatus:(AVMediaType const)mediaType {
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
switch (status) {
case AVAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case AVAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case AVAuthorizationStatusDenied:
return PermissionStatusDenied;
case AVAuthorizationStatusAuthorized:
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
}
@end
\ No newline at end of file
//
// AudioVideoPermissions.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import AVFoundation
import Foundation
class AudioVideoPermissionStrategy : NSObject, PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
if permission == PermissionGroup.camera {
return AudioVideoPermissionStrategy.getPermissionStatus(mediaType: AVMediaType.video)
} else if permission == PermissionGroup.microphone {
return AudioVideoPermissionStrategy.getPermissionStatus(mediaType: AVMediaType.audio)
}
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
private static func getPermissionStatus(mediaType: AVMediaType) -> PermissionStatus {
let status: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: mediaType)
switch status {
case AVAuthorizationStatus.authorized:
return PermissionStatus.granted
case AVAuthorizationStatus.denied:
return PermissionStatus.denied
case AVAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
if permissionStatus != PermissionStatus.unknown {
completionHandler(permissionStatus)
return
}
var mediaType: AVMediaType
if permission == PermissionGroup.camera {
mediaType = AVMediaType.video
} else if permission == PermissionGroup.microphone {
mediaType = AVMediaType.audio
} else {
completionHandler(PermissionStatus.unknown)
return
}
AVCaptureDevice.requestAccess(for: mediaType, completionHandler: {
(granted: Bool) in
if granted {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
})
}
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <AddressBook/ABAddressBook.h>
#import <Contacts/Contacts.h>
#import <Foundation/Foundation.h>
#import "PermissionStrategy.h"
@interface ContactPermissionStrategy : NSObject <PermissionStrategy>
@end
\ No newline at end of file
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "ContactPermissionStrategy.h"
@implementation ContactPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return [ContactPermissionStrategy permissionStatus];
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusNotApplicable;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
completionHandler(status);
}
if (@available(iOS 9.0, *)) {
[ContactPermissionStrategy requestPermissionsFromContactStore:completionHandler];
} else {
[ContactPermissionStrategy requestPermissionsFromAddressBook:completionHandler];
}
}
+ (PermissionStatus)permissionStatus {
if (@available(iOS 9.0, *)) {
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
switch (status) {
case CNAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case CNAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case CNAuthorizationStatusDenied:
return PermissionStatusDenied;
case CNAuthorizationStatusAuthorized:
return PermissionStatusGranted;
}
} else {
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
switch (status) {
case kABAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case kABAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case kABAuthorizationStatusDenied:
return PermissionStatusDenied;
case kABAuthorizationStatusAuthorized:
return PermissionStatusGranted;
}
}
return PermissionStatusUnknown;
}
+ (void)requestPermissionsFromContactStore:(PermissionStatusHandler)completionHandler API_AVAILABLE(ios(9)) {
CNContactStore *contactStore = [CNContactStore new];
[contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError *__nullable error) {
if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusDenied);
}
}];
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreate(), ^(bool granted, CFErrorRef error) {
if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusDenied);
}
});
}
+ (void)requestPermissionsFromAddressBook:(PermissionStatusHandler)completionHandler {
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreate(), ^(bool granted, CFErrorRef error) {
if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusDenied);
}
});
}
@end
//
// ContactPermissions.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import AddressBook
import Contacts
import Foundation
class ContactPermissionStrategy : NSObject, PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
return ContactPermissionStrategy.getPermissionStatus()
}
private static func getPermissionStatus() -> PermissionStatus {
if #available(iOS 9.0, *) {
let status: CNAuthorizationStatus = CNContactStore.authorizationStatus(for: .contacts)
switch status {
case CNAuthorizationStatus.authorized:
return PermissionStatus.granted
case CNAuthorizationStatus.denied:
return PermissionStatus.denied
case CNAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
let status: ABAuthorizationStatus = ABAddressBookGetAuthorizationStatus()
switch status {
case ABAuthorizationStatus.authorized:
return PermissionStatus.granted
case ABAuthorizationStatus.denied:
return PermissionStatus.denied
case ABAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
if permissionStatus != PermissionStatus.unknown {
completionHandler(permissionStatus)
return
}
if #available(iOS 9.0, *) {
ContactPermissionStrategy.requestPermissionsFromContactStore(completionHandler: completionHandler)
} else {
ContactPermissionStrategy.requestPermissionsFromAddressBook(completionHandler: completionHandler)
}
}
@available(iOS 9.0, *)
private static func requestPermissionsFromContactStore(completionHandler: @escaping PermissionStatusHandler) {
let contactStore = CNContactStore.init()
contactStore.requestAccess(for: .contacts, completionHandler: {
(authorized: Bool, error: Error?) in
if authorized {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
})
}
private static func requestPermissionsFromAddressBook(completionHandler: @escaping PermissionStatusHandler) {
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreate() as ABAddressBook, {
(granted: Bool, error: CFError?) in
if granted {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
})
}
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <EventKit/EventKit.h>
#import "PermissionStrategy.h"
@interface EventPermissionStrategy : NSObject <PermissionStrategy>
@end
\ No newline at end of file
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "EventPermissionStrategy.h"
@implementation EventPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
if (permission == PermissionGroupCalendar) {
return [EventPermissionStrategy permissionStatus:EKEntityTypeEvent];
} else if (permission == PermissionGroupReminders) {
return [EventPermissionStrategy permissionStatus:EKEntityTypeReminder];
}
return PermissionStatusUnknown;
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusNotApplicable;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus permissionStatus = [self checkPermissionStatus:permission];
if (permissionStatus != PermissionStatusUnknown) {
completionHandler(permissionStatus);
return;
}
EKEntityType entityType;
if (permission == PermissionGroupCalendar) {
entityType = EKEntityTypeEvent;
} else if (permission == PermissionGroupReminders) {
entityType = EKEntityTypeReminder;
} else {
completionHandler(PermissionStatusUnknown);
return;
}
EKEventStore *eventStore = [[EKEventStore alloc] init];
[eventStore requestAccessToEntityType:entityType completion:^(BOOL granted, NSError *error) {
if (granted) {
completionHandler(PermissionStatusGranted);
} else {
completionHandler(PermissionStatusDenied);
}
}];
}
+ (PermissionStatus)permissionStatus:(EKEntityType)entityType {
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:entityType];
switch (status) {
case EKAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case EKAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case EKAuthorizationStatusDenied:
return PermissionStatusDenied;
case EKAuthorizationStatusAuthorized:
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
}
@end
//
// EventPermissions.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import EventKit
import Foundation
class EventPermissionStrategy : NSObject, PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
if permission == PermissionGroup.calendar {
return EventPermissionStrategy.getPermissionStatus(entityType: EKEntityType.event)
} else if permission == PermissionGroup.reminders {
return EventPermissionStrategy.getPermissionStatus(entityType: EKEntityType.reminder)
}
return PermissionStatus.unknown
}
private static func getPermissionStatus(entityType: EKEntityType) -> PermissionStatus {
let status: EKAuthorizationStatus = EKEventStore.authorizationStatus(for: entityType)
switch status {
case EKAuthorizationStatus.authorized:
return PermissionStatus.granted
case EKAuthorizationStatus.denied:
return PermissionStatus.denied
case EKAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
if permissionStatus != PermissionStatus.unknown {
completionHandler(permissionStatus)
return
}
var entityType: EKEntityType
if permission == PermissionGroup.calendar {
entityType = EKEntityType.event
} else if permission == PermissionGroup.reminders {
entityType = EKEntityType.reminder
} else {
completionHandler(PermissionStatus.unknown)
return
}
let eventStore: EKEventStore = EKEventStore.init()
eventStore.requestAccess(to: entityType) { (granted: Bool, error: Error?) in
if granted {
completionHandler(PermissionStatus.granted)
} else {
completionHandler(PermissionStatus.denied)
}
}
}
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>
#import "PermissionStrategy.h"
@interface LocationPermissionStrategy : NSObject <PermissionStrategy, CLLocationManagerDelegate>
- (instancetype)initWithLocationManager;
@end
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "LocationPermissionStrategy.h"
@implementation LocationPermissionStrategy {
CLLocationManager *_locationManager;
PermissionStatusHandler _permissionStatusHandler;
PermissionGroup _requestedPermission;
}
- (instancetype)initWithLocationManager {
self = [super init];
if (self) {
_locationManager = [CLLocationManager new];
_locationManager.delegate = self;
}
return self;
}
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return [LocationPermissionStrategy permissionStatus:permission];
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return [CLLocationManager locationServicesEnabled] ? ServiceStatusEnabled : ServiceStatusDisabled;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse && permission == PermissionGroupLocationAlways) {
// don't do anything and continue requesting permissions
} else if (status != PermissionStatusUnknown) {
completionHandler(status);
}
_permissionStatusHandler = completionHandler;
_requestedPermission = permission;
if (permission == PermissionGroupLocation) {
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil) {
[_locationManager requestAlwaysAuthorization];
} else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) {
[_locationManager requestWhenInUseAuthorization];
} else {
[[NSException exceptionWithName:NSInternalInconsistencyException reason:@"To use location in iOS8 you need to define either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in the app bundle's Info.plist file" userInfo:nil] raise];
}
} else if (permission == PermissionGroupLocationAlways) {
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil) {
[_locationManager requestAlwaysAuthorization];
} else {
[[NSException exceptionWithName:NSInternalInconsistencyException reason:@"To use location in iOS8 you need to define NSLocationAlwaysUsageDescription in the app bundle's Info.plist file" userInfo:nil] raise];
}
} else if (permission == PermissionGroupLocationWhenInUse) {
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) {
[_locationManager requestWhenInUseAuthorization];
} else {
[[NSException exceptionWithName:NSInternalInconsistencyException reason:@"To use location in iOS8 you need to define NSLocationWhenInUseUsageDescription in the app bundle's Info.plist file" userInfo:nil] raise];
}
}
}
// {WARNING}
// This is called when the location manager is first initialized and raises the following situations:
// 1. When we first request [PermissionGroupLocationWhenInUse] and then [PermissionGroupLocationAlways]
// this will be called when the [CLLocationManager] is first initialized with
// [kCLAuthorizationStatusAuthorizedWhenInUse]. As a consequence we send back the result to early.
// 2. When we first request [PermissionGroupLocationWhenInUse] and then [PermissionGroupLocationAlways]
// and the user doesn't allow for [kCLAuthorizationStatusAuthorizedAlways] this method is not called
// at all.
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusNotDetermined) {
return;
}
if (_permissionStatusHandler == nil || @(_requestedPermission) == nil) {
return;
}
PermissionStatus permissionStatus = [LocationPermissionStrategy
determinePermissionStatus:_requestedPermission authorizationStatus:status];
_permissionStatusHandler(permissionStatus);
}
+ (PermissionStatus)permissionStatus:(PermissionGroup)permission {
CLAuthorizationStatus authorizationStatus = [CLLocationManager authorizationStatus];
PermissionStatus status = [LocationPermissionStrategy
determinePermissionStatus:permission authorizationStatus:authorizationStatus];
if ((status == PermissionStatusGranted || status == PermissionStatusDenied)
&& ![CLLocationManager locationServicesEnabled]) {
return PermissionStatusDisabled;
}
return status;
}
+ (PermissionStatus)determinePermissionStatus:(PermissionGroup)permission authorizationStatus:(CLAuthorizationStatus)authorizationStatus {
if (@available(iOS 8.0, *)) {
if (permission == PermissionGroupLocationAlways) {
switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied:
case kCLAuthorizationStatusAuthorizedWhenInUse:
return PermissionStatusDenied;
case kCLAuthorizationStatusAuthorizedAlways:
return PermissionStatusGranted;
}
}
switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied:
return PermissionStatusDenied;
case kCLAuthorizationStatusAuthorizedAlways:
case kCLAuthorizationStatusAuthorizedWhenInUse:
return PermissionStatusGranted;
}
}
switch (authorizationStatus) {
case kCLAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case kCLAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case kCLAuthorizationStatusDenied:
return PermissionStatusDenied;
case kCLAuthorizationStatusAuthorized:
return PermissionStatusGranted;
default:
return PermissionStatusUnknown;
}
}
@end
//
// LocationPermissions.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import CoreLocation
import Foundation
class LocationPermissionStrategy : NSObject, PermissionStrategy, CLLocationManagerDelegate {
private var _locationManager: CLLocationManager? = nil
private var _permissionStatusHandler: PermissionStatusHandler? = nil
private var _requestedPermission: PermissionGroup? = nil
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
return LocationPermissionStrategy.getPermissionStatus(permission: permission)
}
private static func getPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
let authorizationStatus: CLAuthorizationStatus = CLLocationManager.authorizationStatus()
let permissionStatus: PermissionStatus = LocationPermissionStrategy.determinePermissionStatus(
permission: permission,
authorizationStatus: authorizationStatus)
if (permissionStatus == PermissionStatus.granted || permissionStatus == PermissionStatus.denied) && !CLLocationManager.locationServicesEnabled() {
return PermissionStatus.disabled
}
return permissionStatus
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return CLLocationManager.locationServicesEnabled()
? ServiceStatus.enabled
: ServiceStatus.disabled
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let permissionStatus = checkPermissionStatus(permission: permission)
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse && permission == PermissionGroup.locationAlways {
// don't do anything and continue requesting permissions
} else if permissionStatus != PermissionStatus.unknown {
completionHandler(permissionStatus)
return
}
_permissionStatusHandler = completionHandler
_requestedPermission = permission
if(_locationManager == nil) {
_locationManager = CLLocationManager()
_locationManager!.delegate = self
}
if(permission == PermissionGroup.location) {
if (Bundle.main.object(forInfoDictionaryKey: "NSLocationAlwaysUsageDescription") != nil) {
_locationManager!.requestAlwaysAuthorization()
} else if (Bundle.main.object(forInfoDictionaryKey: "NSLocationWhenInUseUsageDescription") != nil) {
_locationManager!.requestWhenInUseAuthorization();
} else {
NSException(name: NSExceptionName.internalInconsistencyException, reason:"To use location in iOS8 you need to define either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in the app bundle's Info.plist file", userInfo: nil).raise()
}
} else if permission == PermissionGroup.locationAlways {
if (Bundle.main.object(forInfoDictionaryKey: "NSLocationAlwaysUsageDescription") != nil) {
_locationManager!.requestAlwaysAuthorization();
} else {
NSException(name: NSExceptionName.internalInconsistencyException, reason:"To use location in iOS8 you need to define NSLocationAlwaysUsageDescription in the app bundle's Info.plist file", userInfo: nil).raise()
}
} else if permission == PermissionGroup.locationWhenInUse {
if (Bundle.main.object(forInfoDictionaryKey: "NSLocationWhenInUseUsageDescription") != nil) {
_locationManager!.requestWhenInUseAuthorization();
} else {
NSException(name: NSExceptionName.internalInconsistencyException, reason:"To use location in iOS8 you need to define NSLocationWhenInUseUsageDescription in the app bundle's Info.plist file", userInfo: nil).raise()
}
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == CLAuthorizationStatus.notDetermined {
return
}
guard let completionHandler = _permissionStatusHandler else { return }
completionHandler(
LocationPermissionStrategy.determinePermissionStatus(
permission: _requestedPermission!,
authorizationStatus: status))
}
private static func determinePermissionStatus(permission: PermissionGroup, authorizationStatus: CLAuthorizationStatus) -> PermissionStatus {
if #available(iOS 8.0, *) {
if permission == PermissionGroup.locationAlways {
switch authorizationStatus {
case CLAuthorizationStatus.authorizedAlways:
return PermissionStatus.granted
case CLAuthorizationStatus.authorizedWhenInUse,
CLAuthorizationStatus.denied:
return PermissionStatus.denied
case CLAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
switch authorizationStatus {
case CLAuthorizationStatus.authorizedAlways,
CLAuthorizationStatus.authorizedWhenInUse:
return PermissionStatus.granted
case CLAuthorizationStatus.denied:
return PermissionStatus.denied
case CLAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
switch authorizationStatus {
case CLAuthorizationStatus.authorized:
return PermissionStatus.granted
case CLAuthorizationStatus.denied:
return PermissionStatus.denied
case CLAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#include "PermissionStrategy.h"
@interface MediaLibraryPermissionStrategy : NSObject <PermissionStrategy>
@end
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "MediaLibraryPermissionStrategy.h"
@implementation MediaLibraryPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return [MediaLibraryPermissionStrategy permissionStatus];
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusNotApplicable;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
completionHandler(status);
return;
}
if (@available(iOS 9.3, *)) {
[MPMediaLibrary requestAuthorization:^(MPMediaLibraryAuthorizationStatus status) {
completionHandler([MediaLibraryPermissionStrategy determinePermissionStatus:status]);
}];
} else {
completionHandler(PermissionStatusUnknown);
return;
}
}
+ (PermissionStatus)permissionStatus {
if (@available(iOS 9.3, *)) {
MPMediaLibraryAuthorizationStatus status = [MPMediaLibrary authorizationStatus];
return [MediaLibraryPermissionStrategy determinePermissionStatus:status];
}
return PermissionStatusUnknown;
}
+ (PermissionStatus)determinePermissionStatus:(MPMediaLibraryAuthorizationStatus)authorizationStatus {
switch (authorizationStatus) {
case MPMediaLibraryAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case MPMediaLibraryAuthorizationStatusDenied:
return PermissionStatusDenied;
case MPMediaLibraryAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case MPMediaLibraryAuthorizationStatusAuthorized:
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
}
@end
\ No newline at end of file
//
// MediaLibraryPermissions.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import Foundation
import MediaPlayer
class MediaLibraryPermissionStrategy : NSObject, PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
return MediaLibraryPermissionStrategy.getPermissionStatus()
}
private static func getPermissionStatus() -> PermissionStatus {
if #available(iOS 9.3, *) {
let status: MPMediaLibraryAuthorizationStatus = MPMediaLibrary.authorizationStatus()
return MediaLibraryPermissionStrategy.determinePermissionStatus(authorizationStatus: status)
}
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) -> Void {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
completionHandler(status)
return
}
if #available(iOS 9.3, *) {
MPMediaLibrary.requestAuthorization { (status: MPMediaLibraryAuthorizationStatus) in
completionHandler(
MediaLibraryPermissionStrategy.determinePermissionStatus(authorizationStatus: status))
}
} else {
completionHandler(PermissionStatus.unknown)
return
}
}
@available(iOS 9.3, *)
private static func determinePermissionStatus(authorizationStatus: MPMediaLibraryAuthorizationStatus) -> PermissionStatus {
switch authorizationStatus {
case MPMediaLibraryAuthorizationStatus.authorized:
return PermissionStatus.granted
case MPMediaLibraryAuthorizationStatus.denied:
return PermissionStatus.denied
case MPMediaLibraryAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Enums.h"
typedef void (^PermissionStatusHandler)(PermissionStatus permissionStatus);
@protocol PermissionStrategy <NSObject>
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission;
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission;
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler;
@end
//
// Task.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import Foundation
typealias PermissionStatusHandler = (_ permissionStatus: PermissionStatus) -> Void
protocol PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler)
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "PermissionStrategy.h"
#import <Photos/Photos.h>
@interface PhotoPermissionStrategy : NSObject <PermissionStrategy>
@end
\ No newline at end of file
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "PhotoPermissionStrategy.h"
@implementation PhotoPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return [PhotoPermissionStrategy permissionStatus];
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusNotApplicable;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
completionHandler(status);
return;
}
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus authorizationStatus) {
completionHandler([PhotoPermissionStrategy determinePermissionStatus:authorizationStatus]);
}];
}
+ (PermissionStatus)permissionStatus {
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
return [PhotoPermissionStrategy determinePermissionStatus:status];
}
+ (PermissionStatus)determinePermissionStatus:(PHAuthorizationStatus)authorizationStatus {
switch (authorizationStatus) {
case PHAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case PHAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case PHAuthorizationStatusDenied:
return PermissionStatusDenied;
case PHAuthorizationStatusAuthorized:
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
}
@end
\ No newline at end of file
//
// PhotoPermissions.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import Foundation
import Photos
class PhotoPermissionStrategy : NSObject, PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
return PhotoPermissionStrategy.getPermissionStatus()
}
private static func getPermissionStatus() -> PermissionStatus {
let status: PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
return PhotoPermissionStrategy.determinePermissionStatus(authorizationStatus: status)
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
completionHandler(status)
return
}
PHPhotoLibrary.requestAuthorization { (authorizationStatus: PHAuthorizationStatus) in
completionHandler(
PhotoPermissionStrategy.determinePermissionStatus(authorizationStatus: authorizationStatus))
}
}
private static func determinePermissionStatus(authorizationStatus: PHAuthorizationStatus) -> PermissionStatus {
switch authorizationStatus {
case PHAuthorizationStatus.authorized:
return PermissionStatus.granted
case PHAuthorizationStatus.denied:
return PermissionStatus.denied
case PHAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <CoreMotion/CoreMotion.h>
#import <Foundation/Foundation.h>
#import "PermissionStrategy.h"
@interface SensorPermissionStrategy : NSObject <PermissionStrategy>
@end
\ No newline at end of file
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "SensorPermissionStrategy.h"
@implementation SensorPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return [SensorPermissionStrategy permissionStatus];
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
if (@available(iOS 11.0, *)) {
return [CMMotionActivityManager isActivityAvailable]
? ServiceStatusEnabled
: ServiceStatusDisabled;
}
return ServiceStatusUnknown;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
completionHandler(status);
return;
}
if (@available(iOS 11.0, *)) {
CMMotionActivityManager *motionManager = [[CMMotionActivityManager alloc] init];
NSDate *today = [NSDate new];
[motionManager queryActivityStartingFromDate:today toDate:today toQueue:[NSOperationQueue mainQueue] withHandler:^(NSArray<CMMotionActivity *> *__nullable activities, NSError *__nullable error) {
if (error != nil && error.code == CMErrorMotionActivityNotAuthorized) {
completionHandler(PermissionStatusDenied);
} else {
completionHandler(PermissionStatusGranted);
}
}];
} else {
completionHandler(PermissionStatusUnknown);
}
}
+ (PermissionStatus)permissionStatus {
if (@available(iOS 11.0, *)) {
CMAuthorizationStatus status = [CMMotionActivityManager authorizationStatus];
PermissionStatus permissionStatus;
switch (status) {
case CMAuthorizationStatusNotDetermined:
permissionStatus = PermissionStatusUnknown;
break;
case CMAuthorizationStatusRestricted:
permissionStatus = PermissionStatusRestricted;
break;
case CMAuthorizationStatusDenied:
permissionStatus = PermissionStatusDenied;
break;
case CMAuthorizationStatusAuthorized:
permissionStatus = PermissionStatusGranted;
break;
default:
permissionStatus = PermissionStatusGranted;
}
if ((permissionStatus == PermissionStatusGranted || permissionStatus == PermissionStatusDenied) && ![CMMotionActivityManager isActivityAvailable]) {
return PermissionStatusDisabled;
} else {
return permissionStatus;
}
}
return PermissionStatusUnknown;
}
@end
//
// SensorPermissions.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import CoreMotion
import Foundation
class SensorPermissionStrategy : NSObject, PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
return SensorPermissionStrategy.getPermissionStatus()
}
private static func getPermissionStatus() -> PermissionStatus {
if #available(iOS 11.0, *) {
let status: CMAuthorizationStatus = CMMotionActivityManager.authorizationStatus()
var permissionStatus: PermissionStatus
switch status {
case CMAuthorizationStatus.authorized:
permissionStatus = PermissionStatus.granted
case CMAuthorizationStatus.denied:
permissionStatus = PermissionStatus.denied
case CMAuthorizationStatus.restricted:
permissionStatus = PermissionStatus.restricted
default:
permissionStatus = PermissionStatus.unknown
}
if (permissionStatus == PermissionStatus.granted || permissionStatus == PermissionStatus.denied) && !CMMotionActivityManager.isActivityAvailable() {
return PermissionStatus.disabled
} else {
return permissionStatus
}
}
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
if #available(iOS 11.0, *) {
return CMMotionActivityManager.isActivityAvailable()
? ServiceStatus.enabled
: ServiceStatus.disabled
}
return ServiceStatus.unknown
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
completionHandler(status)
return
}
if #available(iOS 11.0, *) {
let motionManager = CMMotionActivityManager.init()
motionManager.startActivityUpdates(to: OperationQueue.main) { (_) in
motionManager.stopActivityUpdates()
completionHandler(.granted)
}
} else {
completionHandler(.unknown)
}
}
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "PermissionStrategy.h"
#import <Speech/Speech.h>
@interface SpeechPermissionStrategy : NSObject <PermissionStrategy>
@end
\ No newline at end of file
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "SpeechPermissionStrategy.h"
@implementation SpeechPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return [SpeechPermissionStrategy permissionStatus];
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusNotApplicable;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
PermissionStatus status = [self checkPermissionStatus:permission];
if (status != PermissionStatusUnknown) {
completionHandler(status);
return;
}
if (@available(iOS 10.0, *)) {
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus authorizationStatus) {
completionHandler([SpeechPermissionStrategy determinePermissionStatus:authorizationStatus]);
}];
} else {
completionHandler(PermissionStatusUnknown);
}
}
+ (PermissionStatus)permissionStatus {
if (@available(iOS 10.0, *)) {
SFSpeechRecognizerAuthorizationStatus status = [SFSpeechRecognizer authorizationStatus];
return [SpeechPermissionStrategy determinePermissionStatus:status];
}
return PermissionStatusUnknown;
}
+ (PermissionStatus)determinePermissionStatus:(SFSpeechRecognizerAuthorizationStatus)authorizationStatus {
switch (authorizationStatus) {
case SFSpeechRecognizerAuthorizationStatusNotDetermined:
return PermissionStatusUnknown;
case SFSpeechRecognizerAuthorizationStatusDenied:
return PermissionStatusDenied;
case SFSpeechRecognizerAuthorizationStatusRestricted:
return PermissionStatusRestricted;
case SFSpeechRecognizerAuthorizationStatusAuthorized:
return PermissionStatusGranted;
}
return PermissionStatusUnknown;
}
@end
//
// SpeechPermissions.swift
// permission_handler
//
// Created by Maurits van Beusekom on 26/07/2018.
//
import Foundation
import Speech
class SpeechPermissionStrategy : NSObject, PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
return SpeechPermissionStrategy.getPermissionStatus()
}
private static func getPermissionStatus() -> PermissionStatus {
if #available(iOS 10.0, *) {
let status: SFSpeechRecognizerAuthorizationStatus = SFSpeechRecognizer.authorizationStatus()
return SpeechPermissionStrategy.determinePermissionStatus(authorizationStatus: status)
}
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.notApplicable
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
let status = checkPermissionStatus(permission: permission)
if status != PermissionStatus.unknown {
completionHandler(status)
return
}
if #available(iOS 10.0, *) {
SFSpeechRecognizer.requestAuthorization { (authorizationStatus: SFSpeechRecognizerAuthorizationStatus) in
completionHandler(
SpeechPermissionStrategy.determinePermissionStatus(authorizationStatus: authorizationStatus))
return
}
} else {
completionHandler(PermissionStatus.unknown)
}
}
@available(iOS 10.0, *)
private static func determinePermissionStatus(authorizationStatus: SFSpeechRecognizerAuthorizationStatus) -> PermissionStatus {
switch authorizationStatus {
case SFSpeechRecognizerAuthorizationStatus.authorized:
return PermissionStatus.granted
case SFSpeechRecognizerAuthorizationStatus.denied:
return PermissionStatus.denied
case SFSpeechRecognizerAuthorizationStatus.restricted:
return PermissionStatus.restricted
default:
return PermissionStatus.unknown
}
}
}
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "PermissionStrategy.h"
@interface UnknownPermissionStrategy : NSObject <PermissionStrategy>
@end
\ No newline at end of file
//
// Created by Razvan Lung(long1eu) on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "UnknownPermissionStrategy.h"
@implementation UnknownPermissionStrategy
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return PermissionStatusUnknown;
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return ServiceStatusUnknown;
}
- (void)requestPermission:(PermissionGroup)permission completionHandler:(PermissionStatusHandler)completionHandler {
completionHandler(PermissionStatusUnknown);
}
@end
\ No newline at end of file
//
// UnknownPermissionStrategy.swift
// permission_handler
//
// Created by Maurits van Beusekom on 07/08/2018.
//
import Foundation
class UnknownPermissionStrategy : NSObject, PermissionStrategy {
func checkPermissionStatus(permission: PermissionGroup) -> PermissionStatus {
return PermissionStatus.unknown
}
func checkServiceStatus(permission: PermissionGroup) -> ServiceStatus {
return ServiceStatus.unknown
}
func requestPermission(permission: PermissionGroup, completionHandler: @escaping PermissionStatusHandler) {
completionHandler(PermissionStatus.unknown)
}
}
//
// Created by Razvan Lung on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Enums.h"
@interface Codec : NSObject
+ (PermissionGroup)decodePermissionGroupFrom:(NSNumber *_Nonnull)event;
+ (NSArray*_Nullable)decodePermissionGroupsFrom:(NSArray<NSNumber *> *_Nullable)event;
+ (NSNumber *_Nullable)encodePermissionStatus:(enum PermissionStatus)permissionStatus;
+ (NSNumber *_Nullable)encodeServiceStatus:(enum ServiceStatus)serviceStatus;
@end
//
// Created by Razvan Lung on 2019-02-15.
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
//
#import "Codec.h"
@implementation Codec
+ (PermissionGroup)decodePermissionGroupFrom:(NSNumber *)event {
return (PermissionGroup) event.intValue;
}
+ (NSArray *_Nullable)decodePermissionGroupsFrom:(NSArray<NSNumber *> *)event {
NSMutableArray *result = [[NSMutableArray alloc] init];
for (NSNumber *number in event) {
[result addObject:@([self decodePermissionGroupFrom:number])];
}
return [[NSArray alloc] initWithArray:result];
}
+ (NSNumber *_Nullable)encodePermissionStatus:(enum PermissionStatus)permissionStatus {
return [[NSNumber alloc] initWithInt:permissionStatus];
}
+ (NSNumber *_Nullable)encodeServiceStatus:(enum ServiceStatus)serviceStatus {
return [[NSNumber alloc] initWithInt:serviceStatus];
}
@end
//
// Codec.swift
// permission_handler
//
// Created by Maurits van Beusekom on 25/07/2018.
//
import Foundation
struct Codec {
private static let jsonDecoder = JSONDecoder()
private static let jsonEncoder = JSONEncoder()
static func decodePermissionGroup(from arguments: Any?) -> PermissionGroup {
var permissionString: String = arguments as! String
permissionString.removeFirst()
permissionString.removeLast()
return PermissionGroup(rawValue: permissionString)!
}
static func decodePermissionGroups(from arguments: Any?) -> [PermissionGroup] {
let data = (arguments as! String).data(using: .utf8)
let permissions = try! jsonDecoder.decode([PermissionGroup].self, from: data!)
return permissions
}
static func encodePermissionStatus(permissionStatus: PermissionStatus) -> String? {
let status = "\"" + permissionStatus.rawValue + "\""
return status
}
static func encodeServiceStatus(serviceStatus: ServiceStatus) -> String? {
let status = "\"" + serviceStatus.rawValue + "\""
return status
}
static func encodePermissionRequestResult(permissionStatusResult: [PermissionGroup: PermissionStatus]) -> String? {
let jsonDict = Dictionary(uniqueKeysWithValues:
permissionStatusResult.map {
(key: PermissionGroup, value: PermissionStatus) in (key.rawValue, value.rawValue)
})
let jsonData = try! JSONSerialization.data(withJSONObject: jsonDict, options: [])
let jsonString = String(data: jsonData, encoding: .utf8)!
return jsonString
}
}
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
# #
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'permission_handler' s.name = 'permission_handler'
s.version = '2.2.0' s.version = '3.0.0'
s.summary = 'Permission plugin for Flutter.' s.summary = 'Permission plugin for Flutter.'
s.description = <<-DESC s.description = <<-DESC
Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. A new Flutter project.
DESC DESC
s.homepage = 'https://github.com/baseflowit/flutter-permission-handler' s.homepage = 'https://github.com/baseflowit/flutter-permission-handler'
s.license = { :file => '../LICENSE' } s.license = { :file => '../LICENSE' }
...@@ -15,8 +15,7 @@ Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Andro ...@@ -15,8 +15,7 @@ Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Andro
s.source_files = 'Classes/**/*' s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h' s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter' s.dependency 'Flutter'
s.swift_version = '4.2'
s.ios.deployment_target = '8.0' s.ios.deployment_target = '8.0'
s.pod_target_xcconfig = { 'SWIFT_VERSION' => '4.2' }
end end
library permission_handler; library permission_handler;
import 'dart:async'; export 'src/permission_enums.dart';
import 'dart:convert'; export 'src/permission_handler.dart';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
part 'package:permission_handler/permission_enums.dart';
part 'package:permission_handler/utils/codec.dart';
/// Provides a cross-platform (iOS, Android) API to request and check permissions.
class PermissionHandler {
factory PermissionHandler() {
if (_instance == null) {
const MethodChannel methodChannel =
MethodChannel('flutter.baseflow.com/permissions/methods');
_instance = PermissionHandler.private(methodChannel);
}
return _instance;
}
@visibleForTesting
PermissionHandler.private(this._methodChannel);
static PermissionHandler _instance;
final MethodChannel _methodChannel;
/// Check current permission status.
///
/// Returns a [Future] containing the current permission status for the supplied [PermissionGroup].
Future<PermissionStatus> checkPermissionStatus(
PermissionGroup permission) async {
final String status = await _methodChannel.invokeMethod(
'checkPermissionStatus', Codec.encodePermissionGroup(permission));
return Codec.decodePermissionStatus(status);
}
/// Check current service status.
///
/// Returns a [Future] containing the current service status for the supplied [PermissionGroup].
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) async {
final String status = await _methodChannel.invokeMethod(
'checkServiceStatus', Codec.encodePermissionGroup(permission));
return Codec.decodeServiceStatus(status);
}
/// Open the App settings page.
///
/// Returns [true] if the app settings page could be opened, otherwise [false] is returned.
Future<bool> openAppSettings() async {
final bool hasOpened = await _methodChannel.invokeMethod('openAppSettings');
return hasOpened;
}
/// Request the user for access to the supplied list of permissiongroups.
///
/// Returns a [Map] containing the status per requested permissiongroup.
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) async {
final String jsonData = Codec.encodePermissionGroups(permissions);
final String status =
await _methodChannel.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].
Future<bool> shouldShowRequestPermissionRationale(
PermissionGroup permission) async {
if (!Platform.isAndroid) {
return false;
}
final bool shouldShowRationale = await _methodChannel.invokeMethod(
'shouldShowRequestPermissionRationale',
Codec.encodePermissionGroup(permission));
return shouldShowRationale;
}
}
part of permission_handler;
/// Defines the state of a permission group /// Defines the state of a permission group
enum PermissionStatus { class PermissionStatus {
const PermissionStatus._(this.value);
final int value;
/// Permission to access the requested feature is denied by the user. /// Permission to access the requested feature is denied by the user.
denied, static const PermissionStatus denied = PermissionStatus._(0);
/// The feature is disabled (or not available) on the device. /// The feature is disabled (or not available) on the device.
disabled, static const PermissionStatus disabled = PermissionStatus._(1);
/// Permission to access the requested feature is granted by the user. /// Permission to access the requested feature is granted by the user.
granted, static const PermissionStatus granted = PermissionStatus._(2);
/// The user granted restricted access to the requested feature (only on iOS). /// The user granted restricted access to the requested feature (only on iOS).
restricted, static const PermissionStatus restricted = PermissionStatus._(3);
/// Permission is in an unknown state /// Permission is in an unknown state
unknown static const PermissionStatus unknown = PermissionStatus._(4);
static const List<PermissionStatus> values = <PermissionStatus>[
denied,
disabled,
granted,
restricted,
unknown,
];
static const List<String> _names = <String>[
'denied',
'disabled',
'granted',
'restricted',
'unknown',
];
@override
String toString() => 'PermissionStatus.${_names[value]}';
} }
/// Defines the state of a service related to the permission group /// Defines the state of a service related to the permission group
enum ServiceStatus { class ServiceStatus {
/// The unknown service status indicates the state of the service could not be determined. const ServiceStatus._(this.value);
unknown,
/// There is no service for the supplied permission group. final int value;
notApplicable,
/// The service for the supplied permission group is disabled. /// The service for the supplied permission group is disabled.
disabled, static const ServiceStatus disabled = ServiceStatus._(0);
/// The service for the supplied permission group is enabled. /// The service for the supplied permission group is enabled.
enabled static const ServiceStatus enabled = ServiceStatus._(1);
/// There is no service for the supplied permission group.
static const ServiceStatus notApplicable = ServiceStatus._(2);
/// The unknown service status indicates the state of the service could not be determined.
static const ServiceStatus unknown = ServiceStatus._(3);
static const List<ServiceStatus> values = <ServiceStatus>[
disabled,
enabled,
notApplicable,
unknown,
];
static const List<String> _names = <String>[
'disabled',
'enabled',
'notApplicable',
'unknown',
];
@override
String toString() => 'ServiceStatus.${_names[value]}';
} }
/// Defines the permission groups for which permissions can be checked or requested. /// Defines the permission groups for which permissions can be checked or requested.
enum PermissionGroup { class PermissionGroup {
/// The unknown permission only used for return type, never requested const PermissionGroup._(this.value);
unknown,
final int value;
/// Android: Calendar /// Android: Calendar
/// iOS: Calendar (Events) /// iOS: Calendar (Events)
calendar, static const PermissionGroup calendar = PermissionGroup._(0);
/// Android: Camera /// Android: Camera
/// iOS: Photos (Camera Roll and Camera) /// iOS: Photos (Camera Roll and Camera)
camera, static const PermissionGroup camera = PermissionGroup._(1);
/// Android: Contacts /// Android: Contacts
/// iOS: AddressBook /// iOS: AddressBook
contacts, static const PermissionGroup contacts = PermissionGroup._(2);
/// Android: Fine and Coarse Location /// Android: Fine and Coarse Location
/// iOS: CoreLocation (Always and WhenInUse) /// iOS: CoreLocation (Always and WhenInUse)
location, static const PermissionGroup location = PermissionGroup._(3);
/// Android: Fine and Coarse Location
/// iOS: CoreLocation - Always
static const PermissionGroup locationAlways = PermissionGroup._(4);
/// Android: Fine and Coarse Location
/// iOS: CoreLocation - WhenInUse
static const PermissionGroup locationWhenInUse = PermissionGroup._(5);
/// Android: None
/// iOS: MPMediaLibrary
static const PermissionGroup mediaLibrary = PermissionGroup._(6);
/// Android: Microphone /// Android: Microphone
/// iOS: Microphone /// iOS: Microphone
microphone, static const PermissionGroup microphone = PermissionGroup._(7);
/// Android: Phone /// Android: Phone
/// iOS: Nothing /// iOS: Nothing
phone, static const PermissionGroup phone = PermissionGroup._(8);
/// Android: Nothing /// Android: Nothing
/// iOS: Photos /// iOS: Photos
photos, static const PermissionGroup photos = PermissionGroup._(9);
/// Android: Nothing /// Android: Nothing
/// iOS: Reminders /// iOS: Reminders
reminders, static const PermissionGroup reminders = PermissionGroup._(10);
/// Android: Body Sensors /// Android: Body Sensors
/// iOS: CoreMotion /// iOS: CoreMotion
sensors, static const PermissionGroup sensors = PermissionGroup._(11);
/// Android: Sms /// Android: Sms
/// iOS: Nothing /// iOS: Nothing
sms, static const PermissionGroup sms = PermissionGroup._(12);
/// Android: External Storage
/// iOS: Nothing
storage,
/// Android: Microphone /// Android: Microphone
/// iOS: Speech /// iOS: Speech
speech, static const PermissionGroup speech = PermissionGroup._(13);
/// Android: Fine and Coarse Location
/// iOS: CoreLocation - Always
locationAlways,
/// Android: Fine and Coarse Location /// Android: External Storage
/// iOS: CoreLocation - WhenInUse /// iOS: Nothing
locationWhenInUse, static const PermissionGroup storage = PermissionGroup._(14);
/// Android: None /// The unknown permission only used for return type, never requested
/// iOS: MPMediaLibrary static const PermissionGroup unknown = PermissionGroup._(15);
mediaLibrary
static const List<PermissionGroup> values = <PermissionGroup>[
calendar,
camera,
contacts,
location,
locationAlways,
locationWhenInUse,
mediaLibrary,
microphone,
phone,
photos,
reminders,
sensors,
sms,
speech,
storage,
unknown,
];
static const List<String> _names = <String>[
'calendar',
'camera',
'contacts',
'location',
'locationAlways',
'locationWhenInUse',
'mediaLibrary',
'microphone',
'phone',
'photos',
'reminders',
'sensors',
'sms',
'speech',
'storage',
'unknown',
];
@override
String toString() => 'PermissionGroup.${_names[value]}';
} }
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:permission_handler/src/permission_enums.dart';
import 'package:permission_handler/src/utils/codec.dart';
/// Provides a cross-platform (iOS, Android) API to request and check permissions.
class PermissionHandler {
factory PermissionHandler() {
if (_instance == null) {
const MethodChannel methodChannel =
MethodChannel('flutter.baseflow.com/permissions/methods');
_instance = PermissionHandler.private(methodChannel);
}
return _instance;
}
@visibleForTesting
PermissionHandler.private(this._methodChannel);
static PermissionHandler _instance;
final MethodChannel _methodChannel;
/// Check current permission status.
///
/// Returns a [Future] containing the current permission status for the supplied [PermissionGroup].
Future<PermissionStatus> checkPermissionStatus(
PermissionGroup permission) async {
final int status = await _methodChannel.invokeMethod(
'checkPermissionStatus', permission.value);
return Codec.decodePermissionStatus(status);
}
/// Check current service status.
///
/// Returns a [Future] containing the current service status for the supplied [PermissionGroup].
Future<ServiceStatus> checkServiceStatus(PermissionGroup permission) async {
final int status = await _methodChannel.invokeMethod(
'checkServiceStatus', permission.value);
return Codec.decodeServiceStatus(status);
}
/// Open the App settings page.
///
/// Returns [true] if the app settings page could be opened, otherwise [false] is returned.
Future<bool> openAppSettings() async {
final bool hasOpened = await _methodChannel.invokeMethod('openAppSettings');
return hasOpened;
}
/// Request the user for access to the supplied list of permissiongroups.
///
/// Returns a [Map] containing the status per requested permissiongroup.
Future<Map<PermissionGroup, PermissionStatus>> requestPermissions(
List<PermissionGroup> permissions) async {
final List<int> data = Codec.encodePermissionGroups(permissions);
final Map<dynamic, dynamic> status =
await _methodChannel.invokeMethod('requestPermissions', data);
return Codec.decodePermissionRequestResult(Map<int, int>.from(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].
Future<bool> shouldShowRequestPermissionRationale(
PermissionGroup permission) async {
if (!Platform.isAndroid) {
return false;
}
final bool shouldShowRationale = await _methodChannel.invokeMethod(
'shouldShowRequestPermissionRationale', permission.value);
return shouldShowRationale;
}
}
import 'package:permission_handler/src/permission_enums.dart';
class Codec {
static PermissionStatus decodePermissionStatus(int value) {
return PermissionStatus.values[value];
}
static ServiceStatus decodeServiceStatus(int value) {
return ServiceStatus.values[value];
}
static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult(
Map<int, int> value) {
print('decodePermissionRequestResult called with: value:[$value]');
return value.map((int key, int value) =>
MapEntry<PermissionGroup, PermissionStatus>(
PermissionGroup.values[key], PermissionStatus.values[value]));
}
static List<int> encodePermissionGroups(List<PermissionGroup> permissions) {
return permissions.map((PermissionGroup it) => it.value).toList();
}
}
part of permission_handler;
class Codec {
static PermissionStatus decodePermissionStatus(String value) {
final String permission = json.decode(value);
return PermissionStatus.values.firstWhere(
(PermissionStatus e) => e.toString().split('.').last == permission);
}
static ServiceStatus decodeServiceStatus(String value) {
final String status = json.decode(value);
return ServiceStatus.values.firstWhere(
(ServiceStatus s) => s.toString().split('.').last == status);
}
static Map<PermissionGroup, PermissionStatus> decodePermissionRequestResult(
String value) {
final Map<String, dynamic> jsonObject = json.decode(value);
final Map<PermissionGroup, PermissionStatus> permissionResults =
<PermissionGroup, PermissionStatus>{};
jsonObject.forEach((String key, dynamic value) {
final PermissionGroup permissionGroup = PermissionGroup.values.firstWhere(
(PermissionGroup e) =>
e.toString().split('.').last == key.toString());
final PermissionStatus permissionStatus = PermissionStatus.values
.firstWhere((PermissionStatus 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((PermissionGroup p) => _encodeEnum(p)).toList());
static String _encodeEnum(dynamic value) {
return value.toString().split('.').last;
}
}
...@@ -8,11 +8,11 @@ ...@@ -8,11 +8,11 @@
<excludeFolder url="file://$MODULE_DIR$/.idea" /> <excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/.pub" /> <excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" /> <excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/.pub" /> <excludeFolder url="file://$MODULE_DIR$/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/build" /> <excludeFolder url="file://$MODULE_DIR$/example/build" />
</content> </content>
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart Packages" level="project" />
<orderEntry type="library" name="Dart SDK" level="project" /> <orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Flutter Plugins" level="project" /> <orderEntry type="library" name="Flutter Plugins" level="project" />
</component> </component>
......
name: permission_handler name: permission_handler
description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
version: 2.2.0 version: 3.0.0
author: Baseflow <hello@baseflow.com> authors:
- Baseflow <hello@baseflow.com>
- long1eu <home@long1.eu>
homepage: https://github.com/baseflowit/flutter-permission-handler homepage: https://github.com/baseflowit/flutter-permission-handler
environment:
sdk: ">=2.0.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
meta: ^1.1.6
# For information on the generic Dart part of this file, see the meta: ^1.1.6
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter: flutter:
plugin: plugin:
androidPackage: com.baseflow.permissionhandler androidPackage: com.baseflow.permissionhandler
pluginClass: PermissionHandlerPlugin pluginClass: PermissionHandlerPlugin
\ No newline at end of file
environment:
sdk: ">=2.1.0-dev.5.0 <3.0.0"
# To add assets to your plugin package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.io/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# To add custom fonts to your plugin package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.io/custom-fonts/#from-packages
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