Commit afb1db36 by Razvan Cristian Lung

migrate Swift and Kotlin to ObjC and Java

parent 12c1a0a8
group 'com.baseflow.permissionhandler' group 'com.baseflow.permissionhandler.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,17 +21,13 @@ rootProject.allprojects { ...@@ -22,17 +21,13 @@ 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 "android.support.test.runner.AndroidJUnitRunner"
} }
lintOptions { lintOptions {
disable 'InvalidPackage' disable 'InvalidPackage'
...@@ -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.1.0-alpha04'
}
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" repositories {
implementation "com.google.code.gson:gson:2.8.5" google()
} }
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.baseflow.permissionhandler"> package="com.baseflow.permissionhandler.permissionhandler">
</manifest> </manifest>
package com.baseflow.permissionhandler
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Build
import android.provider.Settings
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import android.util.Log
import com.baseflow.permissionhandler.data.PermissionGroup
import com.baseflow.permissionhandler.data.PermissionStatus
import com.baseflow.permissionhandler.data.ServiceStatus
import com.baseflow.permissionhandler.utils.Codec
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.Registrar
import android.text.TextUtils
import android.provider.Settings.SettingNotFoundException
class PermissionHandlerPlugin(private val registrar: Registrar, private var requestedPermissions: MutableList<String>? = null) : MethodCallHandler {
private var mRequestResults = mutableMapOf<PermissionGroup, PermissionStatus>()
private var mResult: Result? = null
companion object {
const val permissionCode = 25
@JvmStatic
private val mLogTag = "permissions_handler"
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "flutter.baseflow.com/permissions/methods")
val instance = PermissionHandlerPlugin(registrar)
channel.setMethodCallHandler(instance)
registrar.addRequestPermissionsResultListener(PluginRegistry.RequestPermissionsResultListener { id, permissions, grantResults ->
if (id == permissionCode) {
instance.handlePermissionsRequest(permissions, grantResults)
return@RequestPermissionsResultListener true
}
return@RequestPermissionsResultListener false
})
}
@JvmStatic
fun parseManifestName(permission: String): PermissionGroup {
when (permission) {
Manifest.permission.READ_CALENDAR,
Manifest.permission.WRITE_CALENDAR ->
return PermissionGroup.CALENDAR
Manifest.permission.CAMERA ->
return PermissionGroup.CAMERA
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS,
Manifest.permission.GET_ACCOUNTS ->
return PermissionGroup.CONTACTS
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION ->
return PermissionGroup.LOCATION
Manifest.permission.RECORD_AUDIO ->
return PermissionGroup.MICROPHONE
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CALL_PHONE,
Manifest.permission.READ_CALL_LOG,
Manifest.permission.WRITE_CALL_LOG,
Manifest.permission.ADD_VOICEMAIL,
Manifest.permission.USE_SIP,
Manifest.permission.PROCESS_OUTGOING_CALLS ->
return PermissionGroup.PHONE
Manifest.permission.BODY_SENSORS ->
return PermissionGroup.SENSORS
Manifest.permission.SEND_SMS,
Manifest.permission.RECEIVE_SMS,
Manifest.permission.READ_SMS,
Manifest.permission.RECEIVE_WAP_PUSH,
Manifest.permission.RECEIVE_MMS ->
return PermissionGroup.SMS
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE ->
return PermissionGroup.STORAGE
}
return PermissionGroup.UNKNOWN
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
when {
call.method == "checkPermissionStatus" -> {
val permission = Codec.decodePermissionGroup(call.arguments)
val permissionStatus = checkPermissionStatus(permission)
result?.success(Codec.encodePermissionStatus(permissionStatus))
}
call.method == "checkServiceStatus" -> {
val permission = Codec.decodePermissionGroup(call.arguments)
val serviceStatus = checkServiceStatus(permission)
result?.success(Codec.encodeServiceStatus(serviceStatus))
}
call.method == "requestPermissions" -> {
if (mResult != null) {
result.error(
"ERROR_ALREADY_REQUESTING_PERMISSIONS",
"A request for permissions is already running, please wait for it to finish before doing another request (note that you can request multiple permissions at the same time).",
null)
}
mResult = result
val permissions = Codec.decodePermissionGroups(call.arguments)
requestPermissions(permissions)
}
call.method == "shouldShowRequestPermissionRationale" -> {
val permission = Codec.decodePermissionGroup(call.arguments)
result.success(shouldShowRequestPermissionRationale(permission))
}
call.method == "openAppSettings" -> {
val isOpen = openAppSettings()
result.success(isOpen)
}
else -> result.notImplemented()
}
}
private fun checkPermissionStatus(permission: PermissionGroup): PermissionStatus {
val names = getManifestNames(permission)
if (names == null) {
Log.d(mLogTag, "No android specific permissions needed for: $permission")
return PermissionStatus.GRANTED
}
//if no permissions were found then there is an issue and permission is not set in Android manifest
if (names.count() == 0) {
Log.d(mLogTag, "No permissions found in manifest for: $permission")
return PermissionStatus.UNKNOWN
}
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return PermissionStatus.UNKNOWN
}
val targetsMOrHigher = context.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.M
for (name in names) {
if (targetsMOrHigher) {
val permissionStatus = ContextCompat.checkSelfPermission(context, name)
if (permissionStatus == PackageManager.PERMISSION_DENIED) {
return PermissionStatus.DENIED
} else if (permissionStatus != PackageManager.PERMISSION_GRANTED) {
return PermissionStatus.UNKNOWN
}
}
}
if (permission == PermissionGroup.LOCATION || permission == PermissionGroup.LOCATION_ALWAYS || permission == PermissionGroup.LOCATION_WHEN_IN_USE) {
if (!isLocationServiceEnabled(context)) {
return PermissionStatus.DISABLED
}
}
return PermissionStatus.GRANTED
}
private fun checkServiceStatus(permission: PermissionGroup) : ServiceStatus {
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return ServiceStatus.UNKNOWN
}
if (permission == PermissionGroup.LOCATION || permission == PermissionGroup.LOCATION_ALWAYS || permission == PermissionGroup.LOCATION_WHEN_IN_USE) {
return if(isLocationServiceEnabled(context)) ServiceStatus.ENABLED else ServiceStatus.DISABLED
}
return ServiceStatus.NOT_APPLICABLE
}
private fun shouldShowRequestPermissionRationale(permission: PermissionGroup) : Boolean {
val activity = registrar.activity()
if(activity == null)
{
Log.d(mLogTag, "Unable to detect current Activity.")
return false
}
val names = getManifestNames(permission)
// if isn't an android specific group then go ahead and return false;
if (names == null)
{
Log.d(mLogTag, "No android specific permissions needed for: $permission")
return false
}
if (names.isEmpty())
{
Log.d(mLogTag,"No permissions found in manifest for: $permission no need to show request rationale")
return false
}
for(name in names)
{
return ActivityCompat.shouldShowRequestPermissionRationale(activity, name)
}
return false
}
private fun requestPermissions(permissions: Array<PermissionGroup>) {
if (registrar.activity() == null) {
Log.d(mLogTag, "Unable to detect current Activity.")
for (permission in permissions) {
mRequestResults[permission] = PermissionStatus.UNKNOWN
}
processResult()
return
}
val permissionsToRequest = mutableListOf<String>()
for (permission in permissions) {
val permissionStatus = checkPermissionStatus(permission)
if (permissionStatus != PermissionStatus.GRANTED) {
val names = getManifestNames(permission)
//check to see if we can find manifest names
//if we can't add as unknown and continue
if (names == null || names.isEmpty()) {
if (!mRequestResults.containsKey(permission)) {
mRequestResults[permission] = PermissionStatus.UNKNOWN
}
continue
}
names.let { permissionsToRequest.addAll(it) }
} else {
if (!mRequestResults.containsKey(permission)) {
mRequestResults[permission] = PermissionStatus.GRANTED
}
}
}
if (permissionsToRequest.count() > 0) {
ActivityCompat.requestPermissions(
registrar.activity(),
permissionsToRequest.toTypedArray(),
permissionCode)
} else if (mRequestResults.count() > 0) {
processResult()
}
}
private fun handlePermissionsRequest(permissions: Array<String>, grantResults: IntArray) {
if (mResult == null) {
return
}
for (i in permissions.indices) {
val permission = parseManifestName(permissions[i])
if (permission == PermissionGroup.UNKNOWN)
continue
if (permission == PermissionGroup.MICROPHONE) {
if (!mRequestResults.containsKey(PermissionGroup.SPEECH)) {
mRequestResults[PermissionGroup.SPEECH] = grantResults[i].toPermissionStatus()
}
} else if (permission == PermissionGroup.LOCATION) {
val context: Context? = registrar.activity() ?: registrar.activeContext()
val isLocationServiceEnabled= if (context == null) false else isLocationServiceEnabled(context)
var permissionStatus = grantResults[i].toPermissionStatus()
if (permissionStatus == PermissionStatus.GRANTED && !isLocationServiceEnabled) {
permissionStatus = PermissionStatus.DISABLED
}
if (!mRequestResults.containsKey(PermissionGroup.LOCATION_ALWAYS)) {
mRequestResults[PermissionGroup.LOCATION_ALWAYS] = permissionStatus
}
if (!mRequestResults.containsKey(PermissionGroup.LOCATION_WHEN_IN_USE)) {
mRequestResults[PermissionGroup.LOCATION_WHEN_IN_USE] = permissionStatus
}
mRequestResults[permission] = permissionStatus
} else if (!mRequestResults.containsKey(permission)) {
mRequestResults[permission] = grantResults[i].toPermissionStatus()
}
}
processResult()
}
private fun Int.toPermissionStatus(): PermissionStatus {
return if (this == PackageManager.PERMISSION_GRANTED) PermissionStatus.GRANTED else PermissionStatus.DENIED
}
private fun processResult() {
mResult?.success(Codec.encodePermissionRequestResult(mRequestResults))
mRequestResults.clear()
mResult = null
}
private fun openAppSettings(): Boolean {
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return false
}
return try {
val settingsIntent = Intent()
settingsIntent.action = android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
settingsIntent.addCategory(Intent.CATEGORY_DEFAULT)
settingsIntent.data = android.net.Uri.parse("package:" + context.packageName)
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
context.startActivity(settingsIntent)
true
} catch(ex: Exception) {
false
}
}
private fun getManifestNames(permission: PermissionGroup): List<String>? {
val permissionNames: MutableList<String> = mutableListOf()
when (permission) {
PermissionGroup.CALENDAR -> {
if (hasPermissionInManifest(Manifest.permission.READ_CALENDAR))
permissionNames.add(Manifest.permission.READ_CALENDAR)
if (hasPermissionInManifest(Manifest.permission.WRITE_CALENDAR))
permissionNames.add(Manifest.permission.WRITE_CALENDAR)
}
PermissionGroup.CAMERA -> {
if (hasPermissionInManifest(Manifest.permission.CAMERA))
permissionNames.add(Manifest.permission.CAMERA)
}
PermissionGroup.CONTACTS -> {
if (hasPermissionInManifest(Manifest.permission.READ_CONTACTS))
permissionNames.add(Manifest.permission.READ_CONTACTS)
if (hasPermissionInManifest(Manifest.permission.WRITE_CONTACTS))
permissionNames.add(Manifest.permission.WRITE_CONTACTS)
if (hasPermissionInManifest(Manifest.permission.GET_ACCOUNTS))
permissionNames.add(Manifest.permission.GET_ACCOUNTS)
}
PermissionGroup.LOCATION_ALWAYS,
PermissionGroup.LOCATION_WHEN_IN_USE,
PermissionGroup.LOCATION -> {
if (hasPermissionInManifest(Manifest.permission.ACCESS_COARSE_LOCATION))
permissionNames.add(Manifest.permission.ACCESS_COARSE_LOCATION)
if (hasPermissionInManifest(Manifest.permission.ACCESS_FINE_LOCATION))
permissionNames.add(Manifest.permission.ACCESS_FINE_LOCATION)
}
PermissionGroup.SPEECH,
PermissionGroup.MICROPHONE -> {
if (hasPermissionInManifest(Manifest.permission.RECORD_AUDIO))
permissionNames.add(Manifest.permission.RECORD_AUDIO)
}
PermissionGroup.PHONE -> {
if (hasPermissionInManifest(Manifest.permission.READ_PHONE_STATE))
permissionNames.add(Manifest.permission.READ_PHONE_STATE)
if (hasPermissionInManifest(Manifest.permission.CALL_PHONE))
permissionNames.add(Manifest.permission.CALL_PHONE)
if (hasPermissionInManifest(Manifest.permission.READ_CALL_LOG))
permissionNames.add(Manifest.permission.READ_CALL_LOG)
if (hasPermissionInManifest(Manifest.permission.WRITE_CALL_LOG))
permissionNames.add(Manifest.permission.WRITE_CALL_LOG)
if (hasPermissionInManifest(Manifest.permission.ADD_VOICEMAIL))
permissionNames.add(Manifest.permission.ADD_VOICEMAIL)
if (hasPermissionInManifest(Manifest.permission.USE_SIP))
permissionNames.add(Manifest.permission.USE_SIP)
if (hasPermissionInManifest(Manifest.permission.PROCESS_OUTGOING_CALLS))
permissionNames.add(Manifest.permission.PROCESS_OUTGOING_CALLS)
}
PermissionGroup.SENSORS -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
if (hasPermissionInManifest(Manifest.permission.BODY_SENSORS)) {
permissionNames.add(Manifest.permission.BODY_SENSORS)
}
}
}
PermissionGroup.SMS -> {
if (hasPermissionInManifest(Manifest.permission.SEND_SMS))
permissionNames.add(Manifest.permission.SEND_SMS)
if (hasPermissionInManifest(Manifest.permission.RECEIVE_SMS))
permissionNames.add(Manifest.permission.RECEIVE_SMS)
if (hasPermissionInManifest(Manifest.permission.READ_SMS))
permissionNames.add(Manifest.permission.READ_SMS)
if (hasPermissionInManifest(Manifest.permission.RECEIVE_WAP_PUSH))
permissionNames.add(Manifest.permission.RECEIVE_WAP_PUSH)
if (hasPermissionInManifest(Manifest.permission.RECEIVE_MMS))
permissionNames.add(Manifest.permission.RECEIVE_MMS)
}
PermissionGroup.STORAGE -> {
if (hasPermissionInManifest(Manifest.permission.READ_EXTERNAL_STORAGE))
permissionNames.add(Manifest.permission.READ_EXTERNAL_STORAGE)
if (hasPermissionInManifest(Manifest.permission.WRITE_EXTERNAL_STORAGE))
permissionNames.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
else -> return null
}
return permissionNames
}
private fun hasPermissionInManifest(permission: String): Boolean {
try {
requestedPermissions?.let {
return it.any { r -> r.equals(permission, true) }
}
val context: Context? = registrar.activity() ?: registrar.activeContext()
if (context == null) {
Log.d(mLogTag, "Unable to detect current Activity or App Context.")
return false
}
val info: PackageInfo? = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
if (info == null) {
Log.d(mLogTag, "Unable to get Package info, will not be able to determine permissions to request.")
return false
}
requestedPermissions = info.requestedPermissions.toMutableList()
if (requestedPermissions == null) {
Log.d(mLogTag, "There are no requested permissions, please check to ensure you have marked permissions you want to request.")
return false
}
requestedPermissions?.let {
return it.any { r -> r.equals(permission, true) }
} ?: return false
} catch (ex: Exception) {
Log.d(mLogTag, "Unable to check manifest for permission: $ex")
}
return false
}
private fun isLocationServiceEnabled(context: Context): Boolean {
val locationMode: Int
val locationProviders: String
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
locationMode = Settings.Secure.getInt(context.contentResolver, Settings.Secure.LOCATION_MODE)
} catch (e: SettingNotFoundException) {
e.printStackTrace()
return false
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF
} else {
locationProviders = Settings.Secure.getString(context.contentResolver, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
return !TextUtils.isEmpty(locationProviders)
}
}
}
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
connection.project.dir=
eclipse.preferences.version=1
<?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 {
...@@ -48,10 +52,3 @@ android { ...@@ -48,10 +52,3 @@ 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" <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, <uses-permission android:name="android.permission.INTERNET" />
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"/>
<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" />
...@@ -29,32 +26,24 @@ ...@@ -29,32 +26,24 @@
<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.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)
}
}
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
#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
...@@ -8,17 +8,18 @@ ...@@ -8,17 +8,18 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
F83E7534C5D827024000AB4C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36F84C9A972D968241208A7F /* Pods_Runner.framework */; }; B7634AD7E1771AEDD2D1A5F7 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D132729FF349998420355A35 /* libPods-Runner.a */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
...@@ -39,21 +40,21 @@ ...@@ -39,21 +40,21 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
36F84C9A972D968241208A7F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; }; 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D132729FF349998420355A35 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
...@@ -63,17 +64,17 @@ ...@@ -63,17 +64,17 @@
files = ( files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
F83E7534C5D827024000AB4C /* Pods_Runner.framework in Frameworks */, B7634AD7E1771AEDD2D1A5F7 /* libPods-Runner.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
1850378EF7B1AE3FA40E4F87 /* Frameworks */ = { 55A8F50F97AFD5E34636A6AC /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
36F84C9A972D968241208A7F /* Pods_Runner.framework */, D132729FF349998420355A35 /* libPods-Runner.a */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -83,7 +84,6 @@ ...@@ -83,7 +84,6 @@
children = ( children = (
3B80C3931E831B6300D905FE /* App.framework */, 3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */, 9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
...@@ -98,8 +98,8 @@ ...@@ -98,8 +98,8 @@
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
A2B39E4F789ABF9C57736776 /* Pods */, EDB9D82C0C7AC839E456BFF1 /* Pods */,
1850378EF7B1AE3FA40E4F87 /* Frameworks */, 55A8F50F97AFD5E34636A6AC /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
...@@ -114,6 +114,8 @@ ...@@ -114,6 +114,8 @@
97C146F01CF9000F007C117D /* Runner */ = { 97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
...@@ -121,8 +123,6 @@ ...@@ -121,8 +123,6 @@
97C146F11CF9000F007C117D /* Supporting Files */, 97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
); );
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -130,11 +130,12 @@ ...@@ -130,11 +130,12 @@
97C146F11CF9000F007C117D /* Supporting Files */ = { 97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
97C146F21CF9000F007C117D /* main.m */,
); );
name = "Supporting Files"; name = "Supporting Files";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
A2B39E4F789ABF9C57736776 /* Pods */ = { EDB9D82C0C7AC839E456BFF1 /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
); );
...@@ -148,14 +149,14 @@ ...@@ -148,14 +149,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
E8ED1A28A9A0730EDF0565B2 /* [CP] Check Pods Manifest.lock */, CD618854C236B3F0FBC77F28 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
259652FD16940B446BA7C6C6 /* [CP] Embed Pods Frameworks */, 8BA3EF5BA9C129C83EB3F474 /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
...@@ -172,12 +173,12 @@ ...@@ -172,12 +173,12 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 0940; LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors"; ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0910; DevelopmentTeam = DKY2FBVP6L;
}; };
}; };
}; };
...@@ -206,7 +207,7 @@ ...@@ -206,7 +207,7 @@
files = ( files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
); );
...@@ -215,39 +216,41 @@ ...@@ -215,39 +216,41 @@
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
259652FD16940B446BA7C6C6 /* [CP] Embed Pods Frameworks */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios-release/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/permission_handler/permission_handler.framework",
); );
name = "[CP] Embed Pods Frameworks"; name = "Thin Binary";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/permission_handler.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
showEnvVarsInLog = 0;
}; };
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 8BA3EF5BA9C129C83EB3F474 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputFileListPaths = (
);
inputPaths = ( inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
); );
name = "Thin Binary";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
}; };
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
...@@ -263,16 +266,20 @@ ...@@ -263,16 +266,20 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
}; };
E8ED1A28A9A0730EDF0565B2 /* [CP] Check Pods Manifest.lock */ = { CD618854C236B3F0FBC77F28 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputFileListPaths = (
);
inputPaths = ( inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock", "${PODS_ROOT}/Manifest.lock",
); );
name = "[CP] Check Pods Manifest.lock"; name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = ( outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
); );
...@@ -288,7 +295,8 @@ ...@@ -288,7 +295,8 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
...@@ -315,6 +323,78 @@ ...@@ -315,6 +323,78 @@
/* End PBXVariantGroup section */ /* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = DKY2FBVP6L;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.permissionHandlerExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = { 97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
...@@ -329,14 +409,12 @@ ...@@ -329,14 +409,12 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES; CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
...@@ -367,7 +445,6 @@ ...@@ -367,7 +445,6 @@
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
name = Debug; name = Debug;
...@@ -386,14 +463,12 @@ ...@@ -386,14 +463,12 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES; CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
...@@ -417,8 +492,6 @@ ...@@ -417,8 +492,6 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
...@@ -429,8 +502,8 @@ ...@@ -429,8 +502,8 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = DKY2FBVP6L;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
...@@ -442,12 +515,8 @@ ...@@ -442,12 +515,8 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.baseflow.permissionHandlerExample; PRODUCT_BUNDLE_IDENTIFIER = com.example.permissionHandlerExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.2;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
name = Debug; name = Debug;
...@@ -457,8 +526,8 @@ ...@@ -457,8 +526,8 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = DKY2FBVP6L;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
...@@ -470,11 +539,8 @@ ...@@ -470,11 +539,8 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.baseflow.permissionHandlerExample; PRODUCT_BUNDLE_IDENTIFIER = com.example.permissionHandlerExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.2;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
name = Release; name = Release;
...@@ -487,6 +553,7 @@ ...@@ -487,6 +553,7 @@
buildConfigurations = ( buildConfigurations = (
97C147031CF9000F007C117D /* Debug */, 97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */, 97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
...@@ -496,6 +563,7 @@ ...@@ -496,6 +563,7 @@
buildConfigurations = ( buildConfigurations = (
97C147061CF9000F007C117D /* Debug */, 97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */, 97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
......
<?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 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>
......
#import "GeneratedPluginRegistrant.h"
\ No newline at end of file
...@@ -42,7 +42,8 @@ class MyApp extends StatelessWidget { ...@@ -42,7 +42,8 @@ class MyApp extends StatelessWidget {
PermissionWidget(permission)) PermissionWidget(permission))
.toList()), .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
.then((Map<PermissionGroup, PermissionStatus> permissionRequestResult) {
setState(() { setState(() {
print(permissionRequestResult);
_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.1.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:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true uses-material-design: true
\ No newline at end of file
# 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
#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.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"
}
//
// 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)
}
})
}
}
//
// 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)
}
})
}
}
//
// 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)
}
}
}
}
//
// 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
}
}
}
//
// 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
}
}
}
//
// 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)
}
//
// 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
}
}
}
//
// 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)
}
}
}
//
// 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
}
}
}
//
// 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)
}
}
//
// 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,20 +3,19 @@ ...@@ -3,20 +3,19 @@
# #
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 = '0.0.1'
s.summary = 'Permission plugin for Flutter.' s.summary = 'A new Flutter project.'
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 = 'http://example.com'
s.license = { :file => '../LICENSE' } s.license = { :file => '../LICENSE' }
s.author = { 'Baseflow' => 'hello@baseflow.com' } s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' } s.source = { :path => '.' }
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
part of permission_handler;
/// Defines the state of a permission group
enum PermissionStatus {
/// Permission to access the requested feature is denied by the user.
denied,
/// The feature is disabled (or not available) on the device.
disabled,
/// Permission to access the requested feature is granted by the user.
granted,
/// The user granted restricted access to the requested feature (only on iOS).
restricted,
/// Permission is in an unknown state
unknown
}
/// Defines the state of a service related to the permission group
enum ServiceStatus {
/// The unknown service status indicates the state of the service could not be determined.
unknown,
/// There is no service for the supplied permission group.
notApplicable,
/// The service for the supplied permission group is disabled.
disabled,
/// The service for the supplied permission group is enabled.
enabled
}
/// Defines the permission groups for which permissions can be checked or requested.
enum PermissionGroup {
/// The unknown permission only used for return type, never requested
unknown,
/// Android: Calendar
/// iOS: Calendar (Events)
calendar,
/// Android: Camera
/// iOS: Photos (Camera Roll and Camera)
camera,
/// Android: Contacts
/// iOS: AddressBook
contacts,
/// Android: Fine and Coarse Location
/// iOS: CoreLocation (Always and WhenInUse)
location,
/// Android: Microphone
/// iOS: Microphone
microphone,
/// Android: Phone
/// iOS: Nothing
phone,
/// Android: Nothing
/// iOS: Photos
photos,
/// Android: Nothing
/// iOS: Reminders
reminders,
/// Android: Body Sensors
/// iOS: CoreMotion
sensors,
/// Android: Sms
/// iOS: Nothing
sms,
/// Android: External Storage
/// iOS: Nothing
storage,
/// Android: Microphone
/// iOS: Speech
speech,
/// Android: Fine and Coarse Location
/// iOS: CoreLocation - Always
locationAlways,
/// Android: Fine and Coarse Location
/// iOS: CoreLocation - WhenInUse
locationWhenInUse,
/// Android: None
/// iOS: MPMediaLibrary
mediaLibrary
}
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;
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.1.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
meta: ^1.1.6 meta: ^1.1.6
# 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:
plugin: plugin:
androidPackage: com.baseflow.permissionhandler androidPackage: com.baseflow.permissionhandler.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