prosource

Android M 권한 : showRequestPermissionRationale() 함수의 사용법이 헷갈립니다.

probook 2023. 8. 11. 22:24
반응형

Android M 권한 : showRequestPermissionRationale() 함수의 사용법이 헷갈립니다.

안드로이드 M의 새로운 Permissions 모델에 대한 공식 문서를 검토하고 있었습니다.그것은 그것에 대해 말합니다.shouldShowRequestPermissionRationale()을 반환하는 true앱이 이전에 이 권한을 요청했지만 사용자가 요청을 거부한 경우.옵션을 이는 " " " 를 반환합니다.false.

하지만 다음 두 경우를 어떻게 구별할 수 있을까요?

사례 1: 앱에 권한이 없으며 사용자에게 이전에 권한을 요청한 적이 없습니다.이 경우 ShowRequestPermissionRationale()가 false를 반환해야 합니다. 이는 사용자에게 처음 묻는 것이기 때문입니다.

사례 2: 사용자가 권한을 거부하고 "다시 묻지 않음"을 선택했습니다. 이 경우에도 ShowRequestPermissionRationale()가 false를 반환해야 합니다.

케이스 2의 앱 설정 페이지로 사용자를 보내고 싶습니다.이 두 사례를 어떻게 차별화합니까?

M Preview 1 이후에 대화 상자가 처음 표시되는 경우 Never ask again(다시 묻지 않음) 확인란이 없습니다.

사용자가 권한 요청을 거부하면 두 번째 권한이 요청될 때 권한 대화 상자에 다시 묻지 않음 확인란이 표시됩니다.

따라서 논리는 다음과 같아야 합니다.

  1. 요청 권한:

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
    } else {
        //Do the stuff that requires permission...
    }
    
  2. 사용 권한이 에서 거부 또는 허용되었는지 확인합니다.onRequestPermissionsResult.

    이전에 권한이 거부된 경우 이번에는 권한 대화 상자에 다시 묻지 않음 확인란이 표시됩니다.

    shouldShowRequestPermissionRationale다시 묻지 않음을 선택했는지 확인합니다.shouldShowRequestPermissionRationalemethod는 사용자가 다시 묻지 않음을 선택한 경우에만 false를 반환합니다. 또는 디바이스 정책이 앱에 해당 권한을 부여하지 못하도록 지정한 경우에만 false를 반환합니다.

    if (grantResults.length > 0){
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //Do the stuff that requires permission...
        }else if (grantResults[0] == PackageManager.PERMISSION_DENIED){
            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                //Show permission explanation dialog...
            }else{
                //Never ask again selected, or device policy prohibits the app from having that permission.
                //So, disable that feature, or fall back to another situation...
            }
        }
    }
    

따라서 사용자가 다시 묻지 않음을 선택했는지 여부를 추적할 필요가 없습니다.

저도 같은 문제를 가지고 있었고 그것을 알아냈습니다.삶을 훨씬 더 쉽게 만들기 위해 런타임 권한을 처리하는 util 클래스를 작성했습니다.

public class PermissionUtil {
    /*
    * Check if version is marshmallow and above.
    * Used in deciding to ask runtime permission
    * */
    public static boolean shouldAskPermission() {
        return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
    }
private static boolean shouldAskPermission(Context context, String permission){
        if (shouldAskPermission()) {
            int permissionResult = ActivityCompat.checkSelfPermission(context, permission);
            if (permissionResult != PackageManager.PERMISSION_GRANTED) {
                return true;
            }
        }
        return false;
    }
public static void checkPermission(Context context, String permission, PermissionAskListener listener){
/*
        * If permission is not granted
        * */
        if (shouldAskPermission(context, permission)){
/*
            * If permission denied previously
            * */
            if (((Activity) context).shouldShowRequestPermissionRationale(permission)) {
                listener.onPermissionPreviouslyDenied();
            } else {
                /*
                * Permission denied or first time requested
                * */
if (PreferencesUtil.isFirstTimeAskingPermission(context, permission)) {
                    PreferencesUtil.firstTimeAskingPermission(context, permission, false);
                    listener.onPermissionAsk();
                } else {
                    /*
                    * Handle the feature without permission or ask user to manually allow permission
                    * */
                    listener.onPermissionDisabled();
                }
            }
        } else {
            listener.onPermissionGranted();
        }
    }
/*
    * Callback on various cases on checking permission
    *
    * 1.  Below M, runtime permission not needed. In that case onPermissionGranted() would be called.
    *     If permission is already granted, onPermissionGranted() would be called.
    *
    * 2.  Above M, if the permission is being asked first time onPermissionAsk() would be called.
    *
    * 3.  Above M, if the permission is previously asked but not granted, onPermissionPreviouslyDenied()
    *     would be called.
    *
    * 4.  Above M, if the permission is disabled by device policy or the user checked "Never ask again"
    *     check box on previous request permission, onPermissionDisabled() would be called.
    * */
    public interface PermissionAskListener {
/*
        * Callback to ask permission
        * */
        void onPermissionAsk();
/*
        * Callback on permission denied
        * */
        void onPermissionPreviouslyDenied();
/*
        * Callback on permission "Never show again" checked and denied
        * */
        void onPermissionDisabled();
/*
        * Callback on permission granted
        * */
        void onPermissionGranted();
    }
}

그리고 PreferenceUtil 방법은 다음과 같습니다.

public static void firstTimeAskingPermission(Context context, String permission, boolean isFirstTime){
SharedPreferences sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE;
 sharedPreference.edit().putBoolean(permission, isFirstTime).apply();
 }
public static boolean isFirstTimeAskingPermission(Context context, String permission){
return context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE).getBoolean(permission, true);
}

이제 checkPermission 메서드를 적절한 인수와 함께 사용하기만 하면 됩니다.

여기 예가 있습니다.

PermissionUtil.checkPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    new PermissionUtil.PermissionAskListener() {
                        @Override
                        public void onPermissionAsk() {
                            ActivityCompat.requestPermissions(
                                    thisActivity,
              new String[]{Manifest.permission.READ_CONTACTS},
                            REQUEST_EXTERNAL_STORAGE
                            );
                        }
@Override
                        public void onPermissionPreviouslyDenied() {
                       //show a dialog explaining permission and then request permission
                        }
@Override
                        public void onPermissionDisabled() {
Toast.makeText(context, "Permission Disabled.", Toast.LENGTH_SHORT).show();
                        }
@Override
                        public void onPermissionGranted() {
                            readContacts();
                        }
                    });

사례 1: 앱에 권한이 없으며 사용자에게 이전에 권한을 요청한 적이 없습니다.이 경우 ShowRequestPermissionRationale()가 false를 반환해야 합니다. 이는 사용자에게 처음 묻는 것이기 때문입니다.

사례 2: 사용자가 권한을 거부하고 "다시 묻지 않음"을 선택했습니다. 이 경우에도 ShowRequestPermissionRationale()가 false를 반환해야 합니다.

케이스 2의 앱 설정 페이지로 사용자를 보내고 싶습니다.이 두 사례를 어떻게 차별화합니까?

사례 1에 대한 PermissionAsk와 사례 2에 대한 PermissionDisabled에 대한 콜백을 받을 수 있습니다.

해피 코딩 :)

제가 이해하는 바로는 ShowRequestPermissionRationale()가 후드 아래에서 여러 사용 사례를 실행하고, 요청된 권한에 대한 설명을 표시할지 여부를 앱에 알려야 합니다.

런타임 권한의 배경에는 대부분 사용자가 권한 요청에 예라고 대답한다는 개념이 있습니다.이렇게 하면 사용자가 한 번의 클릭만 하면 됩니다.물론 요청은 올바른 맥락에서 사용해야 합니다. 즉, "카메라" 버튼을 눌렀을 때 카메라 권한을 요청해야 합니다.

사용자가 요청을 거부했지만 시간이 지난 후 다시 "카메라" 버튼을 누르면 ShowRequestPermissionRationale()가 true로 반환되므로 앱에서 권한이 요청된 이유와 권한 없이는 앱이 제대로 작동하지 않는 이유에 대해 의미 있는 설명을 표시할 수 있습니다.일반적으로 해당 대화 상자 창에 다시 거부/나중에 결정하는 단추와 권한을 부여하는 단추를 표시합니다.이론적 근거 대화상자의 권한 부여 버튼은 권한 요청을 다시 시작해야 합니다.이번에는 "다시 표시 안 함" 확인란도 표시됩니다.만약 그가 그것을 선택하기로 결정하고 다시 권한을 거부한다면, 그것은 사용자와 앱이 같은 페이지에 있지 않다는 것을 안드로이드 시스템에 알릴 것입니다.이 작업은 두 가지 결과를 초래합니다. ShowRequestPermissionRationale()가 항상 false를 반환하고 requestPermissions() 메서드는 대화 상자를 표시하지 않지만 onRequestPermissionsResult 콜백으로 직접 거부됩니다.

그러나 onRequestPermissionsResult를 사용할 수 있는 다른 시나리오도 있습니다.예를 들어 일부 장치에는 카메라를 비활성화하는 장치 정책이 있을 수 있습니다(CIA, DARPA 등에서 작동).이러한 장치에서 onRequestPermissionsResult는 항상 false를 반환하고 requestPermissions() 메서드는 요청을 자동으로 거부합니다.

안드로이드 프레임워크의 제품 관리자인 벤 포에즈와 함께 팟캐스트를 들으며 모은 내용입니다.
http://androidbackstage.blogspot.jp/2015/08/.htmlhttp ://androidbackstage.blogspot.jp/2015/08/episode-33-permission-mission.html

갱신하다

저는 아래의 CanC의 답변이 따라야 할 정답이라고 생각합니다.확실하게 알 수 있는 유일한 방법은 showPermissionRationale를 사용하여 onRequestPermissionResult 콜백에서 이를 확인하는 것입니다.

==

나의 원래 대답은:

내가 찾은 유일한 방법은 이것이 처음인지 아닌지를 스스로 추적하는 것입니다(예: 공유 선호도 사용).처음이 아니면 다음을 사용합니다.shouldShowRequestPermissionRationale()차별화하기 위해.

참고:Android M - 런타임 권한 확인 - 사용자가 "다시 묻지 않음"을 선택했는지 확인하는 방법은 무엇입니까?

다른 옵션을 게시하십시오. 다른 옵션을 게시하십시오."Android M 시스템 권한 단순화"와 같이 Google 자체에서 제공하는 EasyPermissions를 사용할 수 있습니다.

그럼 당신은 처리할 필요가 없습니다.shouldShowRequestPermissionRationale직접적으로.

이렇게 하면 되나요?

@Retention(RetentionPolicy.SOURCE)
@IntDef({GRANTED, DENIED, NEVER})
public @interface PermissionStatus {
}

public static final int GRANTED = 0;
public static final int DENIED = 1;
public static final int NEVER = 2;

@PermissionStatus
public static int getPermissionStatus(Activity activity, String permission) {
    if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
        return DENIED;
    } else {
        if (ActivityCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED) {
            return GRANTED;
        } else {
            return NEVER;
        }
    }
}

누군가에게 유용할 수 있습니다.

제가 주목한 것은 onRequestPermissionsResult() 콜백 메서드에서 shouldShowRequestPermissionRationale() 플래그를 확인하면 두 가지 상태만 표시된다는 것입니다.

상태 1:-True 반환:-- 사용자가 권한 거부를 클릭할 때마다(처음 포함)

상태 2:-사용자가 "다시 묻지 않음"을 선택하면 false:-을 반환합니다.

자세한 작업 예제에 대한 링크입니다.

이 구현을 확인하십시오.사용 권한 목록을 전달하는 checkPermissions() 메서드에서 권한을 확인합니다.RequestPermissionsResult()에서 권한 요청 결과를 확인합니다.구현을 통해 사용자가 "다시 묻지 않음"을 선택할 때 두 가지 경우를 모두 해결할 수 있습니다.이 구현에서는 "다시 묻지 않음"을 선택하는 경우 대화 상자에 앱 설정 활동으로 이동할 수 있는 옵션이 있습니다.

이 모든 코드는 내 조각 안에 있습니다.권한 관리자처럼 이를 위한 전문 클래스를 만드는 것이 더 나을 것이라고 생각했는데 잘 모르겠습니다.

/**
     * responsible for checking if permissions are granted. In case permissions are not granted, the user will be requested and the method returns false. In case we have all permissions, the method return true.
     * The response of the request for the permissions is going to be handled in the onRequestPermissionsResult() method
     * @param permissions list of permissions to be checked if are granted onRequestPermissionsResult().
     * @param requestCode request code to identify this request in
     * @return true case we already have all permissions. false in case we had to prompt the user for it.
     */
    private boolean checkPermissions(List<String> permissions, int requestCode) {
        List<String> permissionsNotGranted = new ArrayList<>();
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED)
                permissionsNotGranted.add(permission);
        }

        //If there is any permission we don't have (it's going to be in permissionsNotGranted List) , we need to request.
        if (!permissionsNotGranted.isEmpty()) {
            requestPermissions(permissionsNotGranted.toArray(new String[permissionsNotGranted.size()]), requestCode);
            return false;
        }
        return true;
    }

    /**
     * called after permissions are requested to the user. This is called always, either
     * has granted or not the permissions.
     * @param requestCode  int code used to identify the request made. Was passed as parameter in the
     *                     requestPermissions() call.
     * @param permissions  Array containing the permissions asked to the user.
     * @param grantResults Array containing the results of the permissions requested to the user.
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case YOUR_REQUEST_CODE: {
                boolean anyPermissionDenied = false;
                boolean neverAskAgainSelected = false;
                // Check if any permission asked has been denied
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        anyPermissionDenied = true;
                        //check if user select "never ask again" when denying any permission
                        if (!shouldShowRequestPermissionRationale(permissions[i])) {
                            neverAskAgainSelected = true;
                        }
                    }
                }
                if (!anyPermissionDenied) {
                    // All Permissions asked were granted! Yey!
                    // DO YOUR STUFF
                } else {
                    // the user has just denied one or all of the permissions
                    // use this message to explain why he needs to grant these permissions in order to proceed
                    String message = "";
                    DialogInterface.OnClickListener listener = null;
                    if (neverAskAgainSelected) {
                        //This message is displayed after the user has checked never ask again checkbox.
                        message = getString(R.string.permission_denied_never_ask_again_dialog_message);
                        listener = new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                //this will be executed if User clicks OK button. This is gonna take the user to the App Settings
                                startAppSettingsConfigActivity();
                            }
                        };
                    } else {
                        //This message is displayed while the user hasn't checked never ask again checkbox.
                        message = getString(R.string.permission_denied_dialog_message);
                    }
                    new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme)
                            .setMessage(message)
                            .setPositiveButton(getString(R.string.label_Ok), listener)
                            .setNegativeButton(getString(R.string.label_cancel), null)
                            .create()
                            .show();
                }
            }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    /**
     * start the App Settings Activity so that the user can change
     * settings related to the application such as permissions.
     */
    private void startAppSettingsConfigActivity() {
        final Intent i = new Intent();
        i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        i.addCategory(Intent.CATEGORY_DEFAULT);
        i.setData(Uri.parse("package:" + getActivity().getPackageName()));
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        getActivity().startActivity(i);
    }

코틀린 솔루션에 관심이 있는 사람이 있다면, 저는 @muthuraj 답변을 코틀린에 있는 것으로 리팩터링했습니다.또한 청취자 대신 완성 블록을 갖추기 위해 약간 현대화했습니다.

사용 권한 유틸리티

object PermissionUtil {
    private val PREFS_FILE_NAME = "preference"

    fun firstTimeAskingPermission(context: Context, permission: String, isFirstTime: Boolean) {
        val sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE)
        sharedPreference.preferences.edit().putBoolean(permission,
                isFirstTime).apply()
    }

    fun isFirstTimeAskingPermission(context: Context, permission: String): Boolean {
        val sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE)
        return sharedPreference.preferences.getBoolean(permission,
                true)
    }
}

권한 처리기

enum class CheckPermissionResult {
    PermissionAsk,
    PermissionPreviouslyDenied,
    PermissionDisabled,
    PermissionGranted
}

typealias PermissionCheckCompletion = (CheckPermissionResult) -> Unit


object PermissionHandler {

    private fun shouldAskPermission(context: Context, permission: String): Boolean {
        return ContextCompat.checkSelfPermission(context,
                permission) != PackageManager.PERMISSION_GRANTED
    }

    fun checkPermission(context: Context, permission: String, completion: PermissionCheckCompletion) {
        // If permission is not granted
        if (shouldAskPermission(context, permission)) {
            //If permission denied previously
            if ((context as Activity).shouldShowRequestPermissionRationale(permission)) {
                completion(CheckPermissionResult.PermissionPreviouslyDenied)
            } else {
                // Permission denied or first time requested
                if (PermissionUtil.isFirstTimeAskingPermission(context,
                                permission)) {
                    PermissionUtil.firstTimeAskingPermission(context,
                            permission,
                            false)
                    completion(CheckPermissionResult.PermissionAsk)
                } else {
                    // Handle the feature without permission or ask user to manually allow permission
                    completion(CheckPermissionResult.PermissionDisabled)
                }
            }
        } else {
            completion(CheckPermissionResult.PermissionGranted)
        }
    }
}

실행

PermissionHandler.checkPermission(activity,
                    Manifest.permission.CAMERA) { result ->
                when (result) {
                    CheckPermissionResult.PermissionGranted -> {
                        // openCamera()
                    }
                    CheckPermissionResult.PermissionDisabled -> {
                        // displayAlert(noPermissionAlert)
                    }
                    CheckPermissionResult.PermissionAsk -> {
                        // requestCameraPermissions()
                    }
                    CheckPermissionResult.PermissionPreviouslyDenied -> {
                        // displayAlert(permissionRequestAlert)
                    }
                }
            }
public void requestPermission(View view){
        if(ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            if(ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)){

//The Alert Dialog before asking for the second time to help the user understand  why he needs to give permission.

                AlertDialog alert = new AlertDialog.Builder(this).setMessage("Without the permissions you cannot run the application")
                        .setCancelable(false)
                        .setPositiveButton("Okay, I understand", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ActivityCompat.requestPermissions(MainActivity.this,
                                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
                            }
                        }).setNegativeButton("No, Exit the App", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        System.exit(2);
                    }
                }).create();
                alert.setTitle("ALERTY");
                alert.show();
//End of the alert Dialog
            }
            else{
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
            }
        }
        else {
            textView.setText("Permission Is Already Granted");
        }
    }
    /*
     The shouldShowRequestPermissionRationale() function returns true if the app has requested this permission
     previously and the user denied the request.If the user turned down the permission request in the past and chose
     the Don't ask again option, this method returns false.
      */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if(requestCode == REQUEST_FINE_LOCATION) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                textView.setText("Hooray! on Request Permissions Granted");
            }
            else{
                //Since the user has chosen the don't ask again option,
                if(!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)){

//Alert Dialog that will take user to settings where he can manually give the permissions
                    AlertDialog alert = new AlertDialog.Builder(this).setMessage("You have permanently disabled the permission ")
                            .setPositiveButton("Go to Settings", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                             openSettings();
                        }
                    }).setNegativeButton("Don't Go",null).setCancelable(false).create();
                  alert.setTitle("Give permission manually");
                  alert.show();
 // End of the Alert Dialog
                }
                else{
                    textView.setText("Permission has been denied the 1st time");
                }
            }
        }
    }

이것이 openSettings 메서드입니다.

    public void openSettings(){
        Intent intent = new Intent();

        Uri uri = Uri.fromParts("package",this.getPackageName(),null);
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri);
        startActivity(intent);
    }

showRequestPermissionRationaleonRequestPermissionsResult의 올바른 사용법입니다.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
    <androidx.appcompat.widget.LinearLayoutCompat
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity"
        android:gravity="center">
    
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_camera"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Camera"
            android:textAllCaps="false"
            android:background="@color/purple_200"
            android:layout_marginTop="20dp"
            >
        </androidx.appcompat.widget.AppCompatButton>
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_storage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Storage"
            android:textAllCaps="false"
            android:background="@color/purple_200"
            android:layout_marginTop="30dp"
            >
        </androidx.appcompat.widget.AppCompatButton>
    
    </androidx.appcompat.widget.LinearLayoutCompat>
enter code here

기본 활동.kt

package com.example.myapplication
import android.Manifest
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
class MainActivity : AppCompatActivity() {
    private val TAG = "MainActivity"
    lateinit var btnCamera: Button
    private val cameraRequestCode = 100
    lateinit var btnStorage: Button
    private val storageRequestCode = 200
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btnCamera = findViewById(R.id.btn_camera)
        btnStorage = findViewById(R.id.btn_storage)
        btnCamera.setOnClickListener {
            checkPermission(android.Manifest.permission.CAMERA, cameraRequestCode)
        }
        btnStorage.setOnClickListener {
            checkPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, storageRequestCode)
        }
    }

    private fun checkPermission(permissionName: String, requestCode: Int) {
        /**
         * if the permission is given means it will give the  permissionNumber = 0
         * if the permission is not  given means it will give the  permissionNumber =-1
         * It s same as we are checking for PackageManager.PERMISSION_DENIED =-1 & PackageManager.GRANTED=0
         */
        val permissionNumber: Int =
            ContextCompat.checkSelfPermission(this@MainActivity, permissionName)
        if (permissionNumber == PackageManager.PERMISSION_GRANTED) {

        } else if (permissionNumber == PackageManager.PERMISSION_DENIED) {
            askpermission(permissionName, requestCode, permissionNumber)

        }

    }

    private fun askpermission(permissionName: String, permissionCode: Int, permissionNumner: Int) {
        ActivityCompat.requestPermissions(
            this@MainActivity,
            arrayOf(permissionName),
            permissionCode
        )
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == cameraRequestCode) {
            if (permissions.size > 0) {
                if (permissions[0].toString().equals(Manifest.permission.CAMERA, ignoreCase = true)) {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        Toast.makeText(applicationContext,"Permission Granted",Toast.LENGTH_SHORT).show()

                    }else{
                        if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                           var permissionDeniedStatus= checkDeniedPermissionStatus(permissions[0]);
                            if(permissionDeniedStatus){
                                /**
                                 * Permission Denied
                                 */
                                Toast.makeText(applicationContext,"Permission Denied",Toast.LENGTH_SHORT).show()
                            }else{
                                /**
                                 * Permission Denied and Selected Don t ask again.
                                 */
                                showDialog("Permission Denied","Permission Denied Permanently\nOpen Setting to allow")
                            }
                        }
                    }
                }
            }
        }else  if (requestCode == storageRequestCode) {
            if(permissions[0].toString().equals(Manifest.permission.READ_EXTERNAL_STORAGE, ignoreCase = true)){
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        Toast.makeText(applicationContext,"Permission Granted",Toast.LENGTH_SHORT).show()
                    }
                }else{
                    if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                        var permissionDeniedStatus= checkDeniedPermissionStatus(permissions[0]);
                        if(permissionDeniedStatus){
                            /**
                             * Permission Denied
                             */
                            Toast.makeText(applicationContext,"Permission Denied",Toast.LENGTH_SHORT).show()
                        }else{
                            /**
                             * Permission Denied and Selected Don t ask again.
                             */
                            showDialog("Permission Denied","Permission Denied Permanently\nOpen Setting to allow")
                        }
                    }
                }
            }
        }
    }

    private fun checkDeniedPermissionStatus(permissionName: String) :Boolean{
        val permissionDeniedStatus: Boolean = ActivityCompat.shouldShowRequestPermissionRationale(this@MainActivity, permissionName)
        return permissionDeniedStatus
    }

    private fun showDialog(title: String, message: String) {
        val builder = AlertDialog.Builder(this)
        builder.setTitle(title)
        builder.setMessage(message)
        builder.setPositiveButton(android.R.string.yes) { dialog, which ->

        }

        builder.setNegativeButton(android.R.string.no) { dialog, which ->

        }
        builder.show()
    }
}

구글은 내가 답 중 하나를 사용했기 때문에 내 앱을 거부했습니다.제 버전은 다음과 같습니다.

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;

import androidx.core.app.ActivityCompat;

public class PermissionUtil {

    static final String PREFS_NAME = "AppsPermissions";

    private static boolean shouldAskPermission(Context context, String permission) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int permissionResult = ActivityCompat.checkSelfPermission(context, permission);
            if (permissionResult != PackageManager.PERMISSION_GRANTED) {
                return true;
            }
        }
        return false;
    }

    public static void checkPermission(Activity activity, String permission, PermissionAskListener listener) {
        // If permission is not granted
        if (shouldAskPermission(activity, permission)) {
            // If permission denied previously without "Don't ask again"
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                listener.onPermissionAsk();
            } else {
                SharedPreferences sharedPreference = activity.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
                if (sharedPreference.getBoolean(permission, true)) {
                    // Permission first time requested.
                    sharedPreference.edit().putBoolean(permission, false).apply();
                    listener.onPermissionAsk();
                }
                else {
                    // Handle the feature without permission or ask user to manually allow permission
                    listener.onPermissionDenied();
                }
            }
        }
        else {
            listener.onPermissionGranted();
        }
    }

    /// Callback on checking permission.
    public interface PermissionAskListener {
        /// Callback to ask permission
        void onPermissionAsk();

        /// Callback on permission denied
        void onPermissionDenied();

        /// Callback on permission granted
        void onPermissionGranted();
    }
}

이 코드는 런타임 중에 사용자에게 권한을 요청하고, 사용자가 허용하면 결과 메서드를 실행하고, 사용자가 거부하면 사용자 거부로 다시 요청하지만(지시와 함께 다시 요청함), 사용자가 다시 요청하지 않도록 선택하면 다시 요청하지 않습니다.다시 묻지 않음을 처리하고 지침과 함께 열린 설정 옵션을 표시합니다.

public String storagePermissions = Manifest.permission.READ_EXTERNAL_STORAGE;   
private static final int REQUEST_ACCESS =101;  

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

    setContentView(R.layout.activity_main);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      if(checkSelfPermission(storagePermissions)== PackageManager.PERMISSION_GRANTED){
          result();    // result  is your block of code 
      }else {
          requestPermissions(new String[]{storagePermissions},REQUEST_ACCESS);
      }

    }
    else{
        result();    //so if user is lower than api verison M, no permission is requested
    } 

}

 private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
    new AlertDialog.Builder(MainActivity.this)
            .setMessage(message)
            .setTitle("Hi User..")
            .setPositiveButton("Ok", okListener)
            .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {        //idea calling showMessage funtion again
                    Snackbar mySnackbar = Snackbar.make( findViewById(R.id.coordinatorlayout),"You Press Cancel.. ", Snackbar.LENGTH_INDEFINITE);
                    mySnackbar.setAction("Exit", new cancelButton());
                    mySnackbar.show();

                }
            })
            .create()
            .show();
}


private void result(){
          //your code
}

    @RequiresApi(api = Build.VERSION_CODES.M)
public class NeverAskAgain implements View.OnClickListener{
    @Override
    public void onClick(View view)
    {
        goToSettings();
    }
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void goToSettings() {
    Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
    finish();
    myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
    myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivityForResult(myAppSettings, REQUEST_APP_SETTINGS);
}
public class cancelButton implements View.OnClickListener{
    @Override
    public void onClick(View view){
        Toast.makeText(MainActivity.this,"To use this app , you must grant storage permission",Toast.LENGTH_SHORT);
        finish();
    }
    }


 @Override
@RequiresApi(api = Build.VERSION_CODES.M)
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode,permissions,grantResults);

    switch(requestCode) {
        case REQUEST_ACCESS:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission is granted
                    result();
                    break;
                }
                else if (!shouldShowRequestPermissionRationale(permissions[0])){
                    showMessageOKCancel("You choose Never Ask Again,option",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Snackbar mySnackbar = Snackbar.make(findViewById(R.id.coordinatorlayout), "Permission=>Storage=>On", Snackbar.LENGTH_INDEFINITE);
                        mySnackbar.setAction("Settings", new NeverAskAgain());
                        mySnackbar.show();
                    }
                     });
                    break;
                }
                else {
                    showMessageOKCancel("You Denid permission Request..",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(new String[]{storagePermissions}, REQUEST_ACCESS);
                        }
                    });
                    break;
                }
        }
}

언급URL : https://stackoverflow.com/questions/32347532/android-m-permissions-confused-on-the-usage-of-shouldshowrequestpermissionrati

반응형