Android M - periksa izin runtime - cara menentukan apakah pengguna memeriksa “Never ask again”?

307

Menurut ini: http://developer.android.com/preview/features/runtime-permissions.html#coding suatu aplikasi dapat memeriksa izin runtime dan meminta izin jika belum diberikan. Dialog berikut akan ditampilkan kemudian:

masukkan deskripsi gambar di sini

Jika pengguna menolak izin penting, maka aplikasi harus menampilkan penjelasan mengapa izin diperlukan dan dampak penurunan apa yang dimiliki. Dialog itu memiliki dua opsi:

  1. coba lagi (izin diminta lagi)
  2. tolak (aplikasi akan berfungsi tanpa izin itu).

Namun jika pengguna memeriksa Never ask again, dialog kedua dengan penjelasan tidak akan ditampilkan, terutama jika pengguna sudah menolak sekali sebelumnya. Sekarang pertanyaannya adalah: bagaimana aplikasi saya tahu apakah pengguna telah memeriksa Never ask again? IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)tidak memberi saya informasi itu.

Pertanyaan kedua adalah: apakah Google memiliki rencana untuk memasukkan pesan khusus dalam dialog izin yang akan menjelaskan mengapa aplikasi membutuhkan izin? Dengan begitu tidak akan pernah ada dialog kedua yang pasti akan membuat ux menjadi lebih baik.

Emanuel Moecklin
sumber
9
"Apakah Google memiliki rencana untuk memasukkan pesan khusus dalam dialog izin yang akan menjelaskan mengapa aplikasi membutuhkan izin?" - dalam presentasi Google I | O tentang sistem perizinan M, sepertinya saya ingat seseorang bertanya dalam tanya jawab, dan jawabannya adalah mereka memikirkannya.
CommonsWare
1
Tidak mengujinya sendiri, tetapi dokumentasi mengatakan tentang Activity.shouldShowRequestPermissionRationale (String): Metode ini mengembalikan true jika aplikasi telah meminta izin ini sebelumnya dan pengguna menolak permintaan tersebut. Itu menunjukkan bahwa Anda mungkin harus menjelaskan kepada pengguna mengapa Anda memerlukan izin. Jika pengguna menolak permintaan izin di masa lalu dan memilih opsi Jangan tanya lagi dalam dialog sistem permintaan izin, metode ini mengembalikan false. Metode ini juga mengembalikan false jika kebijakan perangkat melarang aplikasi memiliki izin itu.
Takut
1
@Fraid: sepertinya mereka menambahkan ini dengan pratinjau # 2 dari Android M: developer.android.com/preview/support.html#preview2-notes dan mungkin itulah yang saya cari. Saya tidak bisa mengujinya sekarang tetapi akan melakukannya minggu depan. Jika berhasil seperti yang saya harapkan, Anda dapat mempostingnya sebagai jawaban dan mendapatkan reputasi. Sementara itu, ini dapat membantu orang lain: youtube.com/watch?v=f17qe9vZ8RM
Emanuel Moecklin
contoh Izin Berbahaya dan Izin Khusus: github.com/henrychuangtw/AndroidRuntimePermission
HenryChuang
1
@Alex lebih sulit untuk pengembang yang pasti tetapi dari perspektif pengguna bisa memberikan atau menolak izin khusus masuk akal. Masalah utama yang saya lihat adalah bahwa perincian izin sangat tidak konsisten dan Anda akhirnya meminta izin yang mungkin hampir tidak ada hubungannya dengan apa yang Anda coba lakukan di aplikasi Anda (mis. Izin kontak ketika saya ingin terhubung ke Google Drive karena itu memerlukan daftar akun perangkat untuk keperluan otentikasi dan izin akun adalah bagian dari grup izin kontak).
Emanuel Moecklin

Jawaban:

341

Pratinjau Pengembang 2 membawa beberapa perubahan pada bagaimana izin diminta oleh aplikasi (lihat juga http://developer.android.com/preview/support.html#preview2-notes ).

Dialog pertama sekarang terlihat seperti ini:

masukkan deskripsi gambar di sini

Tidak ada kotak centang "Jangan tampilkan lagi" (tidak seperti pratinjau pengembang 1). Jika pengguna menolak izin dan jika izin itu penting untuk aplikasi, ia dapat menyajikan dialog lain untuk menjelaskan alasan aplikasi meminta izin itu, misalnya seperti ini:

masukkan deskripsi gambar di sini

Jika pengguna menolak lagi aplikasi harus dimatikan jika benar-benar membutuhkan izin itu atau tetap berjalan dengan fungsionalitas terbatas. Jika pengguna mempertimbangkan kembali (dan memilih untuk mencoba ulang), izin diminta lagi. Kali ini promptnya terlihat seperti ini:

masukkan deskripsi gambar di sini

Kotak centang "Never ask again" yang kedua kali ditampilkan. Jika pengguna menolak lagi dan mencentang kotak tidak akan terjadi lagi. Apakah kotak centang dicentang atau tidak dapat ditentukan dengan menggunakan Activity.shouldShowRequestPermissionRationale (String), misalnya seperti ini:

if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {...

Itulah yang dikatakan dokumentasi Android ( https://developer.android.com/training/permissions/requesting.html ):

Untuk membantu menemukan situasi di mana Anda perlu memberikan penjelasan tambahan, sistem menyediakan metode Activity.shouldShowRequestPermissionRationale (String). Metode ini mengembalikan true jika aplikasi telah meminta izin ini sebelumnya dan pengguna menolak permintaan tersebut. Itu menunjukkan bahwa Anda mungkin harus menjelaskan kepada pengguna mengapa Anda memerlukan izin.

Jika pengguna menolak permintaan izin di masa lalu dan memilih opsi Jangan tanya lagi dalam dialog sistem permintaan izin, metode ini mengembalikan false. Metode ini juga mengembalikan false jika kebijakan perangkat melarang aplikasi memiliki izin itu.

Untuk mengetahui apakah pengguna menolak dengan "tidak pernah bertanya lagi" Anda dapat memeriksa lagi metode shouldShowRequestPermissionRationale di onRequestPermissionsResult Anda saat pengguna tidak memberikan izin.

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == REQUEST_PERMISSION) {
        // for each permission check if the user granted/denied them
        // you may want to group the rationale in a single dialog,
        // this is just an example
        for (int i = 0, len = permissions.length; i < len; i++) {
            String permission = permissions[i];
            if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
            // user rejected the permission
                boolean showRationale = shouldShowRequestPermissionRationale( permission );
                if (! showRationale) {
                    // user also CHECKED "never ask again"
                    // you can either enable some fall back,
                    // disable features of your app
                    // or open another dialog explaining
                    // again the permission and directing to
                    // the app setting
                } else if (Manifest.permission.WRITE_CONTACTS.equals(permission)) {
                    showRationale(permission, R.string.permission_denied_contacts);
                    // user did NOT check "never ask again"
                    // this is a good place to explain the user
                    // why you need the permission and ask if he wants
                    // to accept it (the rationale)
                } else if ( /* possibly check more permissions...*/ ) {
                }
            }
        }
    }
}

Anda dapat membuka pengaturan aplikasi Anda dengan kode ini:

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);

Tidak ada cara mengirim pengguna langsung ke halaman Otorisasi.

Emanuel Moecklin
sumber
30
Saya memverifikasi nilai pengembalian metode shouldShowRequestPermissionRationale () menjadi false untuk memeriksa apakah pengguna memilih "Jangan tanya lagi". Tapi saya juga mendapatkan nilainya sebagai false untuk pertama kalinya ketika meminta izin. Jadi saya tidak dapat membedakan apakah pengguna memilih kotak centang "Jangan tanya lagi" atau tidak. Tolong sarankan ??
Sagar Trehan
32
Menurut pemahaman saya metode shouldShowRationalePermissionRationale () mengembalikan false dalam tiga kasus: 1. Jika kita memanggil metode ini pertama kali sebelum meminta izin. 2. Jika pengguna memilih "Jangan tanya lagi" dan menolak izin. 3. Jika kebijakan perangkat melarang aplikasi memiliki izin itu
Sagar Trehan
24
Semua baik ... tapi kami, pengembang, benar-benar perlu tahu apakah pengguna mengatakan "tidak pernah bertanya lagi" atau tidak. Saya memiliki tombol yang bagus untuk mengakses fitur. Pertama kali pengguna mengklik: harus bertanya alasannya? tidak, minta izin. Pengguna menyangkal. Pengguna mengklik lagi tombol: rasional? ya! Perlihatkan alasannya, pengguna mengatakan OK, lalu tolak dan jangan pernah bertanya lagi (ok dia idiot, tetapi pengguna sering). Nanti pengguna tekan lagi tombol, rasional? tidak, minta izin, tidak ada yang terjadi untuk pengguna. Saya benar-benar membutuhkan cara, di sana, untuk memberi tahu pengguna: hei jika Anda menginginkan fitur ini sekarang buka pengaturan aplikasi dan berikan izin.
Daniele Segato
4
Hebat @EmanuelMoecklin ini lebih baik daripada Dokumentasi Google sekarang: D
Daniele Segato
4
onRequestPermissionsResult tidak akan dipanggil kecuali Anda meminta izin. Karena tidak ada kotak centang "Jangan tanya lagi" saat pertama kali izin diminta, seharusnyaShowRequestPermissionRationale akan mengembalikan Benar (izin diminta tetapi tanpa pernah bertanya lagi). Akibatnya, alasannya selalu ditampilkan pertama kali pengguna menolak izin tetapi setelah itu hanya jika kotak centang tidak dicentang.
Emanuel Moecklin
95

Anda dapat memeriksa shouldShowRequestPermissionRationale()di onRequestPermissionsResult().

shouldShowRequestPermissionRationale https://youtu.be/C8lUdPVSzDk?t=2m23s

Periksa apakah izin diberikan atau tidak pada onRequestPermissionsResult(). Jika tidak maka periksa shouldShowRequestPermissionRationale().

  1. Jika metode ini kembali truemaka perlihatkan penjelasan mengapa izin khusus ini diperlukan. Kemudian tergantung pada pilihan pengguna lagi requestPermissions().
  2. Jika kembali falsemaka tampilkan pesan kesalahan bahwa izin tidak diberikan dan aplikasi tidak dapat melanjutkan lebih jauh atau fitur tertentu dinonaktifkan.

Di bawah ini adalah contoh kode.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case STORAGE_PERMISSION_REQUEST:
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted :)
                downloadFile();
            } else {
                // permission was not granted
                if (getActivity() == null) {
                    return;
                }
                if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    showStoragePermissionRationale();
                } else {
                    Snackbar snackbar = Snackbar.make(getView(), getResources().getString(R.string.message_no_storage_permission_snackbar), Snackbar.LENGTH_LONG);
                    snackbar.setAction(getResources().getString(R.string.settings), new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (getActivity() == null) {
                                return;
                            }
                            Intent intent = new Intent();
                            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts("package", getActivity().getPackageName(), null);
                            intent.setData(uri);
                            OrderDetailFragment.this.startActivity(intent);
                        }
                    });
                    snackbar.show();
                }
            }
            break;
    }
}

Rupanya, google maps melakukan hal ini untuk izin lokasi.

Abhinav Chauhan
sumber
Terima kasih atas gambar dan tautan Youtube. Ini cocok dengan kurang lebih jawaban saya sendiri. Harus dicatat bahwa pertanyaan diajukan ketika hanya pratinjau pengembang 1 yang tersedia yang tidak memiliki metode shouldShowRequestPermissionRationale.
Emanuel Moecklin
Saya baru di Android dan saya ingin menggunakan metode onRequestPermissionsResult () ini. tapi saya mendapatkan kesalahan bahwa itu harus menerapkan metode tipe super. dapatkah Anda memberi tahu cara menggunakan ini
Andrain
39

Berikut adalah metode yang bagus dan mudah untuk memeriksa status izin saat ini:

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

    public static final int GRANTED = 0;
    public static final int DENIED = 1;
    public static final int BLOCKED_OR_NEVER_ASKED = 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_OR_NEVER_ASKED;
            }
            return DENIED;
        }
        return GRANTED;
    }

Peringatan: mengembalikan BLOCKED_OR_NEVER_ASKED awal aplikasi pertama, sebelum pengguna menerima / menolak izin melalui prompt pengguna (pada sdk 23+ perangkat)

Memperbarui:

Pustaka dukungan Android sekarang juga tampaknya memiliki kelas android.support.v4.content.PermissionCheckeryang sangat mirip yang berisi checkSelfPermission()yang kembali:

public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_DENIED_APP_OP = -2;
Patrick Favre
sumber
1
Untuk peluncuran pertama, saya menyimpan boolean di preferensi bersama.
Saeid Farivar
5
Ini selalu kembali BLOCKED_OR_NEVER_ASKEDjika izin belum diminta.
Saket
6
ya, itulah alasannya disebut "BLOCKED_OR_NEVER_ASKED", juga lihat kalimat terakhir
Patrick Favre
3
android.content.pmsudah mendefinisikan PERMISSION_GRANTED = 0dan PERMISSION_DENIED = -1. Mungkin diatur BLOCKED_OR_NEVER_ASKED = PERMISSION_DENIED - 1atau sesuatu?
samis
Lihat jawaban mVck di bawah ini untuk menangani peringatan.
samis
28

Setelah pengguna menandai "Jangan tanya lagi," pertanyaan tidak dapat ditampilkan lagi. Tetapi dapat dijelaskan kepada pengguna bahwa ia sebelumnya telah menolak izin dan harus memberikan izin dalam pengaturan. Dan rujuk dia ke pengaturan, dengan kode berikut:

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

    if (grantResults.length > 0
            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // now, you have permission go ahead
        // TODO: something

    } else {

        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.READ_CALL_LOG)) {
            // now, user has denied permission (but not permanently!)

        } else {

            // now, user has denied permission permanently!

            Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "You have previously declined this permission.\n" +
                "You must approve this permission in \"Permissions\" in the app settings on your device.", Snackbar.LENGTH_LONG).setAction("Settings", new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + BuildConfig.APPLICATION_ID)));

            }
        });
        View snackbarView = snackbar.getView();
        TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
        textView.setMaxLines(5);  //Or as much as you need
        snackbar.show();

        }

    }
    return;
}
רותם ריכטר
sumber
dalam migrasi ke androidX Anda dapat mengganti android.support.design.R dengan com.google.android.material.R
Ridha Rezzag
26

Semoga bermanfaat bagi seseorang: -

Apa yang saya perhatikan adalah, jika kita memeriksa flag shouldShowRequestPermissionRationale () ke onRequestPermissionsResult () metode panggilan balik, ini hanya menunjukkan dua negara .

Status 1: -Kembalikan benar: - Kapan saja pengguna mengklik Tolak izin (termasuk saat pertama kali).

Status 2: -Returns false: - jika pengguna memilih "tidak pernah bertanya lagi".

Tautan contoh kerja rinci

Torehan
sumber
2
Ini adalah cara yang benar untuk mendeteksi jika pengguna telah memilih opsi jangan pernah bertanya lagi
Muhammad Babar
Ah, kuncinya di sini adalah bahwa Anda menangani ini di onRequestPermissionsResult, bukan ketika benar-benar meminta izin.
Joshua Pinter
26

Anda dapat menentukannya dengan memeriksa apakah izin pemikiran akan ditampilkan di dalam onRequestPermissionsResult()metode panggilan balik. Dan jika Anda menemukan izin yang ditetapkan untuk tidak pernah bertanya lagi , Anda dapat meminta pengguna untuk memberikan izin dari pengaturan.

Implementasi penuh saya akan seperti di bawah ini. Ini berfungsi baik untuk permintaan izin tunggal atau ganda . Gunakan yang berikut atau langsung gunakan perpustakaan saya.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if(permissions.length == 0){
        return;
    }
    boolean allPermissionsGranted = true;
    if(grantResults.length>0){
        for(int grantResult: grantResults){
            if(grantResult != PackageManager.PERMISSION_GRANTED){
                allPermissionsGranted = false;
                break;
            }
        }
    }
    if(!allPermissionsGranted){
        boolean somePermissionsForeverDenied = false;
        for(String permission: permissions){
            if(ActivityCompat.shouldShowRequestPermissionRationale(this, permission)){
                //denied
                Log.e("denied", permission);
            }else{
                if(ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED){
                    //allowed
                    Log.e("allowed", permission);
                } else{
                    //set to never ask again
                    Log.e("set to never ask again", permission);
                    somePermissionsForeverDenied = true;
                }
            }
        }
        if(somePermissionsForeverDenied){
            final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
            alertDialogBuilder.setTitle("Permissions Required")
                    .setMessage("You have forcefully denied some of the required permissions " +
                            "for this action. Please open settings, go to permissions and allow them.")
                    .setPositiveButton("Settings", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                    Uri.fromParts("package", getPackageName(), null));
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }
                    })
                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    })
                    .setCancelable(false)
                    .create()
                    .show();
        }
    } else {
        switch (requestCode) {
            //act according to the request code used while requesting the permission(s).
        }
    }
}
Nabin Bhandari
sumber
hii @ nabin persyaratan saya adalah ketika saya mengklik tombol unduh (yang mengunduh file pdf) waktu itu harus memeriksa izin menulis diizinkan atau ditolak jadi bagaimana cara menggunakan kode ini! bisakah Anda membimbing saya, plz
Rucha Bhatt Joshi
hello @RuchaBhatt Lihatlah perpustakaan saya. github.com/nabinbhandari/Android-Permissions
Nabin Bhandari
15

Jika Anda ingin mendeteksi semua "status" (pertama kali ditolak, baru saja ditolak, baru saja ditolak dengan "Never Ask Again" atau ditolak secara permanen) Anda dapat melakukan hal berikut:

Buat 2 booleans

private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;

Tetapkan yang pertama sebelum meminta izin:

beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Tetapkan yang kedua di dalam metode onRequestPermissionsResult Anda:

afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Gunakan "tabel" berikut untuk melakukan apa pun yang Anda butuhkan di onRequestPermissionsResult () (setelah memeriksa bahwa Anda masih tidak memiliki izin):

// before after
// FALSE  FALSE  =  Was denied permanently, still denied permanently --> App Settings
// FALSE  TRUE   =  First time deny, not denied permanently yet --> Nothing
// TRUE   FALSE  =  Just been permanently denied --> Changing my caption to "Go to app settings to edit permissions"
// TRUE   TRUE   =  Wasn't denied permanently, still not denied permanently --> Nothing
mVck
sumber
Tidak ada gunanya memeriksa shouldShowRequestPermissionRationale sebelum memanggil requestPermissions kecuali Anda ingin menunjukkan alasannya sebelum meminta izin. Menampilkan alasan hanya setelah pengguna menolak izin tampaknya bagaimana sebagian besar aplikasi menanganinya saat ini.
Emanuel Moecklin
2
@ EmanuelMoecklin, sejauh yang saya tahu itu satu-satunya cara untuk memeriksa apakah sudah ditolak (dengan memeriksanya sebelum dan sesudah, seperti yang dijelaskan dalam tabel kebenaran saya) atau jika itu pertama kali ditolak (dalam kasus saya, saya mengarahkan pengguna ke pengaturan aplikasi jika ditolak secara permanen)
mVck
1
// TRUE FALSEjuga terjadi ketika pengguna mengizinkan izin setelah sebelumnya menolaknya.
samis
11

Saya memiliki masalah yang sama dan saya mengatasinya. Untuk membuat hidup lebih sederhana, saya menulis kelas util untuk menangani izin runtime.

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

Dan metode PreferenceUtil adalah sebagai berikut.

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

Sekarang, yang Anda butuhkan adalah menggunakan metode * checkPermission * dengan argumen yang tepat.

Berikut ini sebuah contoh,

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

bagaimana aplikasi saya tahu apakah pengguna telah memeriksa "Never ask again"?

Jika pengguna memeriksa Jangan pernah bertanya lagi , Anda akan mendapatkan panggilan balik di onPermissionDisabled .

Selamat coding :)

muthuraj
sumber
shouldShowRequestPermissionRationale saya mendapat kesalahan di sini, dapatkah Anda membantu saya.
Rucha Bhatt Joshi
saya tidak dapat menemukan metode ini shouldShowRequestPermissionRationale mungkin saya gagal mendapatkan konteks .. tapi tidak apa-apa saya menemukan solusi alternatif lainnya .. Terima kasih atas bantuannya :)
Rucha Bhatt Joshi
1
Salahku. shouldShowRequestPermissionRationale tersedia melalui Aktivitas, bukan konteks. Saya memperbarui jawaban saya dengan mengirimkan konteks ke Aktivitas sebelum memanggil metode itu. Lihat ini :)
muthuraj
1
Ini adalah satu-satunya cara untuk menyiasati nilai palsu pertama yang dikembalikan oleh shouldShowRequestPermissionRationale, menyimpan preferensi permintaan yang dikirim ke pengguna. Saya punya ide yang sama dan menemukan jawaban Anda. Nice job man
MatPag
4

Penjelasan lengkap untuk setiap kasus izin

/**
 *    Case 1: User doesn't have permission
 *    Case 2: User has permission
 *
 *    Case 3: User has never seen the permission Dialog
 *    Case 4: User has denied permission once but he din't clicked on "Never Show again" check box
 *    Case 5: User denied the permission and also clicked on the "Never Show again" check box.
 *    Case 6: User has allowed the permission
 *
 */
public void handlePermission() {
    if (ContextCompat.checkSelfPermission(MainActivity.this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        // This is Case 1. Now we need to check further if permission was shown before or not

        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

            // This is Case 4.
        } else {
            // This is Case 3. Request for permission here
        }

    } else {
        // This is Case 2. You have permission now you can do anything related to it
    }
}

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

    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // This is Case 2 (Permission is now granted)
    } else {
        // This is Case 1 again as Permission is not granted by user

        //Now further we check if used denied permanently or not
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            // case 4 User has denied permission but not permanently

        } else {
            // case 5. Permission denied permanently.
            // You can open Permission setting's page from here now.
        }

    }
}
saksham
sumber
4

Fungsi yang berguna untuk menentukan apakah izin sewenang-wenang telah diblokir untuk meminta (di Kotlin):

private fun isPermissionBlockedFromAsking(activity: Activity, permission: String): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED
            && !activity.shouldShowRequestPermissionRationale(permission)
            && PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false)
    }
    return false
}

Penggunaan ini membutuhkan pengaturan boolean preferensi bersama dengan nama izin yang Anda inginkan (misalnya android.Manifest.permission.READ_PHONE_STATE) trueketika Anda pertama kali meminta izin.


Penjelasan:

Build.VERSION.SDK_INT >= Build.VERSION_CODES.M karena beberapa kode hanya dapat dijalankan pada API level 23+.

ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED untuk memeriksa kami belum memiliki izin.

!activity.shouldShowRequestPermissionRationale(permission)untuk memeriksa apakah pengguna telah menolak permintaan aplikasi lagi. Karena kebiasaan fungsi ini , baris berikut juga diperlukan.

PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false) ini digunakan (bersama dengan menyetel nilai ke true pada permintaan izin pertama) untuk membedakan antara status "Never ask" dan "Never ask again", karena baris sebelumnya tidak mengembalikan informasi ini.

JakeSteam
sumber
4

Metode shouldShowRequestPermissionRationale () dapat digunakan untuk memeriksa apakah pengguna memilih opsi 'tidak pernah ditanya lagi' dan menolak izin. Ada banyak contoh kode, jadi saya lebih suka menjelaskan cara menggunakannya untuk tujuan seperti itu, karena saya pikir nama dan implementasinya membuat ini lebih rumit dari yang sebenarnya.

Seperti dijelaskan dalam Meminta Izin saat Jalankan , metode itu mengembalikan true jika opsi 'tidak pernah bertanya lagi' terlihat, salah jika tidak; sehingga mengembalikan false saat pertama kali dialog ditampilkan, kemudian dari yang kedua kembali benar, dan hanya jika pengguna menolak izin memilih opsi, pada saat itu kembali palsu.

Untuk mendeteksi kasus seperti itu, Anda dapat mendeteksi urutan false-true-false, atau (lebih sederhana) Anda dapat memiliki bendera yang melacak waktu awal dialog ditampilkan. Setelah itu, metode itu mengembalikan benar atau salah, di mana yang palsu akan memungkinkan Anda untuk mendeteksi ketika opsi tersebut dipilih.

Alessio
sumber
3

Tolong jangan melempari saya dengan batu untuk solusi ini.

Ini berfungsi tetapi sedikit "retas".

Saat Anda menelepon requestPermissions, daftarkan waktu saat ini.

        mAskedPermissionTime = System.currentTimeMillis();

Lalu masuk onRequestPermissionsResult

jika hasilnya tidak diberikan, periksa waktu lagi.

 if (System.currentTimeMillis() - mAskedPermissionTime < 100)

Karena pengguna tidak mungkin mengklik begitu cepat pada tombol tolak, kami tahu bahwa ia memilih "tidak pernah bertanya lagi" karena panggilan baliknya instan.

Gunakan dengan risiko Anda sendiri.

Antzi
sumber
bagaimana jika kita melihat dialog yang diminta selama 5 menit dan kemudian menolak?
saksham
Lalu apa gunanya ini jika tidak dapat memenuhi persyaratan dasar. Kode dapat berupa retasan yang diterima jika kode itu jelas memenuhi semua persyaratan dalam setiap kasus yang lain tidak.
saksham
Ya ini buruk. Penguji otomatis seperti ini mungkin dapat mengatur untuk mengklik lebih cepat dari itu: developer.android.com/training/testing/crawler
stackzebra
2

Saya menulis singkatan untuk permintaan izin di Android M. Kode ini juga menangani kompatibilitas ke belakang ke versi Android yang lebih lama.

Semua kode jelek diekstraksi menjadi Fragmen yang melampirkan dan melepaskan dirinya sendiri ke Aktivitas yang meminta izin. Anda dapat menggunakan PermissionRequestManagersebagai berikut:

new PermissionRequestManager()
        // We need a AppCompatActivity here, if you are not using support libraries you will have to slightly change 
        // the PermissionReuqestManager class
        .withActivity(this)

        // List all permissions you need
        .withPermissions(android.Manifest.permission.CALL_PHONE, android.Manifest.permission.READ_CALENDAR)

        // This Runnable is called whenever the request was successfull
        .withSuccessHandler(new Runnable() {
            @Override
            public void run() {
                // Do something with your permissions!
                // This is called after the user has granted all 
                // permissions, we are one a older platform where 
                // the user does not need to grant permissions 
                // manually, or all permissions are already granted

            }
        })

        // Optional, called when the user did not grant all permissions
        .withFailureHandler(new Runnable() {
            @Override
            public void run() {
                // This is called if the user has rejected one or all of the requested permissions
                L.e(this.getClass().getSimpleName(), "Unable to request permission");

            }
        })

        // After calling this, the user is prompted to grant the rights
        .request();

Lihatlah: https://gist.github.com/crysxd/385b57d74045a8bd67c4110c34ab74aa

crysxd
sumber
2
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
            if (grantResults.length > 0) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    // Denied
                } else {
                    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                        // To what you want
                    } else {
                       // Bob never checked click
                    }
                }
            }
        }
    }
}
Vinod Ranga
sumber
2

Coba pustaka izin sederhana ini. Ini akan menangani semua operasi yang terkait dengan izin dalam 3 langkah mudah. Ini menghemat waktu saya. Anda dapat menyelesaikan semua pekerjaan terkait izin dalam 15 menit .

Dapat menangani Deny, Dapat menangani Tidak pernah bertanya lagi, Dapat memanggil pengaturan aplikasi untuk izin, Dapat memberikan pesan Rasional, Dapat memberikan pesan Penolakan, Dapat memberikan daftar izin yang diterima, Dapat memberikan daftar ditolak izin dan lain-lain

https://github.com/ParkSangGwon/TedPermission

Langkah 1: tambahkan ketergantungan Anda

dependencies {
     compile 'gun0912.ted:tedpermission:2.1.1'
     //check the above link for latest libraries
}

Langkah2: Minta izin

TedPermission.with(this)
    .setPermissionListener(permissionlistener)
    .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
    .setPermissions(Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION)
    .check();

Langkah 3: Menangani respons izin

PermissionListener permissionlistener = new PermissionListener() {
    @Override
    public void onPermissionGranted() {
        Toast.makeText(MainActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onPermissionDenied(ArrayList<String> deniedPermissions) {
        Toast.makeText(MainActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
    }
};
Vignes
sumber
Bagus. Ini menghemat waktu saya
Vigneswaran A
Bagus, mudah digunakan
Uray Febri
2

Anda bisa mendengarkan dengan cantik.

Pendengar

interface PermissionListener {
    fun onNeedPermission()
    fun onPermissionPreviouslyDenied(numberDenyPermission: Int)
    fun onPermissionDisabledPermanently(numberDenyPermission: Int)
    fun onPermissionGranted()
}

MainClass untuk izin

class PermissionUtil {

    private val PREFS_FILENAME = "permission"
    private val TAG = "PermissionUtil"

    private fun shouldAskPermission(context: Context, permission: String): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val permissionResult = ActivityCompat.checkSelfPermission(context, permission)
            if (permissionResult != PackageManager.PERMISSION_GRANTED) {
                return true
            }
        }
        return false
    }

    fun checkPermission(context: Context, permission: String, listener: PermissionListener) {

        Log.i(TAG, "CheckPermission for $permission")

        if (shouldAskPermission(context, permission)) {

            // Load history permission
            val sharedPreference = context.getSharedPreferences(PREFS_FILENAME, 0)
            val numberShowPermissionDialog = sharedPreference.getInt(permission, 0)

            if (numberShowPermissionDialog == 0) {

                (context as? Activity)?.let {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(it, permission)) {
                        Log.e(TAG, "User has denied permission but not permanently")
                        listener.onPermissionPreviouslyDenied(numberShowPermissionDialog)
                    } else {
                        Log.e(TAG, "Permission denied permanently.")
                        listener.onPermissionDisabledPermanently(numberShowPermissionDialog)
                    }
                } ?: kotlin.run {
                    listener.onNeedPermission()
                }

            } else {
                // Is FirstTime
                listener.onNeedPermission()
            }


            // Save history permission
            sharedPreference.edit().putInt(permission, numberShowPermissionDialog + 1).apply()


        } else {
            listener.onPermissionGranted()
        }

    }
}

Digunakan dengan cara ini

      PermissionUtil().checkPermission(this, Manifest.permission.ACCESS_FINE_LOCATION,
                object : PermissionListener {
                    override fun onNeedPermission() {
                        log("---------------------->onNeedPermission")

//                            ActivityCompat.requestPermissions(this@SplashActivity,
//                                    Array(1) { Manifest.permission.ACCESS_FINE_LOCATION },
//                                    118)

                    }

                    override fun onPermissionPreviouslyDenied(numberDenyPermission: Int) {
                        log("---------------------->onPermissionPreviouslyDenied")
                    }

                    override fun onPermissionDisabledPermanently(numberDenyPermission: Int) {
                        log("---------------------->onPermissionDisabled")
                    }

                    override fun onPermissionGranted() {
                        log("---------------------->onPermissionGranted")
                    }

                })

menimpa padaRequestPermissionsHasil kembali aktivitas atau fragmnet

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
 if (requestCode == 118) {
        if (permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            getLastLocationInMap()
        }
        }
    }
Rasoul Miri
sumber
1

Alih-alih, Anda akan menerima panggilan balik pada onRequestPermissionsResult()PERMISSION_DENIED saat Anda meminta izin lagi saat jatuh dalam kondisi salahshouldShowRequestPermissionRationale()

Dari Android doc:

Ketika sistem meminta pengguna untuk memberikan izin, pengguna memiliki opsi untuk memberitahu sistem untuk tidak meminta izin itu lagi. Dalam hal itu, kapan saja aplikasi menggunakan requestPermissions()untuk meminta izin itu lagi, sistem segera menolak permintaan itu. Sistem memanggil onRequestPermissionsResult()metode panggilan balik Anda dan lolos PERMISSION_DENIED, sama seperti jika pengguna menolak permintaan Anda secara eksplisit lagi. Ini berarti bahwa ketika Anda menelepon requestPermissions(), Anda tidak dapat mengasumsikan bahwa interaksi langsung dengan pengguna telah terjadi.

Farhan
sumber
1

Kamu bisa memakai if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) metode untuk mendeteksi apakah tidak pernah meminta dicentang atau tidak.

Untuk referensi lebih lanjut: Periksa ini

Untuk memeriksa beberapa izin gunakan:

  if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
                            showDialogOK("Service Permissions are 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.
                                                    finish();
                                                    break;
                                            }
                                        }
                                    });
                        }
                        //permission is denied (and never ask again is  checked)
                        //shouldShowRequestPermissionRationale will return false
                        else {
                            explain("You need to give some mandatory permissions to continue. Do you want to go to app settings?");
                            //                            //proceed with logic by disabling the related features or quit the app.
                        }

jelaskan metode ()

private void explain(String msg){
        final android.support.v7.app.AlertDialog.Builder dialog = new android.support.v7.app.AlertDialog.Builder(this);
        dialog.setMessage(msg)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        //  permissionsclass.requestPermission(type,code);
                        startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:com.exampledemo.parsaniahardik.marshmallowpermission")));
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        finish();
                    }
                });
        dialog.show();
    }

Kode di atas juga akan menampilkan dialog, yang akan mengarahkan pengguna ke layar pengaturan aplikasi dari mana ia dapat memberikan izin jika telah diperiksa tombol jangan pernah bertanya lagi.

user6435056
sumber
1

Kamu bisa memakai

shouldShowRequestPermissionRationale()

dalam

onRequestPermissionsResult()

Lihat contoh di bawah ini:

Periksa apakah ada izin ketika pengguna mengklik tombol:

@Override
public void onClick(View v) {
    if (v.getId() == R.id.appCompatBtn_changeProfileCoverPhoto) {
        if (Build.VERSION.SDK_INT < 23) { // API < 23 don't need to ask permission
            navigateTo(MainActivity.class); // Navigate to activity to change photos
        } else {
            if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                // Permission is not granted yet. Ask for permission...
                requestWriteExternalPermission();
            } else {
                // Permission is already granted, good to go :)
                navigateTo(MainActivity.class);
            }
        } 
    }
}

Ketika pengguna menjawab kotak dialog izin kita akan pergi ke onRequestPermissionResult:

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

    if (requestCode == WRITE_EXTERNAL_PERMISSION_REQUEST_CODE) {
        // Case 1. Permission is granted.  
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {  
            if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                // Before navigating, I still check one more time the permission for good practice.
                navigateTo(MainActivity.class);
            }
        } else { // Case 2. Permission was refused
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                // Case 2.1. shouldShowRequest... returns true because the
                // permission was denied before. If it is the first time the app is running we will 
                // end up in this part of the code. Because he need to deny at least once to get 
                // to onRequestPermissionsResult. 
                Snackbar snackbar = Snackbar.make(findViewById(R.id.relLayout_container), R.string.you_must_verify_permissions_to_send_media, Snackbar.LENGTH_LONG);
                snackbar.setAction("VERIFY", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        ActivityCompat.requestPermissions(SettingsActivity.this
                                , new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}
                                , WRITE_EXTERNAL_PERMISSION_REQUEST_CODE);
                    }
                });
                snackbar.show();
            } else {
                // Case 2.2. Permission was already denied and the user checked "Never ask again". 
                // Navigate user to settings if he choose to allow this time.
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(R.string.instructions_to_turn_on_storage_permission)
                        .setPositiveButton(getString(R.string.settings), new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Intent settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                Uri uri = Uri.fromParts("package", getPackageName(), null);
                                settingsIntent.setData(uri);
                                startActivityForResult(settingsIntent, 7);
                            }
                        })
                        .setNegativeButton(getString(R.string.not_now), null);
                Dialog dialog = builder.create();
                dialog.show();
            }
        }
    }

}
Segera Santos
sumber
0

Saya juga ingin mendapatkan informasi apakah pengguna telah memilih "tidak pernah bertanya lagi". Saya telah mencapai 'hampir solusi' dengan bendera yang terlihat jelek, tetapi sebelum saya memberitahu Anda caranya, saya akan memberi tahu Anda tentang motivasi saya:

Saya ingin menawarkan fungsionalitas yang merujuk izin pada awalnya. Jika pengguna menggunakannya dan tidak memiliki hak, ia mendapatkan dialog ke-1 dari atas atau ke-2 dan ke-3. Ketika pengguna memilih 'Never ask again', saya ingin menonaktifkan fungsi dan menampilkannya secara berbeda. - Tindakan saya dipicu oleh entri teks pemintal, saya juga ingin menambahkan '(Izin dicabut)' ke teks label yang ditampilkan. Ini menunjukkan kepada pengguna: 'Ada fungsionalitas tetapi saya tidak dapat menggunakannya, karena pengaturan izin saya.' Namun, ini sepertinya tidak mungkin, karena saya tidak dapat memeriksa apakah 'Never ask again' telah dipilih atau tidak.

Saya datang ke solusi yang bisa saya jalani dengan memiliki fungsi saya selalu diaktifkan dengan pemeriksaan izin aktif. Saya menunjukkan pesan Toast di onRequestPermissionsResult () jika ada respons negatif tetapi hanya jika saya belum menampilkan munculan rasional kustom saya. Jadi, jika pengguna telah memilih 'Jangan tanya lagi', ia hanya menerima pesan roti panggang. Jika pengguna enggan untuk memilih 'tidak pernah bertanya lagi' ia hanya mendapatkan alasan khusus dan permintaan izin muncul dengan sistem operasi tetapi tidak bersulang, karena tiga pemberitahuan berturut-turut akan terlalu menyakitkan.

ChristianKoelle
sumber
0

Saya harus menerapkan izin dinamis untuk kamera. Di mana 3 kemungkinan kasus terjadi: 1. Izinkan, 2. Ditolak, 3. Jangan tanya lagi.

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

    for (String permission : permissions) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permission)) {
            //denied
            Log.e("denied", permission);
        } else {
            if (ActivityCompat.checkSelfPermission(getActivity(), permission) == PackageManager.PERMISSION_GRANTED) {
                //allowed
                Log.e("allowed", permission);
            } else {
                //set to never ask again
                Log.e("set to never ask again", permission);
                //do something here.
            }
        }
    }
    if (requestCode != MaterialBarcodeScanner.RC_HANDLE_CAMERA_PERM) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        return;
    }
    if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        mScannerView.setResultHandler(this);
        mScannerView.startCamera(mCameraId);
        mScannerView.setFlash(mFlash);
        mScannerView.setAutoFocus(mAutoFocus);
        return;
    } else {
        //set to never ask again
        Log.e("set to never ask again", permissions[0]);
    }
    DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
        }
    };
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setTitle("Error")
            .setMessage(R.string.no_camera_permission)
            .setPositiveButton(android.R.string.ok, listener)
            .show();


}

private void insertDummyContactWrapper() {
        int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CAMERA);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.CAMERA},
                    REQUEST_CODE_ASK_PERMISSIONS);
            return;
        }
        mScannerView.setResultHandler(this);
        mScannerView.startCamera(mCameraId);
        mScannerView.setFlash(mFlash);
        mScannerView.setAutoFocus(mAutoFocus);
    }

private int checkSelfPermission(String camera) {
    if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        return REQUEST_CODE_ASK_PERMISSIONS;
    } else {
        return REQUEST_NOT_CODE_ASK_PERMISSIONS;
    }
}
hitesh141
sumber
0

Memperluas jawaban mVck di atas, logika berikut menentukan apakah "Never ask again" telah diperiksa untuk Permission Permission yang diberikan:

bool bStorage = grantResults[0] == Permission.Granted;
bool bNeverAskForStorage =
    !bStorage && (
        _bStorageRationaleBefore == true  && _bStorageRationaleAfter == false ||
        _bStorageRationaleBefore == false && _bStorageRationaleAfter == false
    );

yang dikutip dari bawah (untuk contoh lengkap lihat jawaban ini )

private bool _bStorageRationaleBefore;
private bool _bStorageRationaleAfter;        
private const int ANDROID_PERMISSION_REQUEST_CODE__SDCARD = 2;
//private const int ANDROID_PERMISSION_REQUEST_CODE__CAMERA = 1;
private const int ANDROID_PERMISSION_REQUEST_CODE__NONE = 0;

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode)
    {
        case ANDROID_PERMISSION_REQUEST_CODE__SDCARD:               
            _bStorageRationaleAfter = ShouldShowRequestPermissionRationale(Android.Manifest.Permission.WriteExternalStorage);
            bool bStorage = grantResults[0] == Permission.Granted;
            bool bNeverAskForStorage =
                !bStorage && (
                    _bStorageRationaleBefore == true  && _bStorageRationaleAfter == false ||
                    _bStorageRationaleBefore == false && _bStorageRationaleAfter == false
                );      
            break;                
    }
}

private List<string> GetRequiredPermissions(out int requestCode)
{
    // Android v6 requires explicit permission granting from user at runtime for security reasons            
    requestCode = ANDROID_PERMISSION_REQUEST_CODE__NONE; // 0
    List<string> requiredPermissions = new List<string>();

    _bStorageRationaleBefore = ShouldShowRequestPermissionRationale(Android.Manifest.Permission.WriteExternalStorage);
    Permission writeExternalStoragePerm = ApplicationContext.CheckSelfPermission(Android.Manifest.Permission.WriteExternalStorage);
    //if(extStoragePerm == Permission.Denied)
    if (writeExternalStoragePerm != Permission.Granted)
    {
        requestCode |= ANDROID_PERMISSION_REQUEST_CODE__SDCARD;
        requiredPermissions.Add(Android.Manifest.Permission.WriteExternalStorage);
    }

    return requiredPermissions;
}

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

        // Android v6 requires explicit permission granting from user at runtime for security reasons
        int requestCode;
        List<string> requiredPermissions = GetRequiredPermissions(out requestCode);
        if (requiredPermissions != null && requiredPermissions.Count > 0)
        {
            if (requestCode >= ANDROID_PERMISSION_REQUEST_CODE__SDCARD)                    
            {
                _savedInstanceState = savedInstanceState;
                RequestPermissions(requiredPermissions.ToArray(), requestCode);
                return;
            }
        }
    }            

    OnCreate2(savedInstanceState);
}
Sam adalah
sumber
0

Anda dapat membaca dokumen resmi Izin Aplikasi Android

atau Anda dapat menemukan banyak perpustakaan izin android populer di Github

shellhub
sumber
2
Hanya menyarankan perpustakaan bukan jawaban yang baik: setidaknya jelaskan bagaimana menggunakannya untuk menyelesaikan masalah.
M. Prokhorov
0

Untuk menjawab pertanyaan dengan tepat, Apa yang terjadi ketika pengguna menekan "Never Ask Again"?

Metode / fungsi yang ditimpa

onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray)

Array grantResult keluar menjadi Kosong, sehingga Anda dapat melakukan sesuatu di sana mungkin? Tapi bukan praktik terbaik.

Bagaimana Cara Menangani "Never Ask Again"?

Saya bekerja dengan Fragment, yang membutuhkan izin READ_EXTERNAL_STORAGE.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        when {
            isReadPermissionsGranted() -> {

                /**
                 * Permissions has been Granted
                 */

                getDirectories()
            }

            isPermissionDeniedBefore() -> {

                /**
                 * User has denied before, explain why we need the permission and ask again
                 */

                updateUIForDeniedPermissions()
                checkIfPermissionIsGrantedNow()

            }
            else -> {

                /**
                 * Need to ask For Permissions, First Time
                 */

                checkIfPermissionIsGrantedNow()

                /**
                 * If user selects, "Dont Ask Again" it will never ask again! so just update the UI for Denied Permissions
                 */

                updateUIForDeniedPermissions()

            }
        }
    }

Fungsi lainnya sepele.

// Is Read Write Permissions Granted
fun isReadWritePermissionGranted(context: Context): Boolean {
    return (ContextCompat.checkSelfPermission(
        context as Activity,
        Manifest.permission.READ_EXTERNAL_STORAGE
    ) == PackageManager.PERMISSION_GRANTED) and
            (ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED)
}

fun isReadPermissionDenied(context: Context) : Boolean {
    return ActivityCompat.shouldShowRequestPermissionRationale(
        context as Activity,
        PermissionsUtils.READ_EXTERNAL_STORAGE_PERMISSIONS)
}
devDeejay
sumber