Как мы отличаем никогда не запрашиваемый от стоп-запроса в разрешениях Android M во время выполнения?
Что касается разрешений на выполнение M Developer Preview, согласно Google:
Если вы никогда не просили определенного разрешения, просто попросите его
Если вы спрашивали ранее, и пользователь сказал "нет", а затем пользователь пытается сделать что-то, что требует отклоненного разрешения, вы должны попросить пользователя объяснить, почему вам нужно разрешение, прежде чем вы продолжите запрашивать разрешение снова.
Если вы спрашивали пару раз раньше, и пользователь сказал "нет, и прекратить спрашивать" (с помощью флажка в диалоговом окне разрешения времени выполнения), вам следует просто прекратить беспокоиться (например, отключить пользовательский интерфейс, требующий разрешения)
Тем не менее, у нас есть только один метод, shouldShowRequestPermissionRationale()
, возвращая boolean
и у нас есть три государства. Нам нужен способ отличить состояние никогда не спрашивается от состояния остановки спрашивая, как мы получаем false
от shouldShowRequestPermissionRationale()
для обоих.
Для разрешений, запрашиваемых при первом запуске приложения, это не является большой проблемой. Существует множество рецептов для определения того, что это, вероятно, первый запуск вашего приложения (например, boolean
значение в SharedPreferences
), и поэтому вы предполагаете, что, если это первый запуск вашего приложения, вы находитесь в состоянии "никогда не спрашивать".
Тем не менее, часть видения разрешений во время выполнения состоит в том, что вы можете не запрашивать все из них заранее. Разрешения привязаны к дополнительным функциям, которые вы можете запрашивать только позже, когда пользователь нажимает на то, что требует этого разрешения. Здесь приложение могло запускаться много раз, в течение нескольких месяцев, прежде чем мы внезапно должны запросить другое разрешение.
В этих случаях мы должны отслеживать, запрашивали ли мы разрешение сами или нет? Или в Android M API что-то отсутствует, что говорит нам, спрашивали мы раньше или нет?
11 ответов
Согласно текущему примеру: https://github.com/googlesamples/android-RuntimePermissions/blob/master/Application/src/main/java/com/example/android/system/runtimepermissions/MainActivity.java#L195
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
if (requestCode == REQUEST_CAMERA) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
doThing();
//STORE FALSE IN SHAREDPREFERENCES
} else {
//STORE TRUE IN SHAREDPREFERENCES
}
}
Сохраните логическое значение в SharedPreferences, указав в качестве кода разрешения ключ и значение, как указано выше, чтобы указать, было ли ранее отклонено это предпочтение.
К сожалению, вы, вероятно, не можете проверить предпочтения, которые были приняты, а затем отклонены во время работы вашего приложения. Окончательная спецификация недоступна, но есть вероятность, что ваше приложение либо перезапустится, либо получит фиктивные значения до следующего запуска.
Я знаю, что я публикую очень поздно, но подробный пример может быть полезен для кого-то.
Что я заметил, так это то, что если мы проверяем флаг mustShowRequestPermissionRationale() в методе обратного вызова onRequestPermissionsResult(), он показывает только два состояния.
Состояние 1:-Возврат истины: - Каждый раз, когда пользователь нажимает кнопку "Запретить" (включая самый первый раз).
Состояние 2:- Возвращает false:- если пользователь выбирает s, "никогда больше не спрашивает.
Вот пример с несколькими запросами на разрешение:
При запуске приложению необходимо 2 разрешения. SEND_SMS и ACCESS_FINE_LOCATION (оба упомянуты в manifest.xml).
Как только приложение запускается, оно запрашивает несколько разрешений вместе. Если оба разрешения предоставлены, нормальный поток идет.
public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(checkAndRequestPermissions()) {
// carry on the normal flow, as the case of permissions granted.
}
}
private boolean checkAndRequestPermissions() {
int permissionSendMessage = ContextCompat.checkSelfPermission(this,
Manifest.permission.SEND_SMS);
int locationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
List<String> listPermissionsNeeded = new ArrayList<>();
if (locationPermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (permissionSendMessage != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.SEND_SMS);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
В случае, если одно или несколько разрешений не предоставлены, activityCompat.requestPermissions() запросит разрешения, и элемент управления перейдет к методу обратного вызова onRequestPermissionsResult().
Вы должны проверить значение флага shouldShowRequestPermissionRationale() в методе обратного вызова onRequestPermissionsResult().
Есть только два случая:
Случай 1:- Каждый раз, когда пользователь нажимает кнопку "Запретить" (включая самый первый раз), он возвращает значение "истина". Поэтому, когда пользователь отказывает, мы можем показать больше объяснений и продолжать спрашивать снова.
Случай 2:-Только если пользователь выберет "никогда больше не спрашивать", он вернет false. В этом случае мы можем продолжить работу с ограниченными функциональными возможностями и направлять пользователя для активации разрешений из настроек для получения дополнительных функциональных возможностей, или мы можем завершить настройку, если разрешения для приложения тривиальны.
СЛУЧАЙ 1
ДЕЛО- 2
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
Log.d(TAG, "Permission callback called-------");
switch (requestCode) {
case REQUEST_ID_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<>();
// Initialize the map with both permissions
perms.put(Manifest.permission.SEND_SMS, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0) {
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for both permissions
if (perms.get(Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "sms & location services permission granted");
// process the normal flow
//else any one or both the permissions are not granted
} else {
Log.d(TAG, "Some permissions are not granted ask again ");
//permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
// // shouldShowRequestPermissionRationale will return true
//show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.SEND_SMS) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
showDialogOK("SMS and Location Services Permission required for this app",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
case DialogInterface.BUTTON_NEGATIVE:
// proceed with logic by disabling the related features or quit the app.
break;
}
}
});
}
//permission is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else {
Toast.makeText(this, "Go to settings and enable permissions", Toast.LENGTH_LONG)
.show();
// //proceed with logic by disabling the related features or quit the app.
}
}
}
}
}
}
private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show();
}
Нет, вам не нужно отслеживать, запрашивали ли вы разрешение или нет, и вам не нужно отличать Никогда не спрашивал от Stop-Asking.
Состояния 1 и 3 одинаковы для разработчика приложений: вам нужно разрешение и ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED
тогда вы просто спрашиваете разрешение через ActivityCompat.requestPermissions()
всякий раз, когда пользователь нажимает на функцию, которая требует разрешения, независимо от того, сколько раз вы запрашивали. В конечном итоге пользователь "предоставит" или "отклонит", отметив "никогда больше не спрашивать". Дизайн НЕ отговаривает вас от всплывающего диалогового окна запроса разрешения несколько раз.
Тем не менее, дизайн рекомендует вам объяснить цель разрешения в какой-то момент - ваше состояние 2. shouldShowRequestPermissionRationale()
НЕ используется, чтобы определить, следует ли вам запрашивать разрешение, он используется для определения необходимости показывать объяснения, ДО того, как вы запросите разрешение.
Еще пара объяснений относительно состояния 3:
- Да, мы должны перестать беспокоить пользователя, прекратив показывать объяснение, а не останавливать запрос. Вот почему они предоставили
shouldShowRequestPermissionRationale()
, - Это не мешает держать запрос на разрешение. После того, как пользователь выбрал "никогда не спрашивать",
ActivityCompat.requestPermissions()
больше не будет всплывающего диалогового окна. - Лучше отключать соответствующий интерфейс каждый раз, когда мы обнаруживаем, что у нас нет разрешения, во время однопользовательской сессии. Вместо того, чтобы отключить интерфейс после
shouldShowRequestPermissionRationale()
вернуть ложь.
У меня есть подход к решению вашей проблемы, мне кажется, он работает очень хорошо.
Я отличаю никогда не задаваемый вопрос от стоп-запроса, используя SharedPreferences, я дам вам пример того, как я это использую.
private void requestAccountPermission() {
SharedPreferences mPreferences = getSharedPreferences("configuration", MODE_PRIVATE);
boolean firstTimeAccount = mPreferences.getBoolean("firstTimeAccount", true);
if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.GET_ACCOUNTS)) {
// 2. Asked before, and the user said "no"
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.GET_ACCOUNTS}, REQUEST_CODE_ACCOUNTS);
}else {
if(firstTimeAccount) {
// 1. first time, never asked
SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean("firstTimeAccount", false);
editor.commit();
// Account permission has not been granted, request it directly.
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.GET_ACCOUNTS},REQUEST_CODE_ACCOUNTS);
}else{
// 3. If you asked a couple of times before, and the user has said "no, and stop asking"
// Your code
}
}
}
После нескольких дней биения головой о стену я смог это сделать с помощью нового API-интерфейса Jetpack Compose.
Чтобы отличить состояние «никогда не спрашивать» от состояния «никогда не спрашивать снова», вы можете отслеживать значения и .
Пользователь (полностью) отклонил разрешение, если:
- текущая стоимость сейчас
false
и раньше былоtrue
И
текущая стоимостьisGranted
ложно
мы можем отслеживать стоимостьshouldShowRationale
используяmutableStateOf
иLaunchedEffect
.
// Boolean state variable to track if shouldShowRationale changed from true to false
var shouldShowRationaleBecameFalseFromTrue by remember { mutableStateOf(false) }
// Remember the previous value of shouldShowRationale
var prevShouldShowRationale by remember { mutableStateOf(bluetoothPermissionState.status.shouldShowRationale) }
// Track changes in shouldShowRationale
LaunchedEffect(bluetoothPermissionState.status.shouldShowRationale) {
if (prevShouldShowRationale && !bluetoothPermissionState.status.shouldShowRationale) {
shouldShowRationaleBecameFalseFromTrue = true
}
prevShouldShowRationale = bluetoothPermissionState.status.shouldShowRationale
}
// if shouldShowRationale changed from true to false and the permission is not granted,
// then the user denied the permission and checked the "Never ask again" checkbox
val userDeniedPermission =
shouldShowRationaleBecameFalseFromTrue && !bluetoothPermissionState.status.isGranted
возьмем пример из библиотеки аккомпаниатора :
@OptIn(ExperimentalPermissionsApi::class)
@Composable
private fun FeatureThatRequiresCameraPermission() {
// Camera permission state
val cameraPermissionState = rememberPermissionState(
android.Manifest.permission.CAMERA
)
if (cameraPermissionState.status.isGranted) {
Text("Camera permission Granted")
} else {
Column {
val textToShow = if (cameraPermissionState.status.shouldShowRationale) {
// If the user has denied the permission but the rationale can be shown,
// then gently explain why the app requires this permission
"The camera is important for this app. Please grant the permission."
} else {
// If it's the first time the user lands on this feature, or the user
// doesn't want to be asked again for this permission, explain that the
// permission is required
"Camera permission required for this feature to be available. " +
"Please grant the permission"
}
Text(textToShow)
Button(onClick = { cameraPermissionState.launchPermissionRequest() }) {
Text("Request permission")
}
}
}
}
давайте изменим его с помощью нашей реализации:
@OptIn(ExperimentalPermissionsApi::class)
@Composable
private fun FeatureThatRequiresBluetoothPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return
// Bluetooth permission state
val bluetoothPermissionState = rememberPermissionState(
Manifest.permission.BLUETOOTH_CONNECT
)
// Boolean state variable to track if shouldShowRationale changed from true to false
var shouldShowRationaleBecameFalseFromTrue by remember { mutableStateOf(false) }
// Remember the previous value of shouldShowRationale
var prevShouldShowRationale by remember { mutableStateOf(bluetoothPermissionState.status.shouldShowRationale) }
// Track changes in shouldShowRationale
LaunchedEffect(bluetoothPermissionState.status.shouldShowRationale) {
if (prevShouldShowRationale && !bluetoothPermissionState.status.shouldShowRationale) {
shouldShowRationaleBecameFalseFromTrue = true
}
prevShouldShowRationale = bluetoothPermissionState.status.shouldShowRationale
}
// if shouldShowRationale changed from true to false and the permission is not granted,
// then the user denied the permission and checked the "Never ask again" checkbox
val userDeniedPermission =
shouldShowRationaleBecameFalseFromTrue && !bluetoothPermissionState.status.isGranted
if (userDeniedPermission) {
Text(
"You denied the permission, in order for the app to work properly you need to grant the permission manually." +
"Open the app settings and grant the permission manually."
)
return
}
if (bluetoothPermissionState.status.isGranted) {
Text("Bluetooth permission Granted")
} else {
Column {
val textToShow = if (bluetoothPermissionState.status.shouldShowRationale) {
// If the user has denied the permission but the rationale can be shown,
// then gently explain why the app requires this permission
"The bluetooth is important for this app. Please grant the permission."
} else {
// If it's the first time the user lands on this feature, or the user
// doesn't want to be asked again for this permission, explain that the
// permission is required
"Bluetooth permission required for this feature to be available. " +
"Please grant the permission"
}
Text(textToShow)
Button(onClick = { bluetoothPermissionState.launchPermissionRequest() }) {
Text("Request permission")
}
}
}
}
и все это в рамках одного составного компонента, который может запрашивать разрешения, прослушивать изменения разрешений и реагировать на их изменения. Работайте как шарм:
теперь пользователю будет предложено перейти к настройкам и изменить разрешение вручную всякий раз, когда он отказывает в разрешении слишком много раз.
Вот метод для отслеживания того, когда диалоговое окно разрешений было показано впервые, когда пользователь установил флажок никогда больше не запрашивать, и когда в разрешении прямо отказано после того, как проверенный пользователь больше никогда не запрашивал это, нам нужно сохранить флаг, если перед разрешением показывался диалог обоснования разрешений. результат в onRequestPermissionsResult. Вызвать метод checkPermission() при необходимости.
public boolean mPermissionRationaleDialogShown = false;
public void checkPermission() {
if (ContextCompat.checkSelfPermission(this, "PermissionName")
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")) {
showPermissionRequiredDialog();
} else {
askPermission();
}
} else {
// Permission Granted
}
}
public void askPermission() {
ActivityCompat.requestPermissions(this,
new String[]{"PermissionName"}, permissionRequestCode);
}
public void showPermissionRequiredDialog() {
mPermissionRationaleDialogShown = true;
// Dialog to show why permission is required
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")
&& !mPermissionRationaleDialogShown) {
// Permission dialog was shown for first time
} else if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")
&& mPermissionRationaleDialogShown){
// User deny permission without Never ask again checked
} else if (!ActivityCompat.shouldShowRequestPermissionRationale(this, PERMISSION_READ_EXTERNAL)
&& mPermissionRationaleDialogShown) {
// User has checked Never ask again during this permission request
} else {
// No permission dialog shown to user has user has previously checked Never ask again. Here we can show dialog to open setting screen to change permission
}
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
Перепробовав все ответы здесь и какой-то другой пост через интернет. Я узнал, что я должен использовать sharedPreference isLocationPermissionDialogShown
(по умолчанию false), и все работает в соответствии с ожиданиями.
- Если первый раз попросил разрешения. В этом случае
shouldShowRequestPermissionRationale
возвращаетсяfalse
а такжеisLocationPermissionDialogShown
такжеfalse
- Второй раз
shouldShowRequestPermissionRationale
вернутьtrue
и пока показываем диалог мы устанавливаемisLocationPermissionDialogShown
вtrue
, и когда мы проверим условие, оба будутtrue
- Каждый раз, пока Никогда не спрашивай снова отмечен
shouldShowRequestPermissionRationale
вернутьtrue
а такжеisLocationPermissionDialogShown
возвращаетсяtrue
- Если Никогда не спрашивай снова галочкой
shouldShowRequestPermissionRationale
вернутьfalse
а такжеisLocationPermissionDialogShown
возвращаетсяtrue
, Что нам и нужно.
Пожалуйста, проверьте рабочий пример.
public class MainActivity extends AppCompatActivity {
SharedPreferences sharedPreferences;
String locationPermission;
String prefLocationPermissionKey = "isLocationPermissionDialogShown";
private final int PERMISSION_REQUEST_CODE_LOCATION = 1001;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationPermission = Manifest.permission.ACCESS_FINE_LOCATION;
sharedPreferences = getSharedPreferences("configuration", MODE_PRIVATE);
//check for android version
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Check for permission
if (checkSelfPermission(locationPermission) != PackageManager.PERMISSION_GRANTED) {
//check if clarification dialog should be shown.
if (shouldShowRequestPermissionRationale(locationPermission)) {
showClarificationDialog(locationPermission, PERMISSION_REQUEST_CODE_LOCATION);
} else {
requestPermissions(new String[] { locationPermission}, PERMISSION_REQUEST_CODE_LOCATION);
}
} else {
Log.d("nets-debug", "permission already grranted");
}
}
}
@Override
@TargetApi(Build.VERSION_CODES.M)
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
//for location permission
if (requestCode == PERMISSION_REQUEST_CODE_LOCATION) {
boolean isLocationPermissionDialogShown = sharedPreferences.getBoolean(prefLocationPermissionKey, false);
if (!shouldShowRequestPermissionRationale(locationPermission) && isLocationPermissionDialogShown) {
// user selected Never Ask Again. do something
Log.d("nets-debug", "never ask again");
} else {
// all other conditions like first time asked, previously denied etc are captured here and can be extended if required.
Log.d("nets-debug", "all other cases");
}
}
}
}
@TargetApi(Build.VERSION_CODES.M)
public void showClarificationDialog(final String permission, final int requestCode) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Permission Required");
builder.setMessage("Please grant Location permission to use all features of this app");
builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(prefLocationPermissionKey, true);
editor.apply();
requestPermissions(new String[] {permission}, requestCode);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getApplicationContext(), "This permission required", Toast.LENGTH_LONG).show();
}
});
builder.create().show();
}
}
Надеюсь, это поможет.
Что касается ответа MLProgrammer-CiM, у меня есть представление о том, как решить сценарий, в котором пользователь отменяет разрешение после того, как логическое значение, хранящееся в SharedPrefrences, уже истинно,
просто создайте еще одну константу логического значения, если первая вызывается, например: Constant.FIRST_TIME_REQUEST
(состояние по умолчанию будет истинным), второй будет называться Constant.PERMISSION_ALREADY_GRANTED
(по умолчанию будет false)
На onRequestPermissionsResult
если разрешение было предоставлено, вы, конечно, измените его значение на true.
Теперь, в той части, где вы хотите спросить разрешения с предварительным объяснением, напишите что-нибудь вроде этого:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
SharedPreferences sp = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
boolean isPermissionGranted = sp.getBoolean(Constant.PERMISSION_ALREADY_GRANTED, false);
if (isPermissionGranted) {
sp.putBoolean(Constant.PERMISSION_ALREADY_GRANTED, false);
sp.putBoolean(Constant.FIRST_TIME_REQUEST, true);
}
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, androidPermissionName) || sp.getBoolean(Constant.FIRST_TIME_REQUEST, true) ) {
showDialogExplanation();
}
}
таким образом, даже если пользователь удалит разрешение, логическое значение снова будет установлено в false.
удачи, надеюсь поможет.
Шло
НАКОНЕЦ, МОЕ ВРЕМЯ ПРИШЛО, ЧТОБЫ ОТВЕТИТЬ НА ВОПРОС ИЗ ОБЩЕГО ОБЕСПЕЧЕНИЯ
Бизнес поток:-
1. Когда пользователь впервые нажимает "Отказать в разрешении", я покажу диалоговое окно с обоснованием, чтобы объяснить необходимость разрешения. Затем, если пользователь нажмет кнопку "Отмена" в диалоговом окне обоснования, я покажу тост с сообщением "Пожалуйста, дайте разрешение на определение местоположения".
2. После этого, когда пользователь нажимает на запретить разрешение (больше не спрашивать) в диалоговом окне разрешений, я покажу сообщение "Пожалуйста, дайте разрешение на местоположение в настройках приложения". Обратите внимание, что я добавил слова "из настроек приложения", потому что пользователь установил флажок "больше не спрашивать".
3. Таким образом, с этого момента диалоговое окно разрешения не будет отображаться. Также не будет отображаться диалоговое окно с обоснованием.
Таким образом, ключевой момент здесь заключается в том, что, если диалоговое окно с разрешениями и обоснование не отображаются, это означает, что пользователь установил флажок "не спрашивать снова".
Код:-
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)){
AlertDialogHelper.showDialogWithYesNoCallback(mContext, getString(R.string.confirm), getString(R.string.please_give_permission_to_get_location), new onItemClickReturnBoolean() {
@Override
public void onItemClick(Boolean status) {
if(status){
ActivityCompat.requestPermissions(SplashScreenActivity.this,permissions,AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE);
}
else{
ShowToast.showShortToast(SplashScreenActivity.this,getString(R.string.please_give_permission_to_get_location));
finish();
}
}
});
}
else{
ActivityCompat.requestPermissions(this,permissions,AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE);
}
}
else{
gettingLocationAfterPermissionGranted();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE){
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
gettingLocationAfterPermissionGranted();
}
else{
if(ActivityCompat.shouldShowRequestPermissionRationale(SplashScreenActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)){
ShowToast.showShortToast(this,getString(R.string.please_give_permission_to_get_location));
}
else{
ShowToast.showShortToast(this,getString(R.string.please_give_location_permission_from_app_settings));
}
finish();
}
}
}
Проверьте этот репозиторий: https://github.com/debChowdhury/PermissionHelperEasy
Easy peasy
Вы можете посмотреть здесь - есть блок-схема, которая объясняет процесс довольно хорошо. Это также объясняет, когда вы должны позвонить shouldShowRequestPermissionRationale()
и когда он возвращает истину.
В основном, согласно документации Android, вы всегда должны запрашивать разрешение, если у вас его нет (Android автоматически вернет DENIED при обратном вызове, если пользователь сказал, что никогда больше не спрашивать), и вы должны отобразить короткое сообщение, если пользователь уже отклонил Вы когда-то в прошлом, но не отметили вариант никогда не спрашивать.
Нет необходимости создавать параллельное постоянное состояние для состояния разрешения, вы можете просто использовать этот метод, который возвращает текущее состояние разрешения в любое время:
@Retention(RetentionPolicy.SOURCE)
@IntDef({GRANTED, DENIED, BLOCKED})
public @interface PermissionStatus {}
public static final int GRANTED = 0;
public static final int DENIED = 1;
public static final int BLOCKED = 2;
@PermissionStatus
public static int getPermissionStatus(Activity activity, String androidPermissionName) {
if(ContextCompat.checkSelfPermission(activity, androidPermissionName) != PackageManager.PERMISSION_GRANTED) {
if(!ActivityCompat.shouldShowRequestPermissionRationale(activity, androidPermissionName)){
return BLOCKED;
}
return DENIED;
}
return GRANTED;
}
Предупреждение: возвращает BLOCKED при первом запуске приложения до того, как пользователь принял / отклонил разрешение через приглашение пользователя (на устройствах sdk 23+)