Sunday, March 29, 2020

Flutter - Permission handler example

Our mobile contains lots of sensitive data of the users like files, financial data, contacts and other things that users can store. The mobile operating system has a privileged to keep them secure because all applications are separated from another through a distinct id. Each application work in its own process thus is isolated from all other applications. As a result, an application can’t access any file or data outside its scope until and unless the file or data is shared with the applications.
 

flutter permission hanlder example code snippet.
If an application needs anything outside its scope, then it has to request permission to the user or application. The Mobile operating system comes with a set of predefined permissions (System permissions) for certain tasks.  All mobile applications can request the required permissions to access a particular service of OS. For example, an application can declare required permissions like network, contact, and GPS.




We can divide mobile services permission into two protection levels: Normal and Dangerous Permission:
  • Normal permissions are very deemed harmless for the user's privacy and files from other applications. It is automatically granted to the applications when you install it in the mobile. Examples: ACCESS_WIFI_STATE, WAKE_LOCK, etc. 
  • Dangerous permissions affect the user's privacy and private information. Such kind of permission could potentially affect user data or the operation of other applications. Examples: READ_CONTACTS, ACCESS_COARSE_LOCATION, etc.

In this post, we'll see how we can handle dangerous permissions in the Flutter application. We have to determine which permissions we need because the app needs to publicly declare the permissions. Let create a Flutter application and try to understand the process of permission handling. 

Creating a new Project

1. Create a new project from File ⇒ New Flutter Project with your development IDE.
2. Now, add the plugin permission_handler: '^4.4.0+hotfix.2' as a dependency in the pubspec.yaml file. Once you do that, you need to run flutter packages:

dependencies:
  permission_handler: '^4.4.0+hotfix.2'

3. Now, let's understand the basic behavior of Andriod and iOS before declaring permission in the iOS and Android projects that we going to use in the project. 

  • Android Permission Setup

    • Before API 23,  the Android OS asked permission from the user before installing the application that you have declared in the Android manifest. If the user denies the required permission, the application will not install and if give all the permissions, you can't be denied after the installation.
    • Now, Android has changed the permission concept after API 23. Your application will ask permission during runtime but still, you have to declare the required permissions in the Android manifest and you can disable all permission any time from the application setting. We can declare permission in the Android manifest by using the <uses-permission> tag.  You can find the manifest file android/src/main/AndroidManifest.xml path in the Flutter project:

      <manifest ...>
          <uses-permission android:name="android.permission.READ_CONTACTS"/>
          <application ...>
              ...
          </application>
      </manifest>

    • AndroidX Setup

      The plugin permission_handler: '^4.4.0+hotfix.2' supports AndroidX. This means you have to perform the following action in the Android package.

      Add the following into "gradle.properties" file:
      
      android.useAndroidX=true
      android.enableJetifier=true
      
      Set the compileSdkVersion in "android/app/build.gradle":
      
      android {
       compileSdkVersion 28
       ...
      }


    IOS Permission Setup

    In iOS, we have to add the permissions into information property file info.plist with the Key:

     <key>NSContactsUsageDescription</key>
    <string>This app requires to contact permission</string>

    In Flutters, you can find the info.plist in the iOS/Runner directory at the root of the project.


4.
After that open main.dart file and import
permission_handler.dart to use it in this project.
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: new ThemeData(
        primaryColor: const Color(0xFF02BB9F),
        primaryColorDark: const Color(0xFF167F67),
        accentColor: const Color(0xFF167F67),
      ),
      home: PermissionHandlerHomePage(title: 'Flutter permission handler'),
    );
  }
}

before going to use permission handle plugin in our Flutter project. Let's, understand the methods and behavior of permission_handler: '^4.4.0+hotfix.2' plugin.

How can Request Permission

To request permission, you have to create an instance of PermissionHandler. After that, call method requestPermissions() with a single permission key or list of permissions which allows you to ask for multiple permissions you need at once. You can do it like this.

final PermissionHandler _permissionHandler = PermissionHandler();
var result = await _permissionHandler.requestPermissions([PermissionGroup.contacts]);

finally, you can check the result to see if the user granted permission or not. The results object is an array of PermissionStatus. The key of the array is the permission that you were requesting. 

Checking Permission Status

Sometimes we need to check permission status before performing the action. It can help you determine if a feature is available or disabled on the users’ device. For example, we can check if permission to access contacts was granted like this:
final PermissionHandler _permissionHandler = PermissionHandler();
var permissionStatus = await _permissionHandler.checkPermissionStatus(PermissionGroup.contacts);
 
You can check for permission by using the checkPermissionStatus function, which accepts the Permission as a parameter. This returns a PermissionStatus that you can check with the help of following method or way:

switch (result[PermissionGroup.contacts]) {
  case PermissionStatus.granted:
    // Application has been given permission to use the feature.
    break;
  case PermissionStatus.denied:
    // Application has been denied permission to use the feature.
    break;
  case PermissionStatus.neverAskAgain:
    // No action perform for the permissions.  
    break;
  case PermissionStatus.restricted:
    // iOS has restricted access to a specific feature. 
    break;
  case PermissionStatus.Unknown:
    // Unknown state of the permissions. 
    break; 
  case PermissionStatus.Disabled:
    // Feature is disabled for the application. 
    break;
  default:
} 


Android and ios specific permission

Lots of permissions are common in both OS such as contacts, calendar, microphone, location, etc. But, there are some permissions that do not match up on both OS. Like storage, SMS, etc. are only on android. You have to determine the platform before requesting permission from the user. For example, if you wanted photos from the gallery. Then for iOS, you need photos permission while in android you need external storage permission.

var permission = Platform.isAndroid ? PermissionGroup.storage : PermissionGroup.photos; 
after that, you can check the status of app permission as explained above.

How can open app setting?

Sometimes, we need to open the application setting to view given permission. So, you can open it with the following method:
PermissionHandler().openAppSettings();




5. Here, you can see the complete code snippet of this demo. where we have used all the code snippet that we explained above. In this demo, we showing all the permissions in a list that the plugin provides us and managing the status of permission with different colors.

import 'package:flutter/material.dart';
import 'package:fluttergradientexample/item.dart';
import 'package:permission_handler/permission_handler.dart';
flutter permission handler example
void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', debugShowCheckedModeBanner: false, theme: new ThemeData( primaryColor: const Color(0xFF02BB9F), primaryColorDark: const Color(0xFF167F67), accentColor: const Color(0xFF167F67), ), home: PermissionHandlerHomePage(), ); } } class PermissionHandlerHomePage extends StatefulWidget { @override _PermissionHandlerHomePageState createState() { return _PermissionHandlerHomePageState(); } } class _PermissionHandlerHomePageState extends State<PermissionHandlerHomePage> { List<Item> list = List<Item>(); @override void initState() { super.initState(); initList(); } void initList() { list.clear(); for (var i = 0; i < PermissionGroup.values.length; i++) { list.add(Item(PermissionGroup.values[i], PermissionStatus.denied)); } resolveState(); } void resolveState() { for (var index = 0; index < PermissionGroup.values.length; index++) { Future<PermissionStatus> status = PermissionHandler().checkPermissionStatus(list[index].group); status.then((PermissionStatus status) { setState(() { list[index].status = status; }); }); } } permissionItem(int index) { return Container( child: ListTile( leading: CircleAvatar( child: Text(index.toString()), ), title: Text(list[index].group.toString()), subtitle: (list[index].status != null) ? Text( list[index].status.toString(), style: statusColors(index), ) : null, onTap: () { requestPermission(index); }, ), ); } statusColors(int index) { switch (list[index].status) { case PermissionStatus.granted: return TextStyle(color: Colors.green); case PermissionStatus.denied: return TextStyle(color: Colors.red); break; case PermissionStatus.neverAskAgain: return TextStyle(color: Colors.grey); break; case PermissionStatus.restricted: return TextStyle(color: Colors.red); break; case PermissionStatus.unknown: return TextStyle(color: Colors.red); break; default: } } Future requestPermission(int index) async { await PermissionHandler().requestPermissions([list[index].group]); initList(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( "Permission List", style: TextStyle(color: Colors.white), ), actions: <Widget>[ IconButton( icon: Icon(Icons.refresh, color: Colors.white), onPressed: () { initList(); }, ), IconButton( icon: Icon( Icons.settings, color: Colors.white, ), onPressed: () { PermissionHandler().openAppSettings(); }, ) ], ), body: ListView.builder( itemCount: list.length, itemBuilder: (context, index) { return permissionItem(index); }, ), ); } }

to display list items, we have created a separate file that contains the instance of  PermissionGroup and PermissionStatus.
import 'package:permission_handler/permission_handler.dart';

class Item {
  PermissionGroup group;
  PermissionStatus status;
  Item(this.group, this.status);
}


In this post, we’ve learned how to handle required permission to use a particular service of  OS. I hope, with the help of the above example you can easily use and manage all permission in the Flutter application. If you are facing any problem or you have any quires, please feel free to ask it from the comment section below.



Share:

Get it on Google Play

React Native - Start Development with Typescript

React Native is a popular framework for building mobile apps for both Android and iOS. It allows developers to write JavaScript code that ca...