вівторок, 17 липня 2018 р.

Дозволи доступу в Android 6 та вище (Android permissions)

В андроїді 6 було переглянуто концепцію надання доступу. Раніше розробник у файлі manifest.xml вказував дозволи на доступ до компонентів мобільного таким чином:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.CAMERA"/>

Цього було досить в попередніх версіях андроїда. Користувач при встановленні програми підтверджував ці доступи і програма отримувала доступ до необхідних засобів. Такий підхід призвів до проблеми пов’язаної із тим, що програми-шпигуни могли без відома користувачів отримувати від них інформацію і передавати стороннім особам. Тож в андроїд 6 та вище необхідно додатково писати код, який би запитував користувача про надання доступу. Зокрема необхідно запитувати дозвіл на доступ до камери, списку контактів, місця розташування тощо. При чому дозволи діляться на групи, якщо ви запитали доступ на читання зовнішньої сховища даних, то вам автоматично дається дозвіл на запис до цього сховища. Крім того самі дозволи діляться на нормальні та небезпечні. Нормальні не несуть небезпеки конфіденційності користувачу.

Для отримання дозволу, які класифіковані як небезпечні, необхідно зробити декілька кроків:
1) Перевірити чи раніше не був даний такий доступ
2) Якщо доступ не надано, то запитати користувача
3) Перевизначити метод onRequestPermissionsResult(), який би перевіряв чи користувач прийняв запит чи відхилив і в залежності від того здійснити подальші дії.

Такі дії необхідно виконувати, якщо targetSdkVersion 23 або вище. Якщо цільова версія нижче 23, то ці програми працюють як раніше на новіших версіях андроїда. Щоправда, гугл плей зараз настійливо рекомендує націлювати програми на останні версії андроїда.

При написанні програми в маніфесті, як і раніше необхідно вказувати відповідні рядки з uses-permission.

Допустимо необхідно написати програму для доступу до контактів та камери користувача. Для цього зробимо просту активність із двома кнопками "Контакти" та "Камера":



Про створення активностей, та роботу з кнопками для андроїд див. Activity (Android).

Перевірити дозвіл і вразі відсутності запитати користувача про надання можна наступним чином:
        
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED)
        {

            ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_CONTACTS},
                    MY_PERMISSION_REQUEST_READ_CONTACTS);
        }else{
            readContacts();
        }
MY_PERMISSION_REQUEST_READ_CONTACTS – константа, яку визначає програміст і яку використовують для подальшого відслідковування вибору користувача чи за даним запитом користувач здійснював певні дії. Константі значення призначають довільно, наприклад, так:
private static final int MY_PERMISSION_REQUEST_READ_CONTACTS = 10;


Цього достатньо, щоб програма запитувала користувача про дозвіл, як це зображено на рисунку
.  
Після натиснення кнопки "відхилити", при повторному зверненні буде виведене вікно із схожим запитом, але вже із можливістю запам'ятати вибір. Якщо користувач не надасть дозвіл? тоді йому необхідно згодом вручну надавати дозвіл через налаштування андроїда.

Написання вищенаведеного коду цілком достатньо, якщо ж ми хочемо додати користувачу додаткову інформацію про те, навіщо необхідний дозвіл, то це можна зробити перевизначивши метод onRequestPermissionsResult().

Перевизначений метод onRequestPermissionsResult() може виглядати таким чином:
 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case MY_PERMISSION_REQUEST_READ_CONTACTS:
                if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    readContacts();
                }else{
                    if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)){
                       new AlertDialog.Builder(this).
                               setTitle("Read contact permission").
                               setMessage("You need to grant read contacts permission to use read"+
                               "read contacts feature. Retry and grant it!").show();

                    }else{

                        new AlertDialog.Builder(this).
                                setTitle("Read contact permission denied").
                                setMessage("You denied read contacts. Please grant it in settings!").show();
                    }
                }
                break;
            case MY_PERMISSION_REQUEST_CAMERA:
                // модифікований код аналогічний попередньому case
            break;
        }

    }
Метод буде викликаний після відповідного запиту до користувача методом requestPermission(), по requestCode ми можемо перевірити, на який запит було отримано відповідь. В даному випадку перевіряємо чи це MY_PERMISSION_REQUEST_READ_CONTACTS. Якщо ми надсилали інші запити, то можна додати інші гілки перевірки в оператор case за відповідними іншими кодами.

В результаті користувач отримає такі повідомлення, якщо він натисне кнопку "відхилити":

Повний код прикладу (MainActivity.java):
package com.example.nisona.testpermision;

import android.Manifest;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private static final int MY_PERMISSION_REQUEST_READ_CONTACTS = 10;
    private static final int MY_PERMISSION_REQUEST_CAMERA = 11;
    private Button btn;
    private Button btn2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn = (Button) findViewById(R.id.contact_button);
        btn2 = (Button) findViewById(R.id.camera_button);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                manageBtnContactClick();

            }
        });
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                manageBtnCameraClick();

            }
        });
    }



    private void manageBtnContactClick() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED)
        {

            ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_CONTACTS},
                    MY_PERMISSION_REQUEST_READ_CONTACTS);
        }else{
            readContacts();
        }
    }

    private void readContacts() {
        Toast.makeText(this,"Read contacts", Toast.LENGTH_LONG).show();
    }

    private void manageBtnCameraClick() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED)
        {

            ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.CAMERA},
                    MY_PERMISSION_REQUEST_CAMERA);
        }else{
            readCamera();
        }
    }

    private void readCamera() {
        Toast.makeText(this,"Camera ready!", Toast.LENGTH_LONG).show();
    }



    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case MY_PERMISSION_REQUEST_READ_CONTACTS:
                if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    readContacts();
                }else{
                    if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)){
                       new AlertDialog.Builder(this).
                               setTitle("Read contact permission").
                               setMessage("You need to grant read contacts permission to use read"+
                               "read contacts feature. Retry and grant it!").show();

                    }else{

                        new AlertDialog.Builder(this).
                                setTitle("Read contact permission denied").
                                setMessage("You denied read contacts. Please grant it in settings!").show();
                    }
                }
                break;
            case MY_PERMISSION_REQUEST_CAMERA:
                // модифікований код, аналогічний попередньому case
            break;
        }

    }
}

В даному коді, якщо доступ не наданий, то буде виведено відповідне повідомлення, що необхідно надати доступ. Якщо користувач відмовився надавати при повторному зверненні доступ, то буде виведене повідомлення, що ви не надали відповідного доступу. Тоді для коректного функціонування програми потрібно буде зайти в налаштування програми (через налаштування андроїду/програмні засоби) для включення відповідного доступу або там же можна виключити доступ, в разі потреби. .Також є невеликі відмінності при виклику методів із фрагментів, а не з активності, але принцип залишається той же. Даний приклад наведений при подачі запиту на дозвіл із активності.

При написанні програми за основу взятий наступний відеоурок:
* Manage Permissions on Android Marshmallow

Немає коментарів:

Дописати коментар