Landroid

[플러터] 헷갈리는 권한 정리(with permission_handler) 본문

플러터

[플러터] 헷갈리는 권한 정리(with permission_handler)

silso 2020. 12. 22. 14:52

플러터를 처음 공부할 때 가장 어려웠던 것 중 하나가 권한요청입니다 ㅠㅠ.

정확히는 어렵다기 보다 내장기능이 없고 라이브러리를 끌고 와서 사용해야 한다는 점이

안드로이드랑 좀 달라서 당황스러웠습니다.

 

그럼 플러터에서 권한 요청하는 대표적인 라이브러리인 Permission_handler에 대해 알아보겠습니다.

 

우선 원하는 라이브러리를 찾기 위해 아래 사이트에 접속해서 permission이라고 검색을 합니다.

https://pub.dev/

 

Dart packages

Pub is the package manager for the Dart programming language, containing reusable libraries & packages for Flutter, AngularDart, and general Dart programs.

pub.dev

 

그럼 좋아요와 인기가 압도적으로 많은 라이브러리가 눈에 띌 것 입니다.

이놈을 이용해서 한 번 권한을 요청해보겠습니다.

 

1단계: 라이브러리 추가

pubspec.yaml에 가셔서 dependencies 하위에 permission_handler를 추가합니다.

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.1
  permission_handler: ^5.0.1+1

그다음 오른쪽 상단에 Pub get을 눌러주시고 다음 단계로 넘어갑니다.

 

2단계: 네이티브(AOS)에 권한 추가

맥북이 비싸서 사용 못하는 학생ㅠ

이제부터 안드로이드 기준으로 설명드리겠습니다.

사용하고자 하는 권한은 네이티브 코드에 추가해야 정상적으로 작동합니다.

android > app > src > main > AndroidManifest.xml로 이동해줍니다.

여기서 다음과 같은 형식으로 원하는 권한을 추가합니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sirasatarato.permission">

<!--    <uses-permission android:name="android.permission.권한이름"/>-->
    <uses-permission android:name="android.permission.READ_CALENDAR"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
    <uses-permission android:name="android.permission.BODY_SENSORS"/>
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
더보기

블루투스 같은 권한은 현재 플러터로선 처리할 방법이 없습니다. ㅠㅠ

그래서 이 것과 같은 경우는 네이티브에서 직접 처리해줘야 합니다.

 

3단계: 권한 요청하기

// Permission.dart

static const List<Permission> values = <Permission>[
    calendar,
    camera,
    contacts,
    location,
    locationAlways,
    locationWhenInUse,
    mediaLibrary,
    microphone,
    phone,
    photos,
    reminders,
    sensors,
    sms,
    speech,
    storage,
    ignoreBatteryOptimizations,
    notification,
    accessMediaLocation,
    activityRecognition,
    unknown,
  ];

^ Permission_handler로 요청할 수 있는 권한은 위와 같습니다.

 

3-1. 권한 요청하기

callPermission() async {
  await Permission.camera.request();
}

단순히 권한 요청만 한다면 다음과 같이 요청할 수 있습니다.

하지만 여기에 그치지 않고 사용자가 권한을 허용하는지 거부하는지에 따른 동작이 필요할 때도 있습니다.

다음과 같이 사용자의 행동에 따라 작업을 처리할 수 있습니다.

 

3-2. 권한 요청 처리하기

callPermission() async {
  var status = await Permission.camera.request();
  
  if (status.isGranted) {
    log('권한이 부여되었습니다.');
  }

  if(status.isDenied) {
    log('권한 부여가 거부되었습니다.');
  }

  if(status.isPermanentlyDenied) {
    log('권한 부여가 영구적으로 거부되었습니다.');
  }

  if(status.isRestricted) {
    log('권한이 제한되었습니다.');
  }

  if(status.isUndetermined) {
    log('권한 부여가 아직 미정입니다.');
  }
}

2번째 줄에 'Permission.권한.request()' 은 권한을 요청하는 함수로 반환값은 Future<PermissionStatus>입니다.

따라서 await로 사용자가 권한을 어떻게 할지 선택하면 status에 PermissionStatus 값이 할당되고 위와 같은 5가지의 상태에 대한 처리가 가능합니다.

 

물론 Permission.camera.request()는 권한을 요청하는 코드라서 단순히 PermissionStatus 값만 가져오려면 아래 코드로 가져올 수 있습니다.

var status = await Permission.camera.status;

 

3-3. 여러 권한 요청하기

위에처럼 권한을 하나씩 요청하는 것이 아니라 여러 개를 동시에 요청해야 하는 경우에는 Map<Permission, PermissionStatus>에 .request() 만붙이시면 됩니다.

callPermissions() async {
  Map<Permission, PermissionStatus> statuses = await [
    Permission.location,
    Permission.storage,
  ].request();
  
  print(statuses[Permission.location].isGranted);
}

 

4. 예시 코드

import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
  runApp(MyApp());
}

Future<String> callPermissions() async {
  Map<Permission, PermissionStatus> statuses = await [
    Permission.location,
    Permission.storage,
  ].request();

  if (statuses.values.every((element) => element.isGranted)) {
    return 'success';
  }

  return 'failed';
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Permission'),
        ),
        body: Center(
          child: FutureBuilder(
            future: callPermissions(),
            builder:
                (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
              if (snapshot.hasData) {
                return Text(snapshot.data);
              }

              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

 

 

Comments