요즘(사실 오래됐다)의 안드로이드와 IOS를 사용하려면 권한을 획득해야한다.
플러터는 권한 획득 여부와 획득을 위해서는 네이티브와 통신해야한다.
"아니 이럴거면 네이티브 개발했지!"
걱정마라. 좋은 패키지가 있으니.
이번 포스트에서는 permission_handler를 사용해서 플러터에서 안드로이드와 IOS의 퍼미션 관리에 대한 사용법을 정리하려한다.
dependencies:
permission_handler: ^10.0.0
본 포스트에서는 10.0.0로 작성 시점 최신버전을 사용했다.
네이티브 설정, 권한 획득, 획득 여부에 대해 알아보겠다.
아쉽게도 권한은 OS와 연관되어있기때문에, 네이티브 파일을 건드려 어떤 권한을 사용할지 알려줘야한다.
해당 패키지는 플러터 1.12 안드로이드 프로젝트 이상에서 동작한다. 따라서 1.12 이전의 프로젝트의 경우 상위로 업데이트해줘야한다. 해당 방법은 Upgrading pre 1.12 Android projects을 참고하자.
플러터 1.12 버전 이상에서는 AndroidX를 자동 지원하나, 그 이전의 버전에서는 강제로 AndroidX를 지원하게끔 해야한다.
android.useAndroidX=true
android.enableJetifier=true
compileSdkVersion을 33으로 설정한다.android {
compileSdkVersion 33
...
}
위 과정까지는 마이그레이션 단계라고 생각하면 될 것 같다.
Android 권한을 사용하기 위해서는 AndroidManifest.xml에 사용할 권한을 추가해야한다.
아래 코드는 permission_handler에서 획득할 수 있는 Android의 모든 권한이다.
<!--
Internet permissions do not affect the `permission_handler` plugin, but are required if your app needs access to
the internet.
디버그 모드에서는 INTERNET 권한이 없어도 API 요청 등이 동작한다. 릴리즈 모드에서 사용하기 위해서는 해당 권한이 필요하다.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Permissions options for the `contacts` group
* 그룹 권한의 경우
<uses-permission android:name="android.permission-group.CONTACTS"/>
와 같이 한번에 권한 사용을 지정할 수 있다.
-->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!-- Permissions options for the `storage` group -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- Permissions options for the `camera` group -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- Permissions options for the `sms` group -->
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
<!-- Permissions options for the `phone` group -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
<uses-permission android:name="android.permission.USE_SIP"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<uses-permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"/>
<!-- Permissions options for the `calendar` group -->
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<!-- Permissions options for the `location` group -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- Permissions options for the `microphone` or `speech` group -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Permissions options for the `sensors` group -->
<uses-permission android:name="android.permission.BODY_SENSORS" />
<!-- Permissions options for the `accessMediaLocation` group -->
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<!-- Permissions options for the `activityRecognition` group -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<!-- Permissions options for the `ignoreBatteryOptimizations` group -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<!-- Permissions options for the `bluetooth` group -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Permissions options for the `manage external storage` group -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- Permissions options for the `system alert windows` group -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- Permissions options for the `request install packages` group -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- Permissions options for the `access notification policy` group -->
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
<application
...
이 외에도 많은 권한이 있다. 더 많은 권한 목록은 여기를 찾아보자.
IOS는 두가지 파일을 수정해야한다. Info.plist와 Podfile이다.
info.plist는 앱에 관련된 프로퍼티들을 설정한다.
info.plist 파일을 먼저 수정하자. 아래 키쌍은 permission_handler에서 획득할 수 있는 모든 권한이다. 원하는 권한을 파일에 작성한다.
<dict>
...
<!-- 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>
직접 info.plist파일에 추가해도 되고 xcode에서 추가해도 된다.
<string><string>에는 해당 권한을 왜 사용하는지 써야한다! 개발에는 상관없으나 배포 때는 바꿔주도록 하자. 앱 출시 시, 거절 당하는 원인 중 하나라고 한다!
다음은 Podfile을 수정한다.
post_install do |installer|
installer.pods_project.targets.each do |target|
... # Here are some configurations automatically generated by flutter
# Start of the permission_handler configuration
target.build_configurations.each do |config|
# You can enable the permissions needed here. For example to enable camera
# permission, just remove the `#` character in front so it looks like this:
#
# ## dart: PermissionGroup.camera
# 'PERMISSION_CAMERA=1'
#
# Preprocessor definitions can be found in: https://github.com/Baseflow/flutter-permission-handler/blob/master/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h
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 of the permission_handler configuration
end
end
사용하려는 권한을 아래처럼 주석을 해제한다. 'dart:' 부분은 주석 해제하면 안된다.
## dart: PermissionGroup.camera
'PERMISSION_CAMERA=1'
권한을 획득하려면 request() 매소드를 호출한다.
얻고자 하는 퍼미션의 request() 매소드를 호출하면 권한을 얻는 과정이 실행(다이얼로그 출력 등)되고 PermissionStatus를 반환한다.
해당 객체는 권한을 얻었는지 거부했는지 등의 정보를 가지고 있다.
여러 권한을 한번에 얻으려면 List로 만들어 request() 매소드를 호출한다.
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]);
또한, 해당 패키지는 openAppSettings() 함수를 제공하는데 이는 앱의 권한을 수동으로 부여하고 거절 할 수 있게 앱 세팅화면을 실행시켜준다.
자세한 내용은 permission_handler, Permission API에서 확인 할 수 있다.
정리 너무 감사합니다!!