vmadalin / easypermissions-ktx

🔓 Kotlin version of the popular google/easypermissions wrapper library to simplify basic system permissions logic on Android M or higher.
https://firebaseopensource.com/projects/googlesamples/easypermissions/
Apache License 2.0
382 stars 38 forks source link
android android-library android-sdk dangerous-permissions easypermissions kotlin kotlin-library permission permissions permissions-android request-permissions runtime-permissions

EasyPermissions-ktx

Build Status Code Coverage Latest Version Android API Kotlin Weekly Android Weekly Apache License

Kotlin version of the popular googlesample/easypermissions wrapper library to simplify basic system permissions logic on Android M or higher.

Logo

This library lifts the burden that comes with writing a bunch of check statements whether a permission has been granted or not from you, in order to keep your code clean and safe.

Installation

EasyPermissions-ktx is installed by adding the following dependency to your build.gradle file:

dependencies {
    implementation 'com.vmadalin:easypermissions-ktx:1.0.0'
}

Tutorial

This video tutorial helps and guide you regarding all the process to integrate the library to your project and configure it, thanks to Stevdza-San.

Usage

Basic

To begin using EasyPermissions-ktx, have your Activity (or Fragment) override the onRequestPermissionsResult method:

class MainActivity : AppCompatActivity() {

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        // EasyPermissions handles the request result.
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
    }
}

Request Permissions

The example below shows how to request permissions for a method that requires both CAMERA and ACCESS_FINE_LOCATION permissions. There are a few things to note:

@AfterPermissionGranted(REQUEST_CODE_LOCATION_AND_CONTACTS_PERMISSION)
private void methodRequiresTwoPermission() {
    if (EasyPermissions.hasPermissions(this, ACCESS_FINE_LOCATION, READ_CONTACTS)) {
        // Already have permission, do the thing
        // ...
    } else {
        // Do not have permissions, request them now
        EasyPermissions.requestPermissions(
            host = this,
            rationale = getString(R.string.permission_location_and_contacts_rationale_message),
            requestCode = REQUEST_CODE_LOCATION_AND_CONTACTS_PERMISSION,
            perms = ACCESS_FINE_LOCATION, READ_CONTACTS
        )
    }
}

Or for finer control over the rationale dialog, use a PermissionRequest:

val request = PermissionRequest.Builder(spyActivity)
    .code(REQUEST_CODE)
    .perms(REQUEST_CODE_LOCATION_AND_CONTACTS_PERMISSION)
    .theme(R.style.my_fancy_style)
    .rationale(R.string.camera_and_location_rationale)
    .positiveButtonText(R.string.rationale_ask_ok)
    .negativeButtonText(R.string.rationale_ask_cancel)
    .build()
EasyPermissions.requestPermissions(spyActivity, request)

Optionally, for a finer control, you can have your Activity / Fragment implement the PermissionCallbacks interface.

class MainActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks {

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        // EasyPermissions handles the request result.
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
    }

    override fun onPermissionsGranted(requestCode: Int, perms: List<String>) {
        // Some permissions have been granted
        // ...
    }

    override fun onPermissionsDenied(requestCode: Int, perms: List<String>) {
        // Some permissions have been denied
        // ...
    }
}

Required Permissions

In some cases your app will not function properly without certain permissions. If the user denies these permissions with the "Never Ask Again" option, you will be unable to request these permissions from the user and they must be changed in app settings. You can use the method EasyPermissions.somePermissionPermanentlyDenied(...) to display a dialog to the user in this situation and direct them to the system setting screen for your app:

Note: Due to a limitation in the information provided by the Android framework permissions API, the somePermissionPermanentlyDenied method only works after the permission has been denied and your app has received the onPermissionsDenied callback. Otherwise the library cannot distinguish permanent denial from the "not yet denied" case.

override fun onPermissionsDenied(requestCode: Int, perms: List<String>) {
    Log.d(TAG, "onPermissionsDenied: $requestCode :${perms.size()}")

    // (Optional) Check whether the user denied any permissions and checked "NEVER ASK AGAIN."
    // This will display a dialog directing them to enable the permission in app settings.
    if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
        SettingsDialog.Builder(this).build().show()
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == DEFAULT_SETTINGS_REQ_CODE) {
        val yes = getString(R.string.yes)
        val no = getString(R.string.no)

        // Do something after user returned from app settings screen, like showing a Toast.
        Toast.makeText(
            this,
            getString(
                R.string.returned_from_app_settings_to_activity,
                if (hasCameraPermission()) yes else no,
                if (hasLocationAndContactsPermissions()) yes else no,
                if (hasSmsPermission()) yes else no,
                if (hasStoragePermission()) yes else no
            ),
            LENGTH_LONG
        ).show()
    }
}

Interacting with the rationale dialog

Implement the EasyPermissions.RationaleCallbacks if you want to interact with the rationale dialog.

override fun onRationaleAccepted(requestCode: Int) {
    // Rationale accepted to request some permissions
    // ...
}

override fun onRationaleDenied(requestCode: Int) {
    // Rationale denied to request some permissions
    // ...
}

Rationale callbacks don't necessarily imply permission changes. To check for those, see the EasyPermissions.PermissionCallbacks.