Когда запрашивать разрешение во время выполнения для Android Marshmallow 6.0?

Я тестирую свое приложение на Marshmallow 6.0, и оно принудительно закрывается для android.permission.READ_EXTERNAL_STORAGE, даже если оно уже определено в манифесте. Где-то я читал, что если я запрошу разрешение во время выполнения, это не приведет к принудительному закрытию вашего приложения. Я также прочитал этот документ для Android, который предназначен для запроса разрешение времени выполнения.

Итак, я узнал, что мы можем запросить разрешение, как показано ниже, которое упоминается в документе Android.

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

В приведенном выше коде есть метод обратного вызова onRequestPermissionsResult, который получает результат.

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {

     }
}

Мой вопрос: где именно запрашивать разрешение у пользователя? Должны ли мы использовать запрос разрешения при запуске приложения или мы должны делать это так же, как когда требуется разрешение?


person Pankaj    schedule 08.12.2015    source источник
comment
Посмотрите это видео: youtu.be/iZqDdvhTZj0. В нем описаны некоторые рекомендации.   -  person Thomas R.    schedule 08.12.2015
comment
сделать это, как когда требуется разрешение. Кроме того, проверьте разрешение l-o-c в манифесте для M; <uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE" />   -  person Pararth    schedule 08.12.2015
comment
Поэтому запрос разрешения, когда это необходимо, является лучшей практикой.   -  person Pankaj    schedule 08.12.2015
comment
Попробуйте это, это может сработать stackoverflow.com/a/41221852/5488468   -  person Bipin Bharti    schedule 03.01.2017
comment
также см. этот stackoverflow.com/a/41978011/3496570   -  person AndroidGeek    schedule 01.02.2017
comment
Отвечает ли это на ваш вопрос? Разрешение запроса зефира Android?   -  person Josh Correia    schedule 10.07.2020


Ответы (10)


В общем, запрашивайте необходимые разрешения, как только они вам понадобятся. Таким образом, вы можете сообщить пользователю, почему вам нужно разрешение, и обрабатывать отказы в разрешении намного проще.

Подумайте о сценариях, в которых пользователь отменяет разрешение во время работы вашего приложения: если вы запрашиваете его при запуске и никогда не проверяете его позже, это может привести к непредвиденному поведению или исключениям.

person Jörn Buitink    schedule 08.12.2015
comment
Итак, вы говорите, что я должен запрашивать разрешение, когда нам нужно, а не при запуске. - person Pankaj; 08.12.2015
comment
Да. Вы не знаете, отменяет ли пользователь разрешение во время выполнения вашего приложения. - person Jörn Buitink; 08.12.2015

Это сработало для меня !!! В Your Splash Activity вашего приложения сделайте следующее:

1) Объявить переменную int для кода запроса,

private static final int REQUEST_CODE_PERMISSION = 2;

2) Объявите массив строк с нужным вам количеством разрешений,

 String[] mPermission = {Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS,
 Manifest.permission.ACCESS_FINE_LOCATION,
 Manifest.permission.WRITE_EXTERNAL_STORAGE};

3) Затем проверьте условие для разрешения времени выполнения для вашего метода onCreate,

try {
            if (ActivityCompat.checkSelfPermission(this, mPermission[0])
                    != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[1])
                            != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[2])
                            != MockPackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.checkSelfPermission(this, mPermission[3])
                            != MockPackageManager.PERMISSION_GRANTED) {

                ActivityCompat.requestPermissions(this,
                        mPermission, REQUEST_CODE_PERMISSION);

              // If any permission aboe not allowed by user, this condition will execute every tim, else your else part will work
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

4) Теперь объявите метод onRequestPermissionsResult для проверки кода запроса,

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        Log.e("Req Code", "" + requestCode);
        if (requestCode == REQUEST_CODE_PERMISSION) {
            if (grantResults.length == 4 &&
                    grantResults[0] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[1] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[2] == MockPackageManager.PERMISSION_GRANTED &&
                    grantResults[3] == MockPackageManager.PERMISSION_GRANTED) {

               // Success Stuff here

            }
        }

    }
person Nanda Gopal    schedule 27.01.2016
comment
Не получил ваш код, который вы говорите, делайте свои вещи здесь в двух местах. Должно быть только одно место, чтобы заниматься своими делами, а не в два, и как будет называться onRequestPermissionsResult??? - person Pankaj; 27.01.2016
comment
Извините за это, просто введите код в onRequestPermissionResult, а затем сообщите мне результат - person Nanda Gopal; 27.01.2016

Сделайте так

private static final int  REQUEST_ACCESS_FINE_LOCATION = 111;

В вашем onCreate

boolean hasPermissionLocation = (ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
    if (!hasPermissionLocation) {
        ActivityCompat.requestPermissions(ThisActivity.this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_ACCESS_FINE_LOCATION);
    }

затем проверьте результат

   @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode)
    {

        case REQUEST_ACCESS_FINE_LOCATION: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(ThisActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();

                //reload my activity with permission granted
                finish();
                startActivity(getIntent());

            } else
            {
                Toast.makeText(ThisActivity.this, "The app was not allowed to get your location. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
            }
        }

    }

}
person Tharindu Bandara    schedule 12.10.2016

На мой взгляд, нет единственно правильного ответа на ваш вопрос. Я настоятельно рекомендую вам ознакомиться с этой официальной страницей шаблонов разрешений.

Пара вещей, предложенных Google:

«Ваша стратегия разрешений зависит от ясности и важности типа разрешения, которое вы запрашиваете. Эти шаблоны предлагают разные способы предоставления разрешений пользователю».

«Важные разрешения следует запрашивать заранее. Второстепенные разрешения могут запрашиваться в контексте».

«Разрешения, которые менее ясны, должны информировать о том, что включает в себя разрешение, независимо от того, делается ли оно заранее или в контексте».

Эта иллюстрация может помочь вам лучше понять.

Возможно, наиболее важным моментом здесь является то, запрашиваете ли вы разрешение заранее или в контексте, вы всегда должны помнить, что эти разрешения могут быть отозваны пользователем в любое время (например, ваше приложение все еще работает в фоновом режиме).

Вы должны убедиться, что ваше приложение не падает только потому, что вы запросили разрешение в самом начале приложения и предположили, что пользователь не изменил свои предпочтения в отношении этого разрешения.

person Can Elmas    schedule 09.12.2015
comment
это тоже мое мнение, нет правильного аунсера на этот вопрос, ребята из ux должны решить это в зависимости от продукта - person xanexpt; 26.02.2016

Для запроса разрешения во время выполнения я использую GitHub Library

Добавить библиотеку в Build.gradle файл

dependencies {
     compile 'gun0912.ted:tedpermission:1.0.3'
}

Создайте действие и добавьте PermissionListener

public class MainActivity extends AppCompatActivity{

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);



    PermissionListener permissionlistener = new PermissionListener() {
        @Override
        public void onPermissionGranted() {
            Toast.makeText(RationaleDenyActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
            //Camera Intent and access Location logic here
        }

        @Override
        public void onPermissionDenied(ArrayList<String> deniedPermissions) {
            Toast.makeText(RationaleDenyActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
        }
    };


    new TedPermission(this)
            .setPermissionListener(permissionlistener)
            .setRationaleTitle(R.string.rationale_title)
            .setRationaleMessage(R.string.rationale_message) // "we need permission for access camera and find your location"
            .setDeniedTitle("Permission denied")
            .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
            .setGotoSettingButtonText("Settings")
            .setPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            .check();
   }
}

строка.xml

<resources>

    <string name="rationale_title">Permission required</string>
    <string name="rationale_message">we need permission for read <b>camera</b> and find your <b>location</b></string>

</resources>
person Android Player_Shree    schedule 10.07.2017

Хорошее объяснение и HowTo можно найти здесь:

https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en

Я написал этот код для проверки и запроса разрешений во время выполнения в BaseActivity.class, который является родительским для каждого другого Activity.class, который я реализовал:

public static final int PERMISSION_REQUEST = 42;
public static final int MULTIPLE_PERMISSION_REQUEST = 43;

//Marshmallow Permission Model
public boolean requestPermission(String permission /* Manifest.permission...*/) {
    if (ContextCompat.checkSelfPermission(this,
            permission) != PackageManager.PERMISSION_GRANTED) {
        if (Utils.hasMarshmallow())
            ActivityCompat.requestPermissions(this,
                    new String[]{permission}, PERMISSION_REQUEST
            );
        else {
            requestPermissions(new String[]{permission},
                    PERMISSION_REQUEST);
        }
        return false;
    } else {
        return true;
    }
}

public boolean requestPermission(String... permissions) {
    final List<String> permissionsList = new ArrayList<String>();

    for (String perm : permissions) {
        addPermission(permissionsList, perm);
    }

    if (permissionsList.size() > 0) {
        if (Utils.hasMarshmallow())
            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                    MULTIPLE_PERMISSION_REQUEST);
        else
            ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[permissionsList.size()]),
                    MULTIPLE_PERMISSION_REQUEST);
        return false;
    } else
        return true;
}


private boolean addPermission(List<String> permissionsList, String permission) {
    if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
        permissionsList.add(permission);
        // Check for Rationale Option
        if (Utils.hasMarshmallow())
            if (!shouldShowRequestPermissionRationale(permission))
                return false;
    }
    return true;
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST:
        case MULTIPLE_PERMISSION_REQUEST: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

Просто пример вызова:

activity.requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);

Результат возврата сообщит вам, предоставлено ли разрешение уже или нет.

person Spektakulatius    schedule 20.06.2016

вызывая эту функцию, мы можем позволить пользователю открыть диалоговое окно для запроса разрешения на разрешение камеры и записи звука.

    if ( ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CAMERA) ||
            ActivityCompat.shouldShowRequestPermissionRationale (this,
                    Manifest.permission.RECORD_AUDIO) ) {
        Toast.makeText (this,
                R.string.permissions_needed,
                Toast.LENGTH_LONG).show ();
    } else {
        ActivityCompat.requestPermissions (
                this,
                new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
                CAMERA_MIC_PERMISSION_REQUEST_CODE);
    }
person Deepika kapila    schedule 23.09.2016

https://material.io/guidelines/patterns/permissions.html Эта ссылка будет дать вам другой тип сценария, где разрешения могут быть запрошены. Выберите в соответствии с вашими потребностями.

person Abhigyan    schedule 09.06.2017

Мне нравится короткий код. Я использую RxPermission для разрешений.

RxPermission — лучшая библиотека, которая делает код разрешения неожиданным всего в 1 строку.

RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
.request(Manifest.permission.CAMERA,
         Manifest.permission.READ_PHONE_STATE) // ask single or multiple permission once
.subscribe(granted -> {
    if (granted) {
       // All requested permissions are granted
    } else {
       // At least one permission is denied
    }
});

добавьте в свой build.gradle

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

dependencies {
    implementation 'com.github.tbruyelle:rxpermissions:0.10.1'
    implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
}

Разве это не легко?

person Khemraj Sharma    schedule 10.07.2018

person    schedule
comment
Вам не хватает комментариев к вашему коду, что вы делаете по-другому в своем ответе? и ваш предыдущий ответ? - person not2qubit; 18.01.2017