如何在 Flutter 中请求和检查权限
Posted
技术标签:
【中文标题】如何在 Flutter 中请求和检查权限【英文标题】:How to request and check permissions in Flutter 【发布时间】:2021-02-15 03:24:01 【问题描述】:当用户单击不允许时,我正在使用各种插件来获取用户数据、联系人、照片和相机,应用程序会静默。 当用户选中“不再询问”和“不允许”并再次进入应用程序时,我想向用户显示“询问权限”对话框。
目前,当用户选中“不允许”时,该应用不会再次询问
我知道用户必须授予应用访问个人信息的权限,包括当前位置、相机、日历、联系人、媒体库、麦克风、传感器、语音和照片。尽管人们喜欢使用可以访问这些信息的应用程序的便利性,但他们也希望能够控制他们的私人数据。例如,人们喜欢能够自动用他们的实际位置标记照片或找到附近的朋友,但他们也希望能够选择禁用这些功能。
flutter中如何再次请求用户权限?
【问题讨论】:
【参考方案1】:我对这个问题非常困扰在应用了几个解决方案后,我找到了这个解决方案。所以我想和大家分享一下,所以我问了这个问题,我回答了
在大多数操作系统上,权限不仅仅在安装时授予应用程序。相反,开发人员必须在应用运行时向用户请求权限。
处理权限的最佳方式是使用permission_handler 插入。此插件提供跨平台(ios、android)API 来请求权限并检查其状态。
我们还可以打开设备的应用设置,以便用户授予权限。 在 Android 上,我们可以展示请求权限的理由。
将此添加到您的包的pubspec.yaml
文件中:
dependencies:
permission_handler: ^5.0.1+1
现在在你的 Dart 代码中,你可以使用:
import 'package:permission_handler/permission_handler.dart';
虽然在运行时请求权限,但您仍需要告诉操作系统您的应用可能使用哪些权限。这需要向特定于 Android 和 iOS 的文件添加权限配置。
iOS
为您的 Info.plist 文件添加权限。 Here 是一个示例 Info.plist,其中包含所有可能权限的完整列表。重要提示:当您想提交您的应用程序时,您必须包含所有权限选项。这是因为permission_handler
插件涉及所有不同的 SDK,并且静态代码分析器(由 Apple 在应用程序提交时运行)检测到这一点,如果在 Info.plist
中找不到匹配的权限选项,它将断言。更多相关信息请见here。
将以下内容添加到您的 Podfile
文件中:
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['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
删除您确实要使用的权限前面的#
字符。例如,如果您确实需要访问日历,请确保代码如下所示:
## dart: PermissionGroup.calendar
'PERMISSION_EVENTS=0',
安卓
将以下内容添加到您的“gradle.properties
”文件中:
android.useAndroidX=true
android.enableJetifier=true
确保将“android/app/build.gradle
”文件中的compileSdkVersion
设置为28:
android
compileSdkVersion 30
...
确保替换所有的 android。对其 AndroidX 对应项的依赖项(完整列表可在此处找到:https://developer.android.com/jetpack/androidx/migrate)
为您的AndroidManifest.xml
文件添加权限。有debug
、main
和profile
版本可供选择,具体取决于您启动应用的方式。通常,仅向main
版本添加权限就足够了。这是一个示例 AndroidManifest.xml
,其中包含所有可能权限的完整列表。
终于可以这样使用了
有许多权限。您可以获得Permission
的status
,即granted
、denied
、restricted
或permanentlyDenied
。
var status = await Permission.photos.status;
if (status.isDenied)
// We didn't ask for permission yet.
// You can can also directly ask the permission about its status.
if (await Permission.location.isRestricted)
// The OS restricts access, for example because of parental controls.
Call `request()` on a `Permission` to request it. If it has already been granted before, nothing happens.
request()
返回Permission
的新状态。
if (await Permission.contacts.request().isGranted)
// Either the permission was already granted before or the user just granted it.
// You can request multiple permissions at once.
Map<Permission, PermissionStatus> statuses = await [
Permission.location,
Permission.storage,
].request();
print(statuses[Permission.location]);
On Android, you can show a rationale for using permission:
bool isShown = await Permission.contacts.shouldShowRequestRationale;
完整示例
Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: Icon(Icons.camera_enhance),
title: Text(getTranslated(context, "Camera")),
onTap: () async
var status = await Permission.photos.status;
if (status.isGranted)
final pickedFile =
await _picker.getImage(source: ImageSource.camera);
final File file = File(pickedFile.path);
imageSelected(file);
else if (status.isDenied)
final pickedFile =
await _picker.getImage(source: ImageSource.camera);
final File file = File(pickedFile.path);
imageSelected(file);
else
showDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text('Camera Permission'),
content: Text(
'This app needs camera access to take pictures for upload user profile photo'),
actions: <Widget>[
CupertinoDialogAction(
child: Text('Deny'),
onPressed: () => Navigator.of(context).pop(),
),
CupertinoDialogAction(
child: Text('Settings'),
onPressed: () => openAppSettings(),
),
],
));
),
],
),
)
【讨论】:
谢谢你,我真的不知道如何同时获得 ios 和 android 的权限 这个包有很多bug。你还有其他推荐吗? @ykonda 我认为这不是错误,但实施和理解它的工作原理有点困难,但是一旦你很好地实施它,它就会完美地工作。如果您在实施时遗漏任何内容,它将无法完全发挥作用 @PareshMangukiya android 相机存在这个非常关键的问题github.com/Baseflow/flutter-permission-handler/issues/336 根据@ykonda 在上面发布的 github 问题,截至今天(2021 年 1 月 28 日),最新版本 (5.0.1+1) 继续出现该问题【参考方案2】:我建议使用permission_handler
库并编写抽象代码(策略模式)以相同的方式处理所有权限。通常,文档很模糊,并且没有说明如何处理不可恢复/禁用场景。
代码:
/// handles .isLimited for iOS 14+ where we can restrict access.
abstract class GrantPermissionStrategy
final Permission permission;
GrantPermissionStrategy(this.permission);
Future<void> request(
required final OnPermanentlyDenied onPermanentlyDenied,
required final OnGranted onGranted,
) async
PermissionStatus status = await permission.status;
print("GrantPermissionStrategy status: $status");
if (!status.isLimited && !status.isGranted)
final PermissionStatus result = await permission.request();
if (result.isPermanentlyDenied)
onPermanentlyDenied.call();
return;
if (!result.isGranted)
return;
onGranted.call();
typedef OnPermanentlyDenied = void Function();
typedef OnGranted = void Function();
而且,你可以做出具体的实现,比如:
class GrantPermissionCameraStrategy extends GrantPermissionStrategy
GrantPermissionCameraStrategy() : super(Permission.camera);
class GrantPermissionPhotosStrategy extends GrantPermissionStrategy
GrantPermissionPhotosStrategy() : super(Platform.isAndroid ? Permission.storage : Permission.photos);
最后,调用它!:
await GrantPermissionPhotosStrategy().request(onPermatentlyDenied: ()
// launch dialog, make user go to app settings
, onGranted: () async
// we have passed! Launch the feature.
);
【讨论】:
检查status.isPermanentlyDenied
不可靠来自 permission_handler: >6.0.0
。正如文档所述:WARNING: This can only be determined AFTER requesting this permission. Therefore make a request call first.
在此处阅读更多信息:github.com/Baseflow/flutter-permission-handler/issues/…
@DarkMikey 感谢您发现这一点。更新了代码。【参考方案3】:
为简单起见,我使用了位置权限。要请求另一个权限,只需将 location 替换为该权限。这是list of all permissions。
1。安卓设置:
将这些添加到android/grade.properties
文件中:
android.useAndroidX=true
android.enableJetifier=true
在android/app/build.gradle
文件中:
android
compileSdkVersion 30 // Set this to at least 30
...
给android/app/src/main/AndroidManifest.xml
文件添加权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
...
</manifest>
2。 iOS 设置:
将此添加到info.plist
文件:
<key>NSLocationWhenInUseUsageDescription</key>
<string>App needs location permission to work</string>
将PERMISSION_LOCATION=1
添加到Podfile
:
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['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## Add the following line.
'PERMISSION_LOCATION=1'
]
end
end
end
3。颤振设置:
将此添加到pubspec.yaml
文件中:
permission_handler: ^8.0.0+2
主要工作:
检查权限:
检查位置 aka GPS 是否开启。
final serviceStatus = await Permission.locationWhenInUse.serviceStatus;
bool isGpsOn = serviceStatus == ServiceStatus.enabled;
请求许可:
final status = await Permission.locationWhenInUse.request();
if (status == PermissionStatus.granted)
print('Permission granted');
else if (status == PermissionStatus.denied)
print('Denied. Show a dialog with a reason and again ask for the permission.');
else if (status == PermissionStatus.permanentlyDenied)
print('Take the user to the settings page.');
完整代码:
class HomePage extends StatelessWidget
Future<void> _checkPermission() async
final serviceStatus = await Permission.locationWhenInUse.serviceStatus;
final isGpsOn = serviceStatus == ServiceStatus.enabled;
if (!isGpsOn)
print('Turn on location services before requesting permission.');
return;
final status = await Permission.locationWhenInUse.request();
if (status == PermissionStatus.granted)
print('Permission granted');
else if (status == PermissionStatus.denied)
print('Permission denied. Show a dialog and again ask for the permission');
else if (status == PermissionStatus.permanentlyDenied)
print('Take the user to the settings page.');
await openAppSettings();
@override
Widget build(BuildContext context)
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: _checkPermission,
child: Text('Check Permission'),
),
),
);
【讨论】:
这不适用于 Android 10,您可能还需要更新 MainActivity.kt 或 MainActivity.java @AnthonyO 它适用于所有 Android 版本。我自己在 Android 10 上对其进行了测试。您无需向任何文件的MainActivity
添加任何内容。
@CopsOnRoad 你是个聪明人,你的一些回答对我帮助很大。谢谢你帮助别人。你的答案是正确的答案。当我们使用 [var status = await Permission.photos.status ] 出现错误时,我们必须使用 [var status = await Permission.photos.request();]以上是关于如何在 Flutter 中请求和检查权限的主要内容,如果未能解决你的问题,请参考以下文章