Quyền của Android M: Nhầm lẫn về việc sử dụng hàm nênShowRequestPermissionRationale ()


148

Tôi đã xem qua tài liệu chính thức về mô hình Quyền mới trong Android M. Nó nói về shouldShowRequestPermissionRationale()chức năng trả về truenếu ứng dụng đã yêu cầu quyền này trước đó và người dùng đã từ chối yêu cầu. Nếu trước đây người dùng đã từ chối yêu cầu cấp phép và chọn tùy chọn Không hỏi lại, phương thức này sẽ trả về false.

Nhưng làm thế nào chúng ta có thể phân biệt giữa hai trường hợp sau đây?

Trường hợp 1 : Ứng dụng không có quyền và người dùng chưa được yêu cầu quyền trước đó. Trong trường hợp này, nênShowRequestPermissionRationale () sẽ trả về false vì đây là lần đầu tiên chúng tôi hỏi người dùng.

Trường hợp 2 : Người dùng đã từ chối quyền và đã chọn "Đừng hỏi lại", trong trường hợp này cũng nênShowRequestPermissionRationale () sẽ trả về false.

Tôi muốn gửi người dùng đến trang cài đặt của Ứng dụng trong Trường hợp 2. Làm thế nào để tôi phân biệt hai trường hợp này?


1
Câu trả lời được chấp nhận là tốt. Cũng giống như một giải pháp thay thế, bạn cũng có thể sử dụng một pref được chia sẻ để biết liệu ứng dụng có yêu cầu sự cho phép trước đó hay không. Chỉ cần ném nó ra khỏi đó trong trường hợp nó phù hợp hơn với tình huống của người khác.
Rockin4Life33

4
Cũng có trường hợp 3: Người dùng đã được yêu cầu và cấp / từ chối cấp phép, nhưng đã sử dụng cài đặt quyền để hoàn nguyên về "hỏi mỗi lần". Kiểm tra cho thấy shouldShowRequestPermissionRationale()trả về sai trong trường hợp này, điều này sẽ làm tổn thương bất kỳ mã nào dựa trên cờ "tôi đã hỏi trước".
Pickup Logan

đây là một mẫu google cho thấy các thực tiễn tốt nhất trong permissionsAndroid. github.com/android/permissions-samples
itabdullah

Câu trả lời:


172

Sau M Preview 1, nếu hộp thoại được hiển thị lần đầu tiên , không có hộp kiểm Không bao giờ hỏi lại .

Nếu người dùng từ chối yêu cầu cấp phép, sẽ có hộp kiểm Không bao giờ hỏi lại trong hộp thoại quyền, quyền thứ hai được yêu cầu.

Vì vậy, logic nên như thế này:

  1. Xin phep:

    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. Kiểm tra nếu sự cho phép đã bị từ chối hoặc cấp onRequestPermissionsResult.

    Nếu quyền đã bị từ chối trước đó, lần này sẽ có hộp kiểm Không bao giờ hỏi lại trong hộp thoại cấp phép.

    Gọi shouldShowRequestPermissionRationaleđể xem nếu người dùng kiểm tra Không bao giờ hỏi lại . shouldShowRequestPermissionRationalephương thức chỉ trả về false nếu người dùng đã chọn Không bao giờ hỏi lại hoặc chính sách thiết bị cấm ứng dụng có quyền đó:

    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...
            }
        }
    }
    

Vì vậy, bạn sẽ không phải theo dõi nếu người dùng đã chọn Không bao giờ hỏi lại hay không.


48
Một điểm cần làm rõ, nênShowRequestPermissionRationale () cũng sẽ trả về false nếu người dùng chưa bao giờ được yêu cầu xin phép (tức là lần đầu tiên ứng dụng được chạy). Bạn sẽ không gặp phải trường hợp đó nếu bạn tuân theo logic của ví dụ được cung cấp. Nhưng từ ngữ, dưới 2 là một chút sai lệch.
Ben

1
@Canc giải thích rất hay. Cảm ơn :)
AndoAiron

14
Tôi không chắc chắn, điều này có vẻ thiếu sót. Làm thế nào chúng ta phải biết nếu đó là lần đầu tiên người dùng được hỏi? Tôi phải theo dõi nếu người dùng được hỏi, và nếu anh ta làm vậy, thì tôi phải đảo ngược logic. Không có ý nghĩa gì với tôi.
Daniel F

4
Tôi nghĩ rằng đáng lưu ý rằng nơi bạn đi qua contexttrong ActivityCompat.shouldShowRequestPermissionRationale(...)tham số thực sự là loại Activity. Có thể không ảnh hưởng đến tất cả các bạn nhưng trong trường hợp của tôi thì có.
aProperFox

7
Logic android này thật là ngu ngốc! Nó buộc tôi phải gọi lại shouldtrong cuộc gọi lại và lưu giá trị đối ứng của nó trong NVM chỉ để biết liệu tôi có cần nhắc lại yêu cầu lần sau khi ứng dụng mở ra không! ... wow (facepalm) ... có quá khó để chỉ thực hiện một cuộc gọi trả lại một bảng liệt kê trạng thái không ??
Shockwaver

22

Tôi đã có cùng một vấn đề và tôi đã tìm ra nó. Để làm cho cuộc sống đơn giản hơn nhiều, tôi đã viết một lớp tiện dụng để xử lý các quyền thời gian chạy.

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();
    }
}

Và các phương pháp PreferenceUtil như sau.

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);
}

Bây giờ, tất cả những gì bạn cần là sử dụng phương thức checkPermission với các đối số thích hợp.

Đây là một ví dụ,

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();
                        }
                    });

Trường hợp 1: Ứng dụng không có quyền và người dùng chưa được yêu cầu quyền trước đó. Trong trường hợp này, nênShowRequestPermissionRationale () sẽ trả về false vì đây là lần đầu tiên chúng tôi hỏi người dùng.

Trường hợp 2: Người dùng đã từ chối quyền và chọn "Đừng hỏi lại", trong trường hợp này cũng vậy nênShowRequestPermissionRationale () sẽ trả về false.

Tôi muốn gửi người dùng đến trang cài đặt của Ứng dụng trong Trường hợp 2. Làm thế nào để tôi phân biệt hai trường hợp này?

Bạn sẽ nhận được cuộc gọi lại trên onPermissionAsk cho trường hợp 1 và onPermissionDisables cho trường hợp 2.

Chúc mừng mã hóa :)


Giải thích tuyệt vời bro. Thực hiện theo các thủ tục chính xác của bạn. :)
Sumit Jha

Tôi phải điền gì cho tính năng này? public void onPermissionAsk() { ActivityCompat.requestPermissions( thisActivity, ... .
Mardymar

@Mardymar thisActivitykhông có gì nhưng YourActivity.this.
muthuraj

1
cách xử lý nhiều quyền và cách tích hợp mã này vào đoạn.
Taimur

Bạn contextđang sử dụng loại nào? shouldShowRequestPermissionRationale(permission)không tồn tại trong android.content.Context. đó là trong ActivityCompat
Hilikus

8

CẬP NHẬT

Tôi tin rằng câu trả lời của CanC dưới đây là câu trả lời đúng cần được tuân theo. Cách duy nhất để biết chắc chắn là xác minh điều này trong cuộc gọi lại onRequestPermissionResult bằng cách sử dụng nênShowPermissionRationale.

==

Câu trả lời ban đầu của tôi:

Cách duy nhất mà tôi đã tìm thấy là tự mình theo dõi xem đây có phải là lần đầu tiên hay không (ví dụ: sử dụng tùy chọn chia sẻ). Nếu đó không phải là lần đầu tiên, thì hãy sử dụng shouldShowRequestPermissionRationale()để phân biệt.

Xem thêm: Android M - kiểm tra quyền thời gian chạy - làm thế nào để xác định xem người dùng có kiểm tra "Không bao giờ hỏi lại" không?


1
Có, thậm chí tôi đồng ý rằng phương pháp của CanC là phương pháp nên được tuân theo. Tôi sẽ đánh dấu nó là câu trả lời được chấp nhận.
akshayt23

6

Theo cách tôi hiểu, nênShowRequestPermissionRationale () chạy một số trường hợp sử dụng trong trình duyệt và thông báo cho ứng dụng biết có hiển thị giải thích về các quyền được yêu cầu hay không.

Ý tưởng đằng sau các quyền Run Time là hầu hết thời gian, người dùng sẽ nói Có với yêu cầu cấp phép. Bằng cách đó, người dùng sẽ chỉ phải thực hiện một cú nhấp chuột. Tất nhiên, yêu cầu nên được sử dụng trong ngữ cảnh chính xác - tức là yêu cầu quyền của Camera khi nhấn nút "Camera".

Nếu người dùng từ chối yêu cầu, nhưng sau một thời gian xuất hiện và nhấn nút "Camera" lần nữa, nênShowRequestPermissionRationale () sẽ trả về đúng, vì vậy ứng dụng có thể hiển thị một số lời giải thích có ý nghĩa tại sao quyền được yêu cầu và tại sao ứng dụng sẽ không làm việc đúng cách mà không có nó Thông thường, bạn sẽ hiển thị trong cửa sổ hộp thoại đó một nút để từ chối lại / quyết định sau và một nút để cấp quyền. Nút cấp quyền trong hộp thoại hợp lý, sẽ bắt đầu lại yêu cầu cấp phép. Lần này, người dùng cũng sẽ có hộp kiểm "Không bao giờ hiển thị lại". Nếu anh ta quyết định chọn nó và từ chối cấp phép một lần nữa, nó sẽ thông báo cho hệ thống Android rằng người dùng và ứng dụng không ở trên cùng một trang. Hành động đó sẽ có hai hậu quả - nênShowRequestPermissionRationale () sẽ luôn trả về false,

Nhưng cũng có một kịch bản khả dĩ khác mà onRequestPermissionsResult có thể được sử dụng. Ví dụ: một số thiết bị có thể có chính sách thiết bị vô hiệu hóa máy ảnh (hoạt động cho CIA, DARPA, v.v.). Trên các thiết bị này, onRequestPermissionsResult sẽ luôn trả về false và phương thức requestPermissions () sẽ âm thầm từ chối yêu cầu.

Đó là những gì tôi thu thập được bằng cách nghe podcast với Ben Poiesz - một người quản lý sản phẩm trên khung Android.
http://androidbackstage.blogspot.jp/2015/08/epiT-33- allow-mission.html


6

Chỉ cần đăng một tùy chọn khác, nếu bất cứ ai có thể cảm thấy thích. Bạn có thể sử dụng EasyPermissions do chính Google cung cấp, như đã nói, "Đơn giản hóa các quyền hệ thống Android M".

Sau đó, bạn không phải xử lý shouldShowRequestPermissionRationaletrực tiếp.


tại sao tôi không thấy dự án này thịnh hành :)
Vlad

Vấn đề với EasyPermissions gần như giữ nguyên. Yêu cầu permissionPermanentlyDeniednội bộ chỉ gọi shouldShowPermissionsRationalevà trả lại truetrong trường hợp khi người dùng không bao giờ được yêu cầu cấp quyền.
hgoebl

4

Nếu bất cứ ai quan tâm đến giải pháp của Kotlin, tôi đã tái cấu trúc câu trả lời @muthuraj để có trong Kotlin. Cũng hiện đại hóa nó một chút để có một khối hoàn thành thay vì người nghe.

Giấy phépUtil

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)
    }
}

Giấy phép

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)
        }
    }
}

Thực hiện

PermissionHandler.checkPermission(activity,
                    Manifest.permission.CAMERA) { result ->
                when (result) {
                    CheckPermissionResult.PermissionGranted -> {
                        // openCamera()
                    }
                    CheckPermissionResult.PermissionDisabled -> {
                        // displayAlert(noPermissionAlert)
                    }
                    CheckPermissionResult.PermissionAsk -> {
                        // requestCameraPermissions()
                    }
                    CheckPermissionResult.PermissionPreviouslyDenied -> {
                        // displayAlert(permissionRequestAlert)
                    }
                }
            }

3

Kiểm tra việc thực hiện này. đang làm việc khá tốt cho tôi. về cơ bản, bạn kiểm tra các quyền trong phương thức checkPermissions () thông qua danh sách các quyền. Bạn kiểm tra kết quả của yêu cầu cấp phép trên onRequestPermissionsResult (). Việc triển khai cho phép bạn giải quyết cả hai trường hợp khi người dùng chọn "không bao giờ hỏi lại" hay không. Trong triển khai này, trong trường hợp se chọn "không bao giờ hỏi lại", hộp thoại có một tùy chọn để đưa anh ta đến Hoạt động cài đặt ứng dụng.

Tất cả mã này là bên trong mảnh của tôi. Tôi đã nghĩ rằng sẽ tốt hơn nếu tạo ra một lớp chuyên biệt để làm điều này, như PermissionManager, nhưng tôi không chắc về nó.

/**
     * 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);
    }

2

Có thể hữu ích cho ai đó: -

Những gì tôi đã nhận thấy là, nếu chúng ta kiểm tra cờ nênShowRequestPermissionRationale () trong phương thức gọi lại onRequestPermissionsResult (), nó chỉ hiển thị hai trạng thái.

Trạng thái 1: -Trở lại đúng: - Bất kỳ lúc nào người dùng nhấp vào Từ chối quyền (kể cả lần đầu tiên).

Trạng thái 2: -Returns false: - nếu người dùng chọn thì không bao giờ hỏi lại ".

Liên kết cho ví dụ làm việc chi tiết .


6
nó trả về false lần đầu tiên không đúng sự thật
Jom

Vâng, đó là những gì tôi đã đề cập, nếu bạn kiểm tra cờ trong phương thức gọi lại onRequestPermissionsResult (), nó sẽ chỉ có hai trạng thái, cụ thể là trong cuộc gọi lại này.
Nicks

2
Thật không may, nênShowRequestPermissionRationale luôn trả về false - bất kể người dùng có bao giờ từ chối cấp phép hay không.
IgorGanapolsky

1

Chúng ta có thể làm điều đó bằng cách này?

@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;
        }
    }
}

Thật không may, mã này không phân biệt giữa một tình huống mà sự cho phép không bao giờ được yêu cầu trước đó và nơi "không bao giờ yêu cầu lại" đã được kiểm tra.
Ben

bạn nên sử dụng kết hợp này + lớp trình trợ giúp quyền để kiểm tra xem sự cho phép có được cấp hay không.
Tiến sĩ aNdRO

0

shouldShowRequestPermissionRationale cho phép ĐẶC BIỆT luôn trả về ĐÚNG CHỈ sau khi người dùng từ chối mà không có hộp kiểm

Chúng tôi quan tâm đến giá trị FALSE

Vì vậy, có 3 trường hợp bị mất với giá trị sai :

1. trước đây không có hành động nào như vậy và bây giờ người dùng quyết định đồng ý hoặc từ chối.

Đơn giản chỉ cần xác định một sở thích ASKED_PERMISSION_*mà không tồn tại hiện nay và sẽ là sự thậtonRequestPermissionsResulttrên nó bắt đầu trong bất kỳ trường hợp đồng ý hoặc từ chối

Vì vậy, trong khi sở thích này không tồn tại, không có lý do để kiểm trashouldShowRequestPermissionRationale

2. người dùng nhấp đồng ý.

Đơn giản chỉ cần làm:

checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED

Điều này sẽ trở lại đúngkhông có lý do để kiểm trashouldShowRequestPermissionRationale

3. người dùng nhấp vào từ chối với hộp kiểm (yêu cầu thứ hai trở lên)

Đó là THỜI GIAN để làm việc với shouldShowRequestPermissionRationalenó sẽ trả lại SAI

(ưu tiên tồn tại và chúng tôi không có sự cho phép)


0

Mã này yêu cầu người dùng hỏi quyền trong thời gian chạy, nếu người dùng cho phép, nó thực thi phương thức kết quả, nếu người dùng từ chối, họ sẽ hỏi lại từ chối với từ chối người dùng (nó hỏi lại bằng hướng dẫn), nhưng nếu người dùng chọn không bao giờ hỏi lại. Nó xử lý không bao giờ hỏi lại, hiển thị tùy chọn cài đặt mở với hướng dẫn.

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;
                }
        }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.