• This repository has been archived on 04/Sep/2023
  • Stars
    star
    851
  • Rank 53,558 (Top 2 %)
  • Language
    Kotlin
  • License
    Apache License 2.0
  • Created about 9 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🙏 Android Runtime Permissions made easy and compact, for Kotlin and AndroidX. With coroutines support!

Assent

Assent is designed to make Android's runtime permissions easier and take less code in your app to use.

Android CI Codacy Badge License

Table of Contents

  1. Gradle Dependency
  2. The Basics
  3. Using Results
  4. Permanently Denied
  5. Request Debouncing
  6. Rationales
  7. Coroutines

Core

Core

Add this to your module's build.gradle file:

dependencies {
  
  implementation 'com.afollestad.assent:core:3.0.2'
}

The Basics

Runtime permissions on Android are completely reliant on the UI the user is in. Permission requests go in and out of Activities and Fragments. This library provides its functionality as Kotlin extensions to Fragment Activities (e.g. AppCompatActivity) and AndroidX Fragments.

Note: you need to have permissions declared in your AndroidManifest.xml too, otherwise Android will always deny them.

class YourActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Set to true if one or more permissions are all granted
    val permissionsGranted: Boolean = isAllGranted(WRITE_EXTERNAL_STORAGE, CAMERA)
    
    // Requests one or more permissions, sending the result to a callback
    askForPermissions(WRITE_EXTERNAL_STORAGE, CAMERA) { result ->
      // Check the result, see the Using Results section
    }
    
    // Requests one or multiple permissions and performs an action if all are granted
    runWithPermissions(WRITE_EXTERNAL_STORAGE, CAMERA) { 
      // Do something
    }
  }
}

All of the request methods above have an optional requestCode named parameter which you can use to customize the request code used when dispatching the permission request.

These methods can all be called from within an Activity or a Fragment. It works the same way in both.


Using Results

AssentResult is provided in request callbacks. It has a few useful fields and methods:

val result: AssentResult = // ...

val permissions: List<Permission> = result.permissions
val grantResults: List<GrantResult> = result.grantResults

// Takes a single permission and returns if this result contains it in its set
val containsPermission: Boolean = result.containsPermission(WRITE_EXTERNAL_STORAGE)

// You can pass multiple permissions as varargs
val permissionGranted: Boolean = result.isAllGranted(WRITE_EXTERNAL_STORAGE)

// You can pass multiple permissions as varargs
val permissionDenied: Boolean = result.isAllDenied(WRITE_EXTERNAL_STORAGE)

// Returns GRANTED, DENIED, or PERMANENTLY_DENIED
val writeStorageGrantResult: GrantResult = result[WRITE_EXTERNAL_STORAGE]

val granted: Set<Permission> = result.granted()

val denied: Set<Permission> = result.denied()

val permanentlyDenied: Set<Permission> = result.permanentlyDenied()

Permanently Denied

Assent detects when the user of your app has permanently denied a permission. Once a permission is permanently denied, the Android system will no longer show the permission dialog for that permission. At this point, the only way to get them to grant the permission is to explain why you really need the permission and then launch system app details page for your app.

val result: AssentResult = // ...

if (result[WRITE_EXTERNAL_STORAGE] == PERMANENTLY_DENIED) {
  // NOTE: You should show a dialog of some sort before doing this!
  showSystemAppDetailsPage()
}

Request Debouncing

If you were to do this...

askForPermissions(WRITE_EXTERNAL_STORAGE) { _ -> }

askForPermissions(WRITE_EXTERNAL_STORAGE) { _ -> }

...the permission would only be requested once, and both callbacks would be called at the same time.

If you were to do this...

askForPermissions(WRITE_EXTERNAL_STORAGE) { _ -> }

askForPermissions(CALL_PHONE) { _ -> }

...Assent would wait until the first permission request is done before executing the second request.


Rationales

Rationales

Add this to your module's build.gradle file:

dependencies {

      implementation 'com.afollestad.assent:rationales:3.0.2'
}

Google recommends showing rationales for permissions when it may not be obvious to the user why you need them.

Assent supports extensible rationale handlers, it comes with two out-of-the-box:

  • SnackBarRationaleHandler
  • AlertDialogRationaleHandler
// Could also use createDialogRationale(...) here, 
// or provide your own implementation of RationaleHandler. 
val rationaleHandler = createSnackBarRationale(rootView) {
  onPermission(READ_CONTACTS, "Test rationale #1, please accept!")
  onPermission(WRITE_EXTERNAL_STORAGE, "Test rationale #1, please accept!")
  onPermission(READ_SMS, "Test rationale #3, please accept!")
}

askForPermissions(
    READ_CONTACTS, WRITE_EXTERNAL_STORAGE, READ_SMS,
    rationaleHandler = rationaleHandler
) { result ->
  // Use result
}

Coroutines

Coroutines

Add this to your module's build.gradle file:

dependencies {

  implementation 'com.afollestad.assent:coroutines:3.0.2'
}

Kotlin coroutines enable Assent to work without callbacks. If you do not know the basics of coroutines, you should research them first.

First, awaitPermissionsResult(...) is the coroutines equivalent to askForPermissions(...):

// The coroutine extensions work from within any `suspend` function/lambda.
coroutineScope {
   val result: AssentResult = awaitPermissionsResult(
       READ_CONTACTS, WRITE_EXTERNAL_STORAGE, READ_SMS,
       rationaleHandler = rationaleHandler
   )
   // Use the result...
}

And second, awaitPermissionsGranted(...) is the coroutines equivalent to runWithPermissions(...):

// The coroutine extensions work from within any `suspend` function/lambda.
coroutineScope {
   awaitPermissionsGranted(
       READ_CONTACTS, WRITE_EXTERNAL_STORAGE, READ_SMS,
       rationaleHandler = rationaleHandler
   )
   // All three permissions were granted...
}

More Repositories

1

material-dialogs

😍 A beautiful, fluid, and extensible dialogs API for Kotlin & Android.
Kotlin
19,672
star
2

aesthetic

[DEPRECATED]
Kotlin
1,999
star
3

drag-select-recyclerview

👇 Easy Google Photos style multi-selection for RecyclerViews, powered by Kotlin and AndroidX.
Kotlin
1,969
star
4

photo-affix

📷 Stitch your photos together vertically or horizontally easily!
Kotlin
1,008
star
5

material-cab

🚕 An Android & Kotlin library for placing and manipulating Contextual Action Bars in your UI.
Kotlin
982
star
6

ason

[DEPRECATED]: Prefer Moshi, Jackson, Gson, or LoganSquare
Java
758
star
7

recyclical

🚀 An easy-to-use, extensible Kotlin DSL for setting up and manipulating RecyclerViews.
Kotlin
716
star
8

vvalidator

🤖 An easy to use form validator for Kotlin & Android.
Kotlin
658
star
9

mnml

📹 A minimal, beautiful screen recorder for Android.
Kotlin
656
star
10

nock-nock

🚪 Monitor and validate your websites to maintain maximum uptime.
Kotlin
377
star
11

inline-activity-result

Receive Activity results inline, without any boilerplate. Optional coroutines and RxJava support.
Kotlin
316
star
12

rxkprefs

🛠 A small Kotlin library to make shared preferences easy + RxJava and Coroutines support
Kotlin
277
star
13

ulfberht

🗡️ A small but powerful & opinionated DI library. Written in Kotlin, and powered by annotation processing.
Kotlin
251
star
14

viewpagerdots

👀 Simple, compact Kotlin library for ViewPager page indicators.
Kotlin
189
star
15

date-picker

📅 Custom responsive date picker widget for Android, written in Kotlin.
Kotlin
159
star
16

assure

A Kotlin library that makes biometric authentication quick and easy.
Kotlin
67
star
17

arctic-icon-request

An easy to use Icon Request API for Kotlin, with traditional email capabilities plus the Arctic Manager API.
Kotlin
60
star
18

af.codes

🌐 The source code of my personal website.
HTML
31
star
19

pi-feeder

My WIP Raspberry Pi auto pet feeder system.
CSS
31
star
20

pi-feeder-android

A simple client for my Pi Feeder IoT device. Used for discovery and basic setup, scheduling is left to the web dashboard.
Java
19
star
21

node-deploy

A Git and HTTP powered deployment system for Node.js apps.
JavaScript
8
star
22

web-recording-experiments

Experiments with recording audio and video from the web. This repo is incomplete, right now. I will be adding more.
JavaScript
4
star
23

trifles

JavaScript
3
star
24

color-render

JavaScript
3
star
25

afollestad

2
star