これによると: http://developer.Android.com/preview/features/runtime-permissions.html#coding アプリは実行時権限を確認し、まだ付与されていない場合は権限を要求できます。すると以下のようなダイアログが表示されます。
ユーザーが重要な許可を拒否した場合、許可が必要な理由と拒否に与える影響についての説明をアプリに表示する必要があります。そのダイアログには2つのオプションがあります。
しかし、ユーザーがNever ask again
をチェックした場合、特にユーザーがすでに一度も断った場合は、説明付きの2番目のダイアログは表示されません。今度の質問は、ユーザーがNever ask again
をチェックしたかどうかをアプリがどうやって確認するのかということです。 IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
は私にその情報を与えてくれません。
2つ目の質問は次のとおりです。Googleでは、許可ダイアログにカスタムメッセージを組み込んで、アプリに許可が必要な理由を説明する予定はありますか。そうすれば、確かに良いuxのためになるだろう第二の対話は決してないでしょう。
Developer Preview 2では、アプリによるアクセス権の要求方法に変更が加えられています( http://developer.Android.com/preview/support.html#preview2-notes も参照)。
最初のダイアログはこのようになります。
(開発者プレビュー1とは異なり)「二度と表示しない」チェックボックスはありません。ユーザーが許可を拒否し、許可がアプリにとって不可欠である場合、アプリがその許可を要求する理由を説明するために別のダイアログを表示することができます。このような:
ユーザーが再度拒否した場合は、その許可が絶対に必要な場合はアプリをシャットダウンするか、機能を制限してアプリを実行し続けます。ユーザーが再検討する(そして再試行を選択する)と、許可が再度要求されます。今回はプロンプトは次のようになります。
2回目には、「二度と聞かない」チェックボックスが表示されます。ユーザーが再度拒否し、チェックボックスがチェックされている場合、これ以上何も起こらないはずです。チェックボックスがチェックされているかどうかは、Activity.shouldShowRequestPermissionRationale(String)を使用して判断できます。このような:
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {...
それがAndroidのドキュメントに書かれていることです( https://developer.Android.com/training/permissions/request.html )。
説明を追加する必要がある状況を見つけやすくするために、Activity.shouldShowRequestPermissionRationale(String)メソッドが用意されています。アプリが以前にこの権限を要求し、ユーザーがその要求を拒否した場合、このメソッドはtrueを返します。それはあなたがおそらくあなたが許可を必要とする理由を説明するべきであることを示しています。
ユーザが過去に許可要求を拒否し、許可要求システムダイアログで[今後要求しない]オプションを選択した場合、このメソッドはfalseを返します。デバイスポリシーがアプリにその許可の付与を禁止している場合も、このメソッドはfalseを返します。
ユーザーが「二度と尋ねない」で拒否されたかどうかを知るには、ユーザーが権限を付与しなかったときに、onRequestPermissionsResultの shouldShowRequestPermissionRationale メソッドをもう一度確認します。
@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...*/ ) {
}
}
}
}
}
あなたはこのコードであなたのアプリ設定を開くことができます:
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
ユーザーを承認ページに直接送信する方法はありません。
shouldShowRequestPermissionRationale()
でonRequestPermissionsResult()
を確認できます。
https://youtu.be/C8lUdPVSzDk?t=2m23s
onRequestPermissionsResult()
にパーミッションが付与されているかどうかを確認してください。でなければshouldShowRequestPermissionRationale()
をチェックしてください。
true
を返す場合は、なぜこの特定の権限が必要なのかの説明を表示してください。それからユーザーの選択次第でrequestPermissions()
。false
が返された場合は、パーミッションが付与されていないため、アプリケーションを続行できない、または特定の機能が無効になっているというエラーメッセージを表示します。以下はサンプルコードです。
@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;
}
}
どうやら、グーグルマップは位置許可のためにまさにこれをします。
これは現在の許可ステータスをチェックするための素晴らしく簡単な方法です:
@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;
}
警告:ユーザーがユーザープロンプトを使用して許可を承認/拒否する前に、最初のアプリ起動時にBLOCKED_OR_NEVER_ASKEDを返します(sdk 23+デバイスの場合)
更新:
Androidのサポートライブラリは、非常によく似たクラスAndroid.support.v4.content.PermissionChecker
を持っているようです。これはcheckSelfPermission()
を返します。
public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_DENIED_APP_OP = -2;
パーミッションrationaleがonRequestPermissionsResult()
コールバックメソッドの中に表示されるべきかどうかをチェックすることでそれを決定できるします。また、二度と要求しないに設定されている権限がある場合は、設定から権限を付与するようにユーザーに要求できます。
私の完全な実装は以下のようになります。これはsingleまたはmultipleの両方のアクセス許可要求に対して機能します。次のものを使用するか 私のライブラリを直接使用してください。
@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).
}
}
}
誰かに役立つかもしれません: -
私が気づいたことは、onRequestPermissionsResult()コールバックメソッドにshouldShowRequestPermissionRationale()フラグをチェックインすると、2つの状態しか表示されないことです 。
状態1: - trueに戻る: - ユーザーが[拒否]アクセス許可をクリックしたとき(初回を含む)。
状態2: - 偽を返す: - ユーザが「二度と尋ねない」を選択した場合。
ユーザが「再度質問しない」とマークすると、質問を再度表示することはできません。しかし、それは彼が以前に許可を拒否しており、設定で許可を付与する必要があることをユーザーに説明することができます。次のコードを使って、設定を参照してください。
@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;
}
すべての「状態」(最初に拒否された、ちょうど拒否された、「もう一度確認しない」で拒否された、または完全に拒否された)をすべて検出する場合は、次のようにします。
2つのブール値を作成する
private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;
許可を求める前に最初のものを設定します。
beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);
OnRequestPermissionsResultメソッド内に2番目のものを設定します。
afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);
OnRequestPermissionsResult()で必要なことをすべて実行するには、次の「テーブル」を使用します(まだ権限がないことを確認した後)。
// 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
私は同じ問題を抱えていたので、私はそれを考え出しました。人生をもっと簡単にするために、実行時権限を処理するための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();
}
});
私のアプリはどのようにユーザーが "二度と尋ねない"をチェックしたかどうかを知るのですか?
ユーザーがチェックした場合 二度と質問しない 、コールバックが onPermissionDisabled になる.
ハッピーコーディング:)
許可のすべての場合についての完全な説明
/**
* 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.
}
}
}
私はAndroid Mでパーミッションリクエストの省略形を書きました。このコードは古いAndroidバージョンとの後方互換性も扱います。
醜いコードはすべて、パーミッションを要求しているアクティビティにアタッチしたりデタッチしたりするフラグメントに抽出されます。次のようにPermissionRequestManager
を使用できます。
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();
見てみましょう: https://Gist.github.com/crysxd/385b57d74045a8bd67c4110c34ab74aa
任意の許可が要求からブロックされているかどうかを判断するのに便利な機能(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
}
これを使用するには、あなたが最初にパーミッションを要求したときにあなたの望むパーミッションの名前(例えばAndroid.Manifest.permission.READ_PHONE_STATE
)を持つ共有設定ブール値をtrue
に設定する必要があります。
説明:
一部のコードとしてのBuild.VERSION.SDK_INT >= Build.VERSION_CODES.M
は、APIレベル23以降でのみ実行できます。
確認するためのContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED
は、まだ許可を得ていません。
!activity.shouldShowRequestPermissionRationale(permission)
は、ユーザーがアプリに再度要求を拒否したかどうかを確認します。 この関数の癖 のために、次の行も必要です。
PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false)
これは(最初の許可要求で値をtrueに設定すると共に)「前に要求された」と「二度と要求されない」の状態を区別するために使用されます。前の行はこの情報を返さないからです。
メソッド shouldShowRequestPermissionRationale() は、ユーザーが「二度と質問しない」オプションを選択し、許可を拒否したかどうかを確認するユーザーになることができます。たくさんのコード例があるので、私はその名前とその実装が実際にはこれをより複雑にすると思うので、私はむしろそのような目的のためにそれを使う方法を説明したいと思います。
実行時のアクセス許可の要求 で説明されているように、このメソッドは、オプション 'never never again'が表示されている場合はtrue、それ以外の場合はfalseを返します。そのため、ダイアログが最初に表示されたときにはfalseを返し、2回目以降はtrueを返し、ユーザーがオプションの選択を許可されていない場合にのみ、その時点で再びfalseを返します。
そのような場合を検出するには、シーケンスfalse-true-falseを検出するか、(もっと簡単に)ダイアログが表示される最初の時間を追跡するフラグを持つことができます。その後、そのメソッドはtrueまたはfalseのいずれかを返します。ここでfalseを使用すると、オプションが選択されたときに検出できます。
このシンプルなパーミッションライブラリを試してください。それは3つの簡単なステップで許可に関連するすべての操作を扱います。それは私の時間を節約しました。 あなたは15分ですべての許可関連の仕事を終えることができます 。
Denyを処理することができます、処理することはできませんNever Ask again、許可を得るためにアプリの設定を呼び出すことができます。権限など.
https://github.com/ParkSangGwon/TedPermission
ステップ1: 依存関係を追加する
dependencies {
compile 'gun0912.ted:tedpermission:2.1.1'
//check the above link for latest libraries
}
ステップ2: 許可を求める
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();
ステップ3: 許可応答を処理する
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();
}
};
あなたが使用することができます
shouldShowRequestPermissionRationale()
内部
onRequestPermissionsResult()
以下の例を見てください。
ユーザーがボタンをクリックしたときに権限があるかどうかを確認します。
@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);
}
}
}
}
ユーザーが許可ダイアログボックスに答えると、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();
}
}
}
}
この解決策のために私に石を投げないでください。
これは動作しますが、少し「ハッキー」です。
requestPermissions
を呼び出したら、現在時刻を登録します。
mAskedPermissionTime = System.currentTimeMillis();
それでonRequestPermissionsResult
に
結果が認められない場合は、もう一度時間を確認してください。
if (System.currentTimeMillis() - mAskedPermissionTime < 100)
ユーザーが拒否ボタンをあまり速くクリックできなかったので、コールバックが即時であるため、「二度と質問しない」を選択したことがわかります。
ご自身の責任で使用してください。
あなたはきれいに聞くことができます。
リスナー
interface PermissionListener {
fun onNeedPermission()
fun onPermissionPreviouslyDenied(numberDenyPermission: Int)
fun onPermissionDisabledPermanently(numberDenyPermission: Int)
fun onPermissionGranted()
}
許可のためのMainClass
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()
}
}
}
このように使われる
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")
}
})
アクティビティまたはフラグネットでonRequestPermissionsResultを上書きする
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()
}
}
}
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
}
}
}
}
}
}
上記の mVck の回答を拡張して、次のロジックは、指定された許可要求に対して「二度と尋ねない」がチェックされているかどうかを判断します。
bool bStorage = grantResults[0] == Permission.Granted;
bool bNeverAskForStorage =
!bStorage && (
_bStorageRationaleBefore == true && _bStorageRationaleAfter == false ||
_bStorageRationaleBefore == false && _bStorageRationaleAfter == false
);
これは下から抜粋されています(完全な例についてはこれを参照してください answer )
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);
}
代わりにonRequestPermissionsResult()
の偽の状態に陥っている間に再度許可を要求すると、PERMISSION_DENIEDとしてshouldShowRequestPermissionRationale()
のコールバックを受け取ります。
Androidのドキュメントから:
システムがユーザーに許可を与えるように要求すると、ユーザーはシステムにその許可を再度要求しないように指示することができます。その場合、アプリがrequestPermissions()
を使用してその許可を再度要求するたびに、システムはすぐにその要求を拒否します。システムがonRequestPermissionsResult()
コールバックメソッドを呼び出し、PERMISSION_DENIED
を渡します。これは、ユーザーが再度明示的に要求を拒否した場合と同じ方法です。つまり、requestPermissions()
を呼び出したときに、ユーザーと直接対話したとは限りません。
質問に正確に答えるには、 ユーザーが "Never Ask Again"を押すとどうなりますか?
オーバーライドされたメソッド/機能
onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray)
GrantResult配列がEmptyになるので、そこで何かできることがありますか?しかしベストプラクティスではありません。
「二度と聞かないでください」を処理する方法?
私はフラグメントを操作しています。これには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()
}
}
}
他の機能は簡単です。
// 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)
}
あなたはAndroidの公式文書を読むことができます アプリのアクセス許可を要求
それともGithubで多くの人気のあるAndroidパーミッションライブラリを見つけることができます。
また、「二度と質問しない」を選択したかどうかについても情報を取得したいと思います。私は、見栄えの悪いフラグで「ほぼ解決策」を達成しましたが、その方法を説明する前に、私のモチベーションについて説明します。
最初に機能を参照する許可を提供したいと思います。ユーザーがそれを使用していて権限がない場合は、上から1番目のダイアログ、または2番目と3番目の両方のダイアログを取得します。ユーザーが[今後確認しない]を選択した場合は、機能を無効にして表示方法を変更します。 - 私の行動はスピナーテキスト入力によって引き起こされます、私はまた表示されたラベルテキストに '(Permission revoked)'を追加したいと思います。これは、ユーザーに示しています。「機能はありますが、権限設定のため使用できません。」しかし、これは不可能だと思われます。「二度と尋ねない」が選択されているかどうかを確認できないからです。
私は自分の機能を常に有効な権限チェックで有効にしておくことで解決できるソリューションを見つけました。否定的な応答の場合にonRequestPermissionsResult()にToastメッセージを表示していますが、カスタムの論理的根拠のポップアップを表示していない場合に限ります。そのため、ユーザーが「二度と聞かない」を選択した場合は、トーストメッセージのみが表示されます。ユーザが「二度と聞かない」を選択したがらない場合、ユーザはカスタム論理的根拠と許可要求ポップアップのみをオペレーティングシステムによってポップアップ表示されますが、トーストでは表示されません。
カメラに対する動的許可を実装する必要があります。 3つの可能性がある場合:1.許可、2.拒否、3.再度要求しない.
@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;
}
}
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
メソッドを使用して、never askがチェックされているかどうかを検出できます。
より多くの参照のために: これをチェックしなさい
複数の権限を確認するには、次のコマンドを使用します。
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.
}
explain()メソッド
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();
}
上記のコードではダイアログが表示されます。このダイアログでは、[二度と確認しない]ボタンをオンにした場合に許可を与えることができるアプリケーション設定画面にユーザーをリダイレクトします。