Saltar al contenido principal

Runtime Permissions in Android

As an Android developer, you are probably aware of the importance of permissions in an app. Permissions are rules that an app must follow to access sensitive data or perform certain actions on a user's device. In earlier versions of Android, permissions were granted at the time of installation. However, with the release of Android Marshmallow (6.0), a new permission model called Runtime Permissions was introduced. In this article, we will dive into Runtime Permissions in Android.

What are Runtime Permissions?

Runtime Permissions are permissions that are requested by an app while it is running. This means that an app must ask the user for permission to access sensitive data or perform certain actions when it needs to. The user can either grant or deny the permission request. If the user denies the permission request, the app can still function, but it will not have access to the requested data or functionality.

Why are Runtime Permissions important?

Runtime Permissions are important for two main reasons:

  1. Security: Runtime Permissions provide an additional layer of security to the user's device. By requesting permissions at runtime, the user has more control over which apps have access to their data and device functionality.

  2. User Experience: Runtime Permissions provide a better user experience. Instead of asking for all permissions at installation, an app can request permissions only when it needs them. This reduces the number of permission requests that the user sees and makes the app feel less intrusive.

How to implement Runtime Permissions

Implementing Runtime Permissions in an Android app involves the following steps:

  1. Requesting permissions: When an app needs to access sensitive data or functionality, it must request the appropriate permission from the user. This is done using the requestPermissions() method.
// Requesting permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_CONTACTS),
MY_PERMISSIONS_REQUEST_READ_CONTACTS)
}

In the above example, the app is requesting the READ_CONTACTS permission. If the permission has not already been granted, the app will request the permission using requestPermissions(). The MY_PERMISSIONS_REQUEST_READ_CONTACTS is an integer value that is used to identify the permission request.

  1. Handling permission responses: After the user responds to the permission request, the app must handle the response. This is done using the onRequestPermissionsResult() method.
// Handling permission response
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_READ_CONTACTS -> {
if (grantResults.isNotEmpty()
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
} else {
// Permission denied
}
return
}
}
}

In the above example, the app is handling the response to the READ_CONTACTS permission request. If the permission is granted, the app can proceed with accessing the user's contacts. If the permission is denied, the app can handle the situation appropriately.

Best practices for implementing Runtime Permissions

When implementing Runtime Permissions in an Android app, it is important to follow best practices to ensure a good user experience. Some best practices include:

  1. Explain why permissions are needed: When requesting permissions, it is important to explain to the user why the permission is needed. This can be done using a dialog or a message.

  2. Handle permission denials gracefully: When a user denies a permission request, the app should handle the situation gracefully. This could involve showing a message or providing an alternative way for the user to complete the task.

  3. Test on different Android versions: Runtime Permissions were introduced in Android Marshmallow, but they work differently on different Android versions. It is important to test your app on different Android versions to ensure that the permission requests and responses work as expected.

Quick Permissions Example

1. Android Runtime Permission Check and Request

Let's now put together a simple utility or helper class to allow us check and request for permissions in an easy manner. This class can be reused.

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;

public class PermissionUtils{

private static final int REQUEST_CODE = 1111;

private Context context;

private PermissionCallback callback;

private PermissionUtils(Context context) {
this.context = context;
}

public static PermissionUtils getInstance(Context context){
return new PermissionUtils(context);
}

public void requestPermission(@NonNull String permission){
if (ContextCompat.checkSelfPermission(context,permission) == PackageManager.PERMISSION_GRANTED){
if (callback != null){
callback.success();
}
}else {
ActivityCompat.requestPermissions((Activity) context,new String[]{permission},REQUEST_CODE);
}
}

public PermissionUtils setCallback(PermissionCallback callback) {
this.callback = callback;
return this;
}

public interface PermissionCallback{

int REQUEST_CODE = 1234;

void success();
void fail();
}

}

Full Permission Examples

1. Request and Check Permission

Let's look at a runtime permission example. We will see how to check and request permissions in a full runnable app.

MainActivity.java

This is the main activity. It will be responsible for checking and requesting permission.

```java
package com.example.ankitkumar.permissionrequest;

import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;

import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.CAMERA;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private static final int PERMISSION_REQUEST_CODE = 200;
private View view;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

Button check_permission = (Button) findViewById(R.id.check_permission);
Button request_permission = (Button) findViewById(R.id.request_permission);
check_permission.setOnClickListener(this);
request_permission.setOnClickListener(this);

}
@Override
public void onClick(View v) {

view = v;

int id = v.getId();
switch (id) {
case R.id.check_permission:
if (checkPermission()) {

Snackbar.make(view, "Permission already granted.", Snackbar.LENGTH_LONG).show();

} else {

Snackbar.make(view, "Please request permission.", Snackbar.LENGTH_LONG).show();
}
break;
case R.id.request_permission:
if (!checkPermission()) {

requestPermission();

} else {

Snackbar.make(view, "Permission already granted.", Snackbar.LENGTH_LONG).show();

}
break;
}

}

private boolean checkPermission() {
//int result = ContextCompat.checkSelfPermission(getApplicationContext(), ACCESS_FINE_LOCATION);
int result1 = ContextCompat.checkSelfPermission(getApplicationContext(), CAMERA);

return result1 == PackageManager.PERMISSION_GRANTED;
}

private void requestPermission() {

ActivityCompat.requestPermissions(this, new String[]{CAMERA}, PERMISSION_REQUEST_CODE);

}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0) {

// boolean locationAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean cameraAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED;

if (cameraAccepted)
Snackbar.make(view, "Permission Granted, Now you can access camera.", Snackbar.LENGTH_LONG).show();
else {

Snackbar.make(view, "Permission Denied, You cannot access camera.", Snackbar.LENGTH_LONG).show();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
showMessageOKCancel("You need to allow access to the permission",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{ACCESS_FINE_LOCATION, CAMERA},
PERMISSION_REQUEST_CODE);
}
}
});
return;
}
}

}
}

break;
}
}

private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(MainActivity.this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
}

}

activity_main.xml

This is the main layout. We will have two buttons: one for checking permission while the other for requesting permission.

We wrap them in the RelativeLayout.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout

android_layout_width="match_parent"
android_layout_height="match_parent"
android_paddingBottom="@dimen/activity_vertical_margin"
android_paddingLeft="@dimen/activity_horizontal_margin"
android_paddingRight="@dimen/activity_horizontal_margin"
android_paddingTop="@dimen/activity_vertical_margin"
app_layout_behavior="@string/appbar_scrolling_view_behavior"
tools_context="com.example.ankitkumar.permissionrequest.MainActivity"
>
<Button
android_id="@+id/check_permission"
android_layout_width="match_parent"
android_layout_centerInParent="true"
android_layout_height="wrap_content"
android_text="Check Permission"/>
<Button
android_id="@+id/request_permission"
android_layout_below="@+id/check_permission"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_text="Request Permission"/>
</RelativeLayout>

Download

No.LocationLink
1.GitHubDownload
2.GitHubBrowse
2.GitHubOriginal Creator: @AnkitKumar111

Conclusion

Runtime Permissions are an important aspect of Android app development. They provide an additional layer of security to the user's device and a better user experience. By following best practices and testing on different Android versions, you can ensure that your app implements Runtime Permissions correctly.