Commit f9f6781e by Sebastian Roth

Merge branch 'develop' into ignore-battery-android-m

parents 89b59280 fb752f41
# This is a basic workflow to help you get started with Actions
name: app_facing_package
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the develop branch
on:
push:
branches: [ master, develop ]
paths:
- 'permission_handler/**'
pull_request:
branches: [ master, develop ]
paths:
- 'permission_handler/**'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# Job configuration for the permission_handler (App Facing Package)
permission_handler:
# The type of runner that the job will run on
runs-on: macos-latest
env:
source-directory: ./permission_handler
example-directory: ./permission_handler/example
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# Make sure the stable version of Flutter is available
- uses: subosito/flutter-action@v1
with:
channel: 'beta'
# Download all Flutter packages the permission_handler depends on
- name: Download dependencies
run: flutter pub get
working-directory: ${{env.source-directory}}
# Run Flutter Format to ensure formatting is valid
- name: Run Flutter Format
run: flutter format --set-exit-if-changed lib
working-directory: ${{env.source-directory}}
# Run Flutter Analyzer
- name: Run Flutter Analyzer
run: flutter analyze
working-directory: ${{env.source-directory}}
# Build Android version of the example app
- name: Run Android build
run: flutter build apk --release
working-directory: ${{env.example-directory}}
# Build iOS version of the example app
- name: Run iOS build
run: flutter build ios --release --no-codesign
working-directory: ${{env.example-directory}}
# This is a basic workflow to help you get started with Actions
name: platform_interface_package
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the develop branch
on:
push:
branches: [ master, develop ]
paths:
- 'permission_handler_platform_interface/**'
pull_request:
branches: [ master, develop ]
paths:
- 'permission_handler_platform_interface/**'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# Job configuration for the permission_handler_platform_interface (Platform Interface Package)
permission_handler_platform_interface:
# The type of runner that the job will run on
runs-on: macos-latest
env:
source-directory: ./permission_handler_platform_interface
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# Make sure the stable version of Flutter is available
- uses: subosito/flutter-action@v1
with:
channel: 'beta'
# Download all Flutter packages the permission_handler_platform_interface depends on
- name: Download dependencies
run: flutter pub get
working-directory: ${{env.source-directory}}
# Run Flutter Format to ensure formatting is valid
- name: Run Flutter Format
run: flutter format --set-exit-if-changed lib
working-directory: ${{env.source-directory}}
# Run Flutter Analyzer
- name: Run Flutter Analyzer
run: flutter analyze
working-directory: ${{env.source-directory}}
[![pub package](https://img.shields.io/pub/v/permission_handler.svg)](https://pub.dartlang.org/packages/permission_handler) [![Build Status](https://app.bitrise.io/app/fa4f5d4bf452bcfb/status.svg?token=HorGpL_AOw2llYz39CjmdQ&branch=master)](https://app.bitrise.io/app/fa4f5d4bf452bcfb) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart)
[![pub package](https://img.shields.io/pub/v/permission_handler.svg)](https://pub.dartlang.org/packages/permission_handler) ![Build status](https://github.com/Baseflow/flutter-permission-handler/workflows/permission_handler/badge.svg?branch=master) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart)
On most operating systems, permissions aren't just granted to apps at install time.
Rather, developers have to ask the user for permissions while the app is running.
......@@ -40,7 +40,7 @@ android {
Add permissions to your `AndroidManifest.xml` file.
There's a `debug`, `main` and `profile` version which are chosen depending on how you start your app.
In general, it's sufficient to add permission only to the `main` version.
[Here](https://github.com/Baseflow/flutter-permission-handler/blob/develop/example/android/app/src/main/AndroidManifest.xml)'s an example `AndroidManifest.xml` with a complete list of all possible permissions.
[Here](https://github.com/Baseflow/flutter-permission-handler/blob/develop/permission_handler/example/android/app/src/main/AndroidManifest.xml)'s an example `AndroidManifest.xml` with a complete list of all possible permissions.
</details>
......@@ -199,7 +199,7 @@ Please file any issues, bugs or feature request as an issue on our [GitHub](http
## Want to contribute
If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](../CONTRIBUTING.md) and send us your [pull request](https://github.com/Baseflow/flutter-permission-handler/pulls).
If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](./CONTRIBUTING.md) and send us your [pull request](https://github.com/Baseflow/flutter-permission-handler/pulls).
## Author
......
# 5.0.1+1
## 6.0.0
* Migrated to null safety
## 5.1.0+2
* Solve mismatch with permission constants between Dart and Android (due to addition of permission on iOS);
* Fix compile error which occurred when on iOS the "PERMISSION_PHOTOS" macro is deactivated (meaning code dealing with the `PHPhotoLibrary` library is removed from the code base).
## 5.1.0+1
* Recreate the iOS part of the example project based on the Flutter stable channel (previous version was accidentally created with the Flutter beta channel).
## 5.1.0
* Added support for the limited photos permission available on iOS 14 and up;
* Fixed deprecated warning on iOS;
* Added support for the "READ_PHONE_NUMBERS" permission on Android;
* Fix a link to the contribution guide in the README.md.
## 5.0.1+2
* Pin dependency on permission_handler_platform_interface on version 2.0.1.
## 5.0.1+1
* Fixes Typo
* Issue #233 - on 5.0: Solved a bug that prevented Android applications running in the background to check the permission status.
# 5.0.1
## 5.0.1
* Update `permission_handler_platform_interface 2.0.1`
# 5.0.0+hotfix.10
## 5.0.0+hotfix.10
* Revert pull-request [#317](https://github.com/Baseflow/flutter-permission-handler/pull/317)
# 5.0.0+hotfix.9
## 5.0.0+hotfix.9
* Solved an issue where kCLAuthorizationStatusAuthorizedWhenInUse was returning PermissionStatusDenied (see [#317](https://github.com/Baseflow/flutter-permission-handler/pull/317))
......
......@@ -21,16 +21,17 @@ final class PermissionConstants {
static final int PERMISSION_GROUP_MICROPHONE = 7;
static final int PERMISSION_GROUP_PHONE = 8;
static final int PERMISSION_GROUP_PHOTOS = 9;
static final int PERMISSION_GROUP_REMINDERS = 10;
static final int PERMISSION_GROUP_SENSORS = 11;
static final int PERMISSION_GROUP_SMS = 12;
static final int PERMISSION_GROUP_SPEECH = 13;
static final int PERMISSION_GROUP_STORAGE = 14;
static final int PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS = 15;
static final int PERMISSION_GROUP_NOTIFICATION = 16;
static final int PERMISSION_GROUP_ACCESS_MEDIA_LOCATION = 17;
static final int PERMISSION_GROUP_ACTIVITY_RECOGNITION = 18;
static final int PERMISSION_GROUP_UNKNOWN = 19;
static final int PERMISSION_GROUP_PHOTOS_ADD_ONLY = 10;
static final int PERMISSION_GROUP_REMINDERS = 11;
static final int PERMISSION_GROUP_SENSORS = 12;
static final int PERMISSION_GROUP_SMS = 13;
static final int PERMISSION_GROUP_SPEECH = 14;
static final int PERMISSION_GROUP_STORAGE = 15;
static final int PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS = 16;
static final int PERMISSION_GROUP_NOTIFICATION = 17;
static final int PERMISSION_GROUP_ACCESS_MEDIA_LOCATION = 18;
static final int PERMISSION_GROUP_ACTIVITY_RECOGNITION = 19;
static final int PERMISSION_GROUP_UNKNOWN = 20;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
......@@ -63,7 +64,8 @@ final class PermissionConstants {
static final int PERMISSION_STATUS_GRANTED = 1;
static final int PERMISSION_STATUS_RESTRICTED = 2;
static final int PERMISSION_STATUS_NOT_DETERMINED = 3;
static final int PERMISSION_STATUS_NEVER_ASK_AGAIN = 4;
static final int PERMISSION_STATUS_LIMITED = 4;
static final int PERMISSION_STATUS_NEVER_ASK_AGAIN = 5;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
......@@ -71,7 +73,8 @@ final class PermissionConstants {
PERMISSION_STATUS_GRANTED,
PERMISSION_STATUS_RESTRICTED,
PERMISSION_STATUS_NOT_DETERMINED,
PERMISSION_STATUS_NEVER_ASK_AGAIN,
PERMISSION_STATUS_LIMITED,
PERMISSION_STATUS_NEVER_ASK_AGAIN,
})
@interface PermissionStatus {
}
......
......@@ -38,6 +38,7 @@ public class PermissionUtils {
case Manifest.permission.RECORD_AUDIO:
return PermissionConstants.PERMISSION_GROUP_MICROPHONE;
case Manifest.permission.READ_PHONE_STATE:
case Manifest.permission.READ_PHONE_NUMBERS:
case Manifest.permission.CALL_PHONE:
case Manifest.permission.READ_CALL_LOG:
case Manifest.permission.WRITE_CALL_LOG:
......@@ -118,6 +119,10 @@ public class PermissionUtils {
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_PHONE_STATE))
permissionNames.add(Manifest.permission.READ_PHONE_STATE);
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.Q && hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_PHONE_NUMBERS)) {
permissionNames.add(Manifest.permission.READ_PHONE_NUMBERS);
}
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.CALL_PHONE))
permissionNames.add(Manifest.permission.CALL_PHONE);
......
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.permissionhandlerexample">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
package com.example.example
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
......@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
......
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
# This is a generated file; do not edit or check into version control.
#
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.description = <<-DESC
Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
DESC
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.vendored_frameworks = 'Flutter.framework'
# Framework linking is handled by Flutter tooling, not CocoaPods.
# Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
s.vendored_frameworks = 'path/to/nothing'
end
......@@ -10,75 +10,75 @@ project 'Runner', {
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_key_values = {}
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
generated_key_values
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
target 'Runner' do
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter')
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
flutter_ios_podfile_setup
# Plugin Pods
target 'Runner' do
use_frameworks!
use_modular_headers!
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
# You can remove unused permissions here
# for more infomation: https://github.com/BaseflowIT/flutter-permission-handler/blob/develop/permission_handler/ios/Classes/PermissionHandlerEnums.h
# e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.calendar
# 'PERMISSION_EVENTS=0',
## dart: PermissionGroup.reminders
# 'PERMISSION_REMINDERS=0',
## dart: PermissionGroup.contacts
# 'PERMISSION_CONTACTS=0',
## dart: PermissionGroup.camera
# 'PERMISSION_CAMERA=0',
## dart: PermissionGroup.microphone
# 'PERMISSION_MICROPHONE=0',
## dart: PermissionGroup.speech
# 'PERMISSION_SPEECH_RECOGNIZER=0',
## dart: PermissionGroup.photos
#'PERMISSION_PHOTOS=0'
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
# 'PERMISSION_LOCATION=0',
## dart: PermissionGroup.notification
# 'PERMISSION_NOTIFICATIONS=0',
## dart: PermissionGroup.mediaLibrary
# 'PERMISSION_MEDIA_LIBRARY=0',
## dart: PermissionGroup.sensors
# 'PERMISSION_SENSORS=0'
]
end
end
end
......@@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
location = "self:">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1130"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
......@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
......@@ -11,7 +11,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>permission_handler_example</string>
<string>example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
......@@ -40,9 +40,9 @@
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<false/>
<!-- Permission options for the `location` group -->
<!-- Permission options for the `location` group -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Need location when in use</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array/>
</dict>
</plist>
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter/widgets.dart';
import 'template/globals.dart';
void main() {
runApp(BaseflowPluginExample());
}
void main() => runApp(MyApp());
/// A Flutter application demonstrating the functionality of this plugin
class BaseflowPluginExample extends StatelessWidget {
/// [MaterialColor] to be used in the app [ThemeData]
final MaterialColor themeMaterialColor =
createMaterialColor(const Color.fromRGBO(48, 49, 60, 1));
/// Example Flutter Application demonstrating the functionality of the
/// Permission Handler plugin.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.settings),
onPressed: () async {
var hasOpened = openAppSettings();
debugPrint('App Settings opened: ' + hasOpened.toString());
},
)
],
title: 'Baseflow $pluginName',
theme: ThemeData(
accentColor: Colors.white60,
backgroundColor: const Color.fromRGBO(48, 49, 60, 0.8),
buttonTheme: ButtonThemeData(
buttonColor: themeMaterialColor.shade500,
disabledColor: themeMaterialColor.withRed(200),
splashColor: themeMaterialColor.shade50,
textTheme: ButtonTextTheme.primary,
),
bottomAppBarColor: const Color.fromRGBO(57, 58, 71, 1),
hintColor: themeMaterialColor.shade500,
primarySwatch: createMaterialColor(const Color.fromRGBO(48, 49, 60, 1)),
textTheme: TextTheme(
bodyText1: TextStyle(
color: Colors.white,
fontSize: 16,
height: 1.3,
),
bodyText2: TextStyle(
color: Colors.white,
fontSize: 18,
height: 1.2,
),
button: TextStyle(color: Colors.white),
headline1: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
body: Center(
child: ListView(
children: Permission.values
.where((Permission permission) {
if (Platform.isIOS) {
return permission != Permission.unknown &&
permission != Permission.sms &&
//permission != Permission.storage &&
permission != Permission.ignoreBatteryOptimizations &&
permission != Permission.accessMediaLocation;
} else {
return permission != Permission.unknown &&
permission != Permission.mediaLibrary &&
permission != Permission.photos &&
permission != Permission.reminders;
}
})
.map((permission) => PermissionWidget(permission))
.toList()),
visualDensity: VisualDensity.adaptivePlatformDensity,
inputDecorationTheme: InputDecorationTheme(
fillColor: const Color.fromRGBO(37, 37, 37, 1),
filled: true,
),
),
home: AppHome(title: 'Baseflow $pluginName example app'),
);
}
}
/// Permission widget which displays a permission and allows users to request
/// the permissions.
class PermissionWidget extends StatefulWidget {
/// Constructs a [PermissionWidget] for the supplied [Permission].
const PermissionWidget(this._permission);
/// Creates a [MaterialColor] based on the supplied [Color]
static MaterialColor createMaterialColor(Color color) {
List strengths = <double>[.05];
Map swatch = <int, Color>{};
final r = color.red, g = color.green, b = color.blue;
final Permission _permission;
@override
_PermissionState createState() => _PermissionState(_permission);
for (var i = 1; i < 10; i++) {
strengths.add(0.1 * i);
}
for (var strength in strengths) {
final ds = 0.5 - strength;
swatch[(strength * 1000).round()] = Color.fromRGBO(
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
g + ((ds < 0 ? g : (255 - g)) * ds).round(),
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
1,
);
}
return MaterialColor(color.value, swatch as Map<int, Color>);
}
}
class _PermissionState extends State<PermissionWidget> {
_PermissionState(this._permission);
/// A Flutter example demonstrating how the [pluginName] plugin could be used
class AppHome extends StatefulWidget {
/// Constructs the [AppHome] class
AppHome({Key? key, this.title}) : super(key: key);
final Permission _permission;
PermissionStatus _permissionStatus = PermissionStatus.undetermined;
/// The [title] of the application, which is shown in the application's
/// title bar.
final String? title;
@override
void initState() {
super.initState();
_listenForPermissionStatus();
}
void _listenForPermissionStatus() async {
final status = await _permission.status;
setState(() => _permissionStatus = status);
}
_AppHomeState createState() => _AppHomeState();
}
Color getPermissionColor() {
switch (_permissionStatus) {
case PermissionStatus.denied:
return Colors.red;
case PermissionStatus.granted:
return Colors.green;
default:
return Colors.grey;
}
}
class _AppHomeState extends State<AppHome> {
static final PageController _pageController = PageController(initialPage: 0);
int _currentPage = 0;
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(_permission.toString()),
subtitle: Text(
_permissionStatus.toString(),
style: TextStyle(color: getPermissionColor()),
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).bottomAppBarColor,
title: Center(
child: Image.asset(
'res/images/baseflow_logo_def_light-02.png',
width: 140,
),
),
),
backgroundColor: Theme.of(context).backgroundColor,
body: PageView(
controller: _pageController,
children: pages,
onPageChanged: (page) {
setState(() {
_currentPage = page;
});
},
),
trailing: IconButton(
icon: const Icon(Icons.info),
onPressed: () {
checkServiceStatus(context, _permission);
}),
onTap: () {
requestPermission(_permission);
},
bottomNavigationBar: _bottomAppBar(),
);
}
void checkServiceStatus(BuildContext context, Permission permission) async {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text((await permission.status).toString()),
));
BottomAppBar _bottomAppBar() {
return BottomAppBar(
elevation: 5,
color: Theme.of(context).bottomAppBarColor,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.unmodifiable(() sync* {
for (var i = 0; i < pages.length; i++) {
yield Expanded(
child: IconButton(
iconSize: 30,
icon: Icon(icons.elementAt(i)),
color: _bottomAppBarIconColor(i),
onPressed: () => _animateToPage(i),
),
);
}
}()),
),
);
}
Future<void> requestPermission(Permission permission) async {
final status = await permission.request();
void _animateToPage(int page) {
_pageController.animateToPage(page,
duration: Duration(milliseconds: 200), curve: Curves.linear);
}
setState(() {
print(status);
_permissionStatus = status;
print(_permissionStatus);
});
Color _bottomAppBarIconColor(int page) {
return _currentPage == page ? Colors.white : Theme.of(context).accentColor;
}
}
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'permission_widget.dart';
/// Constructs a [ListView] containing [PermissionWidget] for each available
/// permission.
class PermissionList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: ListView(
children: Permission.values
.where((permission) {
if (Platform.isIOS) {
return permission != Permission.unknown &&
permission != Permission.sms &&
//permission != Permission.storage &&
permission != Permission.ignoreBatteryOptimizations &&
permission != Permission.accessMediaLocation;
} else {
return permission != Permission.unknown &&
permission != Permission.mediaLibrary &&
permission != Permission.photos &&
permission != Permission.reminders;
}
})
.map((permission) => PermissionWidget(permission))
.toList()),
);
}
}
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
/// Permission widget which displays a permission and allows users to request
/// the permissions.
class PermissionWidget extends StatefulWidget {
/// Constructs a [PermissionWidget] for the supplied [Permission].
const PermissionWidget(this._permission);
final Permission _permission;
@override
_PermissionState createState() => _PermissionState(_permission);
}
class _PermissionState extends State<PermissionWidget> {
_PermissionState(this._permission);
final Permission _permission;
PermissionStatus _permissionStatus = PermissionStatus.undetermined;
@override
void initState() {
super.initState();
_listenForPermissionStatus();
}
void _listenForPermissionStatus() async {
final status = await _permission.status;
setState(() => _permissionStatus = status);
}
Color getPermissionColor() {
switch (_permissionStatus) {
case PermissionStatus.denied:
return Colors.red;
case PermissionStatus.granted:
return Colors.green;
case PermissionStatus.limited:
return Colors.orange;
default:
return Colors.grey;
}
}
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(
_permission.toString(),
style: Theme.of(context).textTheme.bodyText1,
),
subtitle: Text(
_permissionStatus.toString(),
style: TextStyle(color: getPermissionColor()),
),
trailing: IconButton(
icon: const Icon(
Icons.info,
color: Colors.white,
),
onPressed: () {
checkServiceStatus(context, _permission);
}),
onTap: () {
requestPermission(_permission);
},
);
}
void checkServiceStatus(BuildContext context, Permission permission) async {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text((await permission.status).toString()),
));
}
Future<void> requestPermission(Permission permission) async {
final status = await permission.request();
setState(() {
print(status);
_permissionStatus = status;
print(_permissionStatus);
});
}
}
import 'dart:core';
import 'package:flutter/material.dart';
import '../plugin_example/permission_list.dart';
import 'info_page.dart';
/// The name of the plugin, which will be displayed throughout the example App.
const String pluginName = 'Permission Handler';
/// Returns Github URL, which is shown in the [InfoPage].
const String githubURL =
'https://github.com/Baseflow/flutter-permission-handler';
/// Returns Baseflow URL, which is shown in the [InfoPage].
const String baseflowURL = 'https://baseflow.com';
/// Returns pub.dev URL, which is shown in the [InfoPage].
const String pubDevURL = 'https://pub.dev/packages/permission_handler';
/// [EdgeInsets] to define horizontal padding throughout the application.
const EdgeInsets defaultHorizontalPadding =
EdgeInsets.symmetric(horizontal: 24);
/// [EdgeInsets] to define vertical padding throughout the application.
const EdgeInsets defaultVerticalPadding = EdgeInsets.symmetric(vertical: 24);
/// Returns a [List] with [IconData] to show in the [AppHome] [AppBar].
final List<IconData> icons = [
Icons.list,
Icons.info_outline,
];
/// Returns a [List] with [Widget]s to construct pages in the [AppBar].
final List<Widget> pages = [
PermissionList(),
InfoPage(),
];
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:url_launcher/url_launcher.dart';
import 'globals.dart';
/// [StatelessWidget] displaying information about Baseflow
class InfoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedBox.expand(
child: Align(
alignment: Alignment.bottomCenter,
child: SingleChildScrollView(
child: Padding(
padding: defaultHorizontalPadding + defaultVerticalPadding,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Image.asset(
'res/images/poweredByBaseflowLogoLight@3x.png',
width: 250,
alignment: Alignment.centerLeft,
),
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 24),
),
Text(
'This app showcases the possibilities of the $pluginName '
'plugin, powered by Baseflow. '
'This plugin is available as open source project on Github. '
'\n\n'
'Need help with integrating functionalities within your own '
'apps? Contact us at hello@baseflow.com',
style: Theme.of(context).textTheme.bodyText1,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
),
_launcherRaisedButton(
'Find us on Github',
githubURL,
context,
),
_launcherRaisedButton(
'Find us on pub.dev',
pubDevURL,
context,
),
_launcherRaisedButton(
'Visit baseflow.com',
baseflowURL,
context,
),
const Padding(
padding: EdgeInsets.only(bottom: 30),
),
],
),
),
),
),
);
}
Widget _launcherRaisedButton(String text, String url, BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: 50,
margin: const EdgeInsets.only(top: 24.0),
alignment: Alignment.center,
child: SizedBox.expand(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
),
child: Text(text),
onPressed: () => _launchURL(url),
),
),
);
}
Future<void> _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
}
......@@ -2,7 +2,7 @@ name: permission_handler_example
description: Demonstrates how to use the permission_handler plugin.
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.12.0-259.9.beta <3.0.0"
dependencies:
flutter:
......@@ -15,5 +15,12 @@ dev_dependencies:
permission_handler:
path: ../
url_launcher: ^6.0.0
flutter:
uses-material-design: true
assets:
- res/images/baseflow_logo_def_light-02.png
- res/images/poweredByBaseflowLogoLight@3x.png
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
......@@ -54,6 +54,13 @@
#define PERMISSION_PHOTOS 1
#endif
// ios: PermissionGroupPhotosAddOnly
// Info.plist: NSPhotoLibraryUsageDescription
// dart: PermissionGroup.photosAddOnly
#ifndef PERMISSION_PHOTOS_ADD_ONLY
#define PERMISSION_PHOTOS_ADD_ONLY 1
#endif
// ios: [PermissionGroupLocation, PermissionGroupLocationAlways, PermissionGroupLocationWhenInUse]
// Info.plist: [NSLocationUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription, NSLocationWhenInUseUsageDescription]
// dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
......@@ -92,6 +99,7 @@ typedef NS_ENUM(int, PermissionGroup) {
PermissionGroupMicrophone,
PermissionGroupPhone,
PermissionGroupPhotos,
PermissionGroupPhotosAddOnly,
PermissionGroupReminders,
PermissionGroupSensors,
PermissionGroupSms,
......@@ -108,6 +116,7 @@ typedef NS_ENUM(int, PermissionStatus) {
PermissionStatusGranted,
PermissionStatusRestricted,
PermissionStatusNotDetermined,
PermissionStatusLimited,
};
typedef NS_ENUM(int, ServiceStatus) {
......
......@@ -32,13 +32,19 @@
}
- (void)requestPermissions:(NSArray *)permissions completion:(PermissionRequestCompletion)completion {
NSMutableSet *requestQueue = [[NSMutableSet alloc] initWithArray:permissions];
NSMutableDictionary *permissionStatusResult = [[NSMutableDictionary alloc] init];
if (permissions.count == 0) {
completion(permissionStatusResult);
return;
}
NSMutableSet *requestQueue = [[NSMutableSet alloc] initWithArray:permissions];
for (int i = 0; i < permissions.count; ++i) {
PermissionGroup value;
[permissions[i] getValue:&value];
PermissionGroup permission = value;
NSNumber *rawNumberValue = permissions[i];
int rawValue = rawNumberValue.intValue;
PermissionGroup permission = (PermissionGroup) rawValue;
id <PermissionStrategy> permissionStrategy = [PermissionManager createPermissionStrategy:permission];
[_strategyInstances addObject:permissionStrategy];
......@@ -96,7 +102,17 @@
case PermissionGroupPhone:
return [PhonePermissionStrategy new];
case PermissionGroupPhotos:
#if PERMISSION_PHOTOS
return [[PhotoPermissionStrategy alloc] initWithAccessAddOnly:false];
#else
return [PhotoPermissionStrategy new];
#endif
case PermissionGroupPhotosAddOnly:
#if PERMISSION_PHOTOS
return [[PhotoPermissionStrategy alloc] initWithAccessAddOnly:true];
#else
return [PhotoPermissionStrategy new];
#endif
case PermissionGroupReminders:
return [EventPermissionStrategy new];
case PermissionGroupSensors:
......
......@@ -11,6 +11,7 @@
#import <Photos/Photos.h>
@interface PhotoPermissionStrategy : NSObject <PermissionStrategy>
-(instancetype)initWithAccessAddOnly:(BOOL) addOnly;
@end
#else
......
......@@ -7,9 +7,21 @@
#if PERMISSION_PHOTOS
@implementation PhotoPermissionStrategy
@implementation PhotoPermissionStrategy{
bool addOnlyAccessLevel;
}
- (instancetype)initWithAccessAddOnly:(BOOL)addOnly {
self = [super init];
if(self) {
addOnlyAccessLevel = addOnly;
}
return self;
}
- (PermissionStatus)checkPermissionStatus:(PermissionGroup)permission {
return [PhotoPermissionStrategy permissionStatus];
return [PhotoPermissionStrategy permissionStatus:addOnlyAccessLevel];
}
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
......@@ -24,13 +36,24 @@
return;
}
if(@available(iOS 14, *)) {
[PHPhotoLibrary requestAuthorizationForAccessLevel:(addOnlyAccessLevel)?PHAccessLevelAddOnly:PHAccessLevelReadWrite handler:^(PHAuthorizationStatus authorizationStatus) {
completionHandler([PhotoPermissionStrategy determinePermissionStatus:authorizationStatus]);
}];
}else {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus authorizationStatus) {
completionHandler([PhotoPermissionStrategy determinePermissionStatus:authorizationStatus]);
}];
}
}
+ (PermissionStatus)permissionStatus {
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
+ (PermissionStatus)permissionStatus:(BOOL) addOnlyAccessLevel {
PHAuthorizationStatus status;
if(@available(iOS 14, *)){
status = [PHPhotoLibrary authorizationStatusForAccessLevel:(addOnlyAccessLevel)?PHAccessLevelAddOnly:PHAccessLevelReadWrite];
}else {
status = [PHPhotoLibrary authorizationStatus];
}
return [PhotoPermissionStrategy determinePermissionStatus:status];
}
......@@ -45,6 +68,8 @@
return PermissionStatusDenied;
case PHAuthorizationStatusAuthorized:
return PermissionStatusGranted;
case PHAuthorizationStatusLimited:
return PermissionStatusLimited;
}
return PermissionStatusNotDetermined;
......
......@@ -3,7 +3,7 @@
#
Pod::Spec.new do |s|
s.name = 'permission_handler'
s.version = '5.0.1+1'
s.version = '5.1.0+2'
s.summary = 'Permission plugin for Flutter.'
s.description = <<-DESC
Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
......
......@@ -23,8 +23,8 @@ Future<bool> openAppSettings() => _handler.openAppSettings();
/// Actions that can be executed on a permission.
extension PermissionActions on Permission {
/// The current status of this permission.
///
/// The Android-only [PermissionStatus.permanentlyDenied] status will only be
///
/// The Android-only [PermissionStatus.permanentlyDenied] status will only be
/// calculated if the active context is an Activity. If it isn't,
/// [PermissionStatus.denied] will be returned.
Future<PermissionStatus> get status => _handler.checkPermissionStatus(this);
......@@ -46,7 +46,8 @@ extension PermissionActions on Permission {
///
/// Returns the new [PermissionStatus].
Future<PermissionStatus> request() async {
return (await [this].request())[this];
final permissionStatus = (await [this].request())[this];
return permissionStatus ?? PermissionStatus.denied;
}
}
......@@ -67,6 +68,10 @@ extension PermissionCheckShortcuts on Permission {
/// *Only supported on iOS.*
Future<bool> get isRestricted => status.isRestricted;
///User has authorized this application for limited photo library access.
/// *Only supported on iOS.(iOS14+)*
Future<bool> get isLimited => status.isLimited;
/// If the user denied this permission and selected to never again show a
/// request for it. The user may still change the permission's status in the
/// device settings.
......
name: permission_handler
description: Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
version: 5.0.1+1
version: 6.0.0
homepage: https://github.com/baseflowit/flutter-permission-handler
flutter:
......@@ -15,13 +15,13 @@ flutter:
dependencies:
flutter:
sdk: flutter
meta: ^1.1.6
permission_handler_platform_interface: ^2.0.1
meta: ^1.3.0
permission_handler_platform_interface: ^3.0.0
dev_dependencies:
effective_dart: ^1.2.1
plugin_platform_interface: ^1.0.1
effective_dart: ^1.3.0
plugin_platform_interface: ^2.0.0
environment:
sdk: ">=2.7.0 <3.0.0"
sdk: ">=2.12.0-259.9.beta <3.0.0"
flutter: ">=1.12.8 <2.0.0"
## 3.0.0+1
* **BREAKING**: Removed PermissionStatus.undetermined. This is now replaced by PermissionStatus.denied.
## 3.0.0
* Migrated to null safety.
## 2.0.2
* Added support for the limited photos permission available on iOS 14 and up.
## 2.0.1
* Update `platform_interface 1.0.2`
......
# permission_handler_platform_interface
[![pub package](https://img.shields.io/pub/v/permission_handler_platform_interface.svg)](https://pub.dartlang.org/packages/permission_handler_platform_interface) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart)
[![pub package](https://img.shields.io/pub/v/permission_handler_platform_interface.svg)](https://pub.dartlang.org/packages/permission_handler_platform_interface) ![Build status](https://github.com/Baseflow/flutter-permission-handler/workflows/platform_interface_package/badge.svg?branch=master) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart)
A common platform interface for the [`permission_handler`][1] plugin.
......
......@@ -52,7 +52,8 @@ class MethodChannelPermissionHandler extends PermissionHandlerPlatform {
/// [false].
Future<bool> openAppSettings() async {
final wasOpened = await _methodChannel.invokeMethod('openAppSettings');
return wasOpened;
return wasOpened ?? false;
}
/// Requests the user for access to the supplied list of [Permission]s, if
......@@ -77,6 +78,6 @@ class MethodChannelPermissionHandler extends PermissionHandlerPlatform {
final shouldShowRationale = await _methodChannel.invokeMethod(
'shouldShowRequestPermissionRationale', permission.value);
return shouldShowRationale;
return shouldShowRationale ?? false;
}
}
......@@ -2,9 +2,6 @@ part of permission_handler_platform_interface;
/// Defines the state of a [Permission].
enum PermissionStatus {
/// The permission wasn't requested yet.
undetermined,
/// The user granted access to the requested feature.
granted,
......@@ -17,6 +14,10 @@ enum PermissionStatus {
/// *Only supported on iOS.*
restricted,
///User has authorized this application for limited access.
/// *Only supported on iOS (iOS14+).*
limited,
/// The user denied access to the requested feature and selected to never
/// again show a request for this permission. The user may still change the
/// permission status in the settings.
......@@ -33,9 +34,11 @@ extension PermissionStatusValue on PermissionStatus {
return 1;
case PermissionStatus.restricted:
return 2;
case PermissionStatus.undetermined:
case PermissionStatus.denied:
return 3;
case PermissionStatus.permanentlyDenied:
return 5;
case PermissionStatus.limited:
return 4;
default:
throw UnimplementedError();
......@@ -47,16 +50,13 @@ extension PermissionStatusValue on PermissionStatus {
PermissionStatus.denied,
PermissionStatus.granted,
PermissionStatus.restricted,
PermissionStatus.undetermined,
PermissionStatus.limited,
PermissionStatus.permanentlyDenied,
][value];
}
}
extension PermissionStatusGetters on PermissionStatus {
/// If the permission was never requested before.
bool get isUndetermined => this == PermissionStatus.undetermined;
/// If the user granted access to the requested feature.
bool get isGranted => this == PermissionStatus.granted;
......@@ -74,12 +74,11 @@ extension PermissionStatusGetters on PermissionStatus {
/// permission status in the settings.
/// *Only supported on Android.*
bool get isPermanentlyDenied => this == PermissionStatus.permanentlyDenied;
bool get isLimited => this == PermissionStatus.limited;
}
extension FuturePermissionStatusGetters on Future<PermissionStatus> {
/// If the permission was never requested before.
Future<bool> get isUndetermined async => (await this).isUndetermined;
/// If the user granted access to the requested feature.
Future<bool> get isGranted async => (await this).isGranted;
......@@ -98,4 +97,6 @@ extension FuturePermissionStatusGetters on Future<PermissionStatus> {
/// *Only supported on Android.*
Future<bool> get isPermanentlyDenied async =>
(await this).isPermanentlyDenied;
Future<bool> get isLimited async => (await this).isLimited;
}
......@@ -55,47 +55,53 @@ class Permission {
/// Android: Nothing
/// iOS: Photos
/// iOS 14+ read & write access level
static const photos = Permission._(9);
/// Android: Nothing
/// iOS: Photos
/// iOS 14+ read & write access level
static const photosAddOnly = Permission._(10);
/// Android: Nothing
/// iOS: Reminders
static const reminders = Permission._(10);
static const reminders = Permission._(11);
/// Android: Body Sensors
/// iOS: CoreMotion
static const sensors = Permission._(11);
static const sensors = Permission._(12);
/// Android: Sms
/// iOS: Nothing
static const sms = Permission._(12);
static const sms = Permission._(13);
/// Android: Microphone
/// iOS: Speech
static const speech = Permission._(13);
static const speech = Permission._(14);
/// Android: External Storage
/// iOS: Access to folders like `Documents` or `Downloads`. Implicitly
/// granted.
static const storage = Permission._(14);
static const storage = Permission._(15);
/// Android: Ignore Battery Optimizations
static const ignoreBatteryOptimizations = Permission._(15);
static const ignoreBatteryOptimizations = Permission._(16);
/// Android: Notification
/// iOS: Notification
static const notification = Permission._(16);
static const notification = Permission._(17);
/// Android: Allows an application to access any geographic locations
/// persisted in the user's shared collection.
static const accessMediaLocation = Permission._(17);
static const accessMediaLocation = Permission._(18);
/// When running on Android Q and above: Activity Recognition
/// When running on Android < Q: Nothing
/// iOS: Nothing
static const activityRecognition = Permission._(18);
static const activityRecognition = Permission._(19);
/// The unknown only used for return type, never requested
static const unknown = Permission._(19);
static const unknown = Permission._(20);
/// Returns a list of all possible [PermissionGroup] values.
static const List<Permission> values = <Permission>[
......@@ -109,6 +115,7 @@ class Permission {
microphone,
phone,
photos,
photosAddOnly,
reminders,
sensors,
sms,
......@@ -132,6 +139,7 @@ class Permission {
'microphone',
'phone',
'photos',
'photosAddOnly',
'reminders',
'sensors',
'sms',
......
......@@ -3,20 +3,20 @@ description: A common platform interface for the permission_handler plugin.
homepage: https://github.com/baseflow/flutter-permission-handler/tree/master/permission_handler_platform_interface
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
version: 2.0.1
version: 3.0.0+1
dependencies:
flutter:
sdk: flutter
meta: ^1.0.5
plugin_platform_interface: ^1.0.2
plugin_platform_interface: ^2.0.0
dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^4.1.1
effective_dart: ^1.2.1
mockito: ^5.0.0
effective_dart: ^1.3.0
environment:
sdk: ">=2.6.0 <3.0.0"
flutter: ">=1.9.1+hotfix.4 <2.0.0"
sdk: ">=2.12.0-259.9.beta <3.0.0"
flutter: ">=1.22.0"
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