Closed WXXXXH closed 3 years ago
Hi @WXXXXH,
Thank you for reporting this bug, I have been looking into it but I cannot reproduce it unfortunately. We did have a bug throwing the EXC_BAD_ACCESS
exception in version 8.1.4 and fixed it in version 8.1.4+1. I wanted to ask you if you could double check if you are really on version 8.1.4+1 and if you could make sure by running flutter clean
followed by a flutter pub upgrade
. I would really appreciate it if you could give this a try and let us know if you are still experiencing the error.
A few other remarks on your code:
Permission.location
is a place holder for the Permission.locationWhenInUse
and Permission.locationAlways
permissions. The permission_handler will determine which of the two permissions is the most appropriate to request. Requesting all three permissions (as you are doing in the checkAndRequestLocationPermission
results into a deadlock on iOS and renders the permission_handler unusable;statuses
to check the permission status, there is no need to use the await Permission.storage.status
property (which makes another call into native code which might costs some extra performance). Meaning you can rewrite your code to this:static checkAndRequestLocationPermission() async {
PermissionStatus status = await Permission.location.request();
if (status != PermissionStatus.granted) {
openAppSettings();
return;
}
}
static checkAndRequestPhotoPermission() {
Map<Permission, PermissionStatus> statuses = await [
Permission.photos,
Permission.storage,
Permission.photosAddOnly,
].request();
if (statuses[Permission.photos] != PermissionStatus.granted ||
statuses[Permission.storage] != PermissionStatus.granted ||
statuses[Permission.photosAddOnly] != PermissionStatus.granted) {
openAppSettings();
return;
}
}
P.S. below is the code I used to try and reproduce the error. I have simply created a new Flutter App and modified the code as follows:
pubspec.yaml
:
name: permission_issue_638
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
permission_handler: ^8.1.4+1
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
ios/Podfile
to enable the permissions needed:
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
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
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
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|
# You can remove unused permissions here
# for more infomation: https://github.com/BaseflowIT/flutter-permission-handler/blob/master/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=1',
## dart: PermissionGroup.reminders
'PERMISSION_REMINDERS=1',
## dart: PermissionGroup.contacts
'PERMISSION_CONTACTS=1',
## dart: PermissionGroup.camera
'PERMISSION_CAMERA=1',
## dart: PermissionGroup.microphone
'PERMISSION_MICROPHONE=1',
## dart: PermissionGroup.speech
'PERMISSION_SPEECH_RECOGNIZER=1',
## dart: PermissionGroup.photos
'PERMISSION_PHOTOS=1',
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
'PERMISSION_LOCATION=1',
## dart: PermissionGroup.notification
'PERMISSION_NOTIFICATIONS=1',
## dart: PermissionGroup.mediaLibrary
'PERMISSION_MEDIA_LIBRARY=1',
## dart: PermissionGroup.sensors
'PERMISSION_SENSORS=1',
## dart: PermissionGroup.bluetooth
'PERMISSION_BLUETOOTH=1',
## dart: PermissionGroup.appTrackingTransparency
'PERMISSION_APP_TRACKING_TRANSPARENCY=1',
## dart: PermissionGroup.criticalAlerts
'PERMISSION_CRITICAL_ALERTS=1',
]
end
end
end
ios/Runner/Info.plist
file:
<?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>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>permission_issue_638</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<!-- Permission options for the `location` group -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Need location when in use</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Always and when in use!</string>
<key>NSLocationUsageDescription</key>
<string>Older devices need location.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Can I have location always?</string>
<!-- Permission options for the `mediaLibrary` group -->
<key>NSAppleMusicUsageDescription</key>
<string>Music!</string>
<key>kTCCServiceMediaLibrary</key>
<string>media</string>
<!-- Permission options for the `calendar` group -->
<key>NSCalendarsUsageDescription</key>
<string>Calendars</string>
<!-- Permission options for the `camera` group -->
<key>NSCameraUsageDescription</key>
<string>camera</string>
<!-- Permission options for the `contacts` group -->
<key>NSContactsUsageDescription</key>
<string>contacts</string>
<!-- Permission options for the `microphone` group -->
<key>NSMicrophoneUsageDescription</key>
<string>microphone</string>
<!-- Permission options for the `speech` group -->
<key>NSSpeechRecognitionUsageDescription</key>
<string>speech</string>
<!-- Permission options for the `sensors` group -->
<key>NSMotionUsageDescription</key>
<string>motion</string>
<!-- Permission options for the `photos` group -->
<key>NSPhotoLibraryUsageDescription</key>
<string>photos</string>
<!-- Permission options for the `reminder` group -->
<key>NSRemindersUsageDescription</key>
<string>reminders</string>
<!-- Permission options for the `bluetooth` -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>bluetooth</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>bluetooth</string>
<!-- Permission options for the `appTrackingTransparency` -->
<key>NSUserTrackingUsageDescription</key>
<string>appTrackingTransparency</string>
</dict>
</plist>
main.dart
with the following code (matching your code samples):
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _requestLocationPermissions() async {
Map<Permission, PermissionStatus> statusses = await [
Permission.location,
Permission.locationAlways,
Permission.locationWhenInUse,
].request();
if (await Permission.location.status != PermissionStatus.granted ||
await Permission.locationAlways.status != PermissionStatus.granted ||
await Permission.locationWhenInUse.status != PermissionStatus.granted) {
print('Permissions are denied');
}
}
void _requestPhotoPermissions() async {
Map<Permission, PermissionStatus> statusses = await [
Permission.photos,
Permission.storage,
Permission.photosAddOnly,
].request();
if (await Permission.photos.status != PermissionStatus.granted ||
await Permission.storage.status != PermissionStatus.granted ||
await Permission.photosAddOnly.status != PermissionStatus.granted) {
print('Permissions are denied');
}
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: [
FloatingActionButton(
onPressed: _requestLocationPermissions,
tooltip: 'Location permissions',
child: Icon(Icons.location_on),
),
SizedBox(
height: 10,
),
FloatingActionButton(
onPressed: _requestPhotoPermissions,
tooltip: 'Photo permissions',
child: Icon(Icons.photo),
),
],
),
);
}
}
Hi @WXXXXH,
Thank you for reporting this bug, I have been looking into it but I cannot reproduce it unfortunately. We did have a bug throwing the
EXC_BAD_ACCESS
exception in version 8.1.4 and fixed it in version 8.1.4+1. I wanted to ask you if you could double check if you are really on version 8.1.4+1 and if you could make sure by runningflutter clean
followed by aflutter pub upgrade
. I would really appreciate it if you could give this a try and let us know if you are still experiencing the error.A few other remarks on your code:
- For requesting the location permissions you should not request all three permissions at the same time. The
Permission.location
is a place holder for thePermission.locationWhenInUse
andPermission.locationAlways
permissions. The permission_handler will determine which of the two permissions is the most appropriate to request. Requesting all three permissions (as you are doing in thecheckAndRequestLocationPermission
results into a deadlock on iOS and renders the permission_handler unusable;- After you request the permissions you can use the result
statuses
to check the permission status, there is no need to use theawait Permission.storage.status
property (which makes another call into native code which might costs some extra performance). Meaning you can rewrite your code to this:static checkAndRequestLocationPermission() async { PermissionStatus status = await Permission.location.request(); if (status != PermissionStatus.granted) { openAppSettings(); return; } } static checkAndRequestPhotoPermission() { Map<Permission, PermissionStatus> statuses = await [ Permission.photos, Permission.storage, Permission.photosAddOnly, ].request(); if (statuses[Permission.photos] != PermissionStatus.granted || statuses[Permission.storage] != PermissionStatus.granted || statuses[Permission.photosAddOnly] != PermissionStatus.granted) { openAppSettings(); return; } }
P.S. below is the code I used to try and reproduce the error. I have simply created a new Flutter App and modified the code as follows:
- Added the dependency to my
pubspec.yaml
:pubspec.yaml
- Updated the
ios/Podfile
to enable the permissions needed:Podfile
- Added the necessary permissions to the
ios/Runner/Info.plist
file:Info.plist
- Updated the
main.dart
with the following code (matching your code samples):main.dart
import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( // This is the theme of your application. // // Try running your application with "flutter run". You'll see the // application has a blue toolbar. Then, without quitting the app, try // changing the primarySwatch below to Colors.green and then invoke // "hot reload" (press "r" in the console where you ran "flutter run", // or simply save your changes to "hot reload" in a Flutter IDE). // Notice that the counter didn't reset back to zero; the application // is not restarted. primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key? key, required this.title}) : super(key: key); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect // how it looks. // This class is the configuration for the state. It holds the values (in this // case the title) provided by the parent (in this case the App widget) and // used by the build method of the State. Fields in a Widget subclass are // always marked "final". final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { void _requestLocationPermissions() async { Map<Permission, PermissionStatus> statusses = await [ Permission.location, Permission.locationAlways, Permission.locationWhenInUse, ].request(); if (await Permission.location.status != PermissionStatus.granted || await Permission.locationAlways.status != PermissionStatus.granted || await Permission.locationWhenInUse.status != PermissionStatus.granted) { print('Permissions are denied'); } } void _requestPhotoPermissions() async { Map<Permission, PermissionStatus> statusses = await [ Permission.photos, Permission.storage, Permission.photosAddOnly, ].request(); if (await Permission.photos.status != PermissionStatus.granted || await Permission.storage.status != PermissionStatus.granted || await Permission.photosAddOnly.status != PermissionStatus.granted) { print('Permissions are denied'); } } @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done // by the _incrementCounter method above. // // The Flutter framework has been optimized to make rerunning build methods // fast, so that you can just rebuild anything that needs updating rather // than having to individually change instances of widgets. return Scaffold( appBar: AppBar( // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.max, children: [ FloatingActionButton( onPressed: _requestLocationPermissions, tooltip: 'Location permissions', child: Icon(Icons.location_on), ), SizedBox( height: 10, ), FloatingActionButton( onPressed: _requestPhotoPermissions, tooltip: 'Photo permissions', child: Icon(Icons.photo), ), ], ), ); } }
![]()
And iOS 12.2 ,iOS 14 is OK
@WXXXXH thank you for the additional information on the iOS version. I can indeed reproduce the problem on iOS 12.2. I will be looking into this and try to find a solution.
Hi @WXXXXH,
I have just published a new hotfix release (version 8.1.4+2) which should fix this issue (see also PR #640). Thank you for pointing it out and supplying all information needed to reproduce the bug.
Hi @WXXXXH,
I have just published a new hotfix release (version 8.1.4+2) which should fix this issue (see also PR #640). Thank you for pointing it out and supplying all information needed to reproduce the bug.
thanks ,is OK
🐛 Bug Report
After denying permission, carsh(location 、 photo、storage )
Version: 8.1.4+1
Platform: