根据这个:http://developer.android.com/preview/features/runtime-permissions.html#coding一个应用程序可以检查运行时权限和请求权限(如果尚未授予它)。然后将显示以下对话框:
如果用户拒绝重要权限,则应用程序应显示解释为何需要权限以及拒绝具有何种影响的解释。该对话框有两个选项:
但是,如果用户检查Never ask again
,则不应显示带有解释的第二个对话框,尤其是如果用户之前已经拒绝过一次。
现在的问题是:我的应用程序如何知道用户是否已检查Never ask again
? IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
没有给我这些信息。
第二个问题是:Google是否计划在权限对话框中添加自定义消息,以解释应用程序需要权限的原因?那样就永远不会有第二个对话框,肯定会有更好的ux。
答案 0 :(得分:310)
开发者预览版2对应用程序请求权限的方式进行了一些更改(另请参阅http://developer.android.com/preview/support.html#preview2-notes)。
现在第一个对话框如下所示:
没有“Never again again”复选框(与开发者预览1不同)。如果用户拒绝该权限,并且该权限对于该应用程序至关重要,则可以提供另一个对话框来解释该应用程序要求该权限的原因,例如:像这样:
如果用户再次拒绝该应用应该在完全需要该权限时关闭,或者继续以有限的功能运行。如果用户重新考虑(并选择重试),则再次请求权限。这次提示符如下所示:
第二次显示“Never ask again”复选框。如果用户再次拒绝并且勾选了复选框,则不会再发生任何事情。 是否勾选了复选框可以通过使用Activity.shouldShowRequestPermissionRationale(String)来确定,例如,像这样:
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {...
这就是Android文档所说的内容(https://developer.android.com/training/permissions/requesting.html):
帮助您找到需要额外提供的情况 解释,系统提供 Activity.shouldShowRequestPermissionRationale(String)方法。这个 如果应用已请求此权限,则method返回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);
无法将用户直接发送到“授权”页面。
答案 1 :(得分:86)
您可以在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;
}
}
显然,谷歌地图确实是为了获得位置许可。
答案 2 :(得分:33)
这是检查当前权限状态的一种简单方法:
@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;
}
警告:在用户通过用户提示(在sdk 23+设备上)接受/拒绝权限之前,返回BLOCKED_OR_NEVER_ASKED第一个应用启动
<强>更新强>
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;
答案 3 :(得分:21)
可以通过检查onRequestPermissionsResult()
回调方法中是否显示权限基本原理来确定。如果您发现任何权限设置为从不再询问,您可以请求用户从设置中授予权限。
我的全面实施如下。它适用于单个或多个权限请求。使用以下或directly use my library.
@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).
}
}
}
答案 4 :(得分:19)
可能对某人有用: -
我注意到的是,如果我们在onRequestPermissionsResult()回调方法中检查shouldShowRequestPermissionRationale()标志,它只显示两个状态。
状态1: - 返回true: - 任何时候用户点击拒绝权限(包括第一次)。
状态2:-Returns false: - 如果用户选择“never again again”。
答案 5 :(得分:15)
一旦用户标记了“不再询问”,该问题将无法再次显示。 但是可以向用户解释,他先前已拒绝许可,并且必须在设置中授予许可。并使用以下代码将其引用给设置:
@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;
}
答案 6 :(得分:9)
如果您想要检测所有“状态”(第一次被拒绝,被拒绝,被拒绝“永不再问”或被永久拒绝),您可以执行以下操作:
创建2个布尔值
private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;
在请求许可之前设置第一个:
beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);
在onRequestPermissionsResult方法中设置第二个:
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
答案 7 :(得分:8)
我有同样的问题,我想出来了。为了简化生活,我编写了一个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 上获得回调。
快乐编码:)
答案 8 :(得分:3)
每个许可案例的完整说明
/**
* 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.
}
}
}
答案 9 :(得分:2)
我在Android M中写了一份权限请求的简写。此代码还处理旧版Android版本的向后兼容性。
将所有丑陋的代码提取到Fragment中,Fragment将自身附加到请求权限的Activity上。您可以使用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
答案 10 :(得分:2)
一个有用的功能,用于确定是否已阻止任意权限进行请求(在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)
,以检查用户是否拒绝了该应用再次询问。由于quirks of this function,以下行也是必需的。
PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false)
(用于在第一次权限请求时将值设置为true)用于区分“从未询问”和“不再询问”状态,因为上一行不会返回此信息
答案 11 :(得分:2)
方法shouldShowRequestPermissionRationale()可以是用户检查用户是否选择了“从未再次询问”选项并拒绝该权限。 有很多代码示例,所以我宁愿解释如何将它用于这样的目的,因为我认为它的名称及其实现使它实际上变得更加复杂。
如Requesting Permissions at Run Time中所述,如果选项'never again again'可见,则该方法返回true,否则返回false;因此它在第一次显示对话框时返回false,然后从第二次开始返回true,并且只有当用户拒绝选择该选项的权限时,此时它才会再次返回false。
要检测这种情况,您可以检测到false-true-false序列,或者(更简单)您可以使用一个标记来跟踪显示对话框的初始时间。之后,该方法返回true或false,其中false将允许您检测何时选择该选项。
答案 12 :(得分:2)
试试这个简单的权限库。它将通过3个简单步骤处理与权限相关的所有操作。它节省了我的时间。 您可以在15分钟内完成与权限相关的所有工作。
它可以处理Deny,它可以处理从不再问,它可以调用app设置以获得权限,它可以给出一条Rational消息,它可以给出一个拒绝消息,它可以给出一个已接受权限的列表,它可以给出一个被拒绝的权限列表等。
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();
}
};
答案 13 :(得分:1)
请不要向我扔石头以获得此解决方案。
这有效,但有点“hacky”。
致电$('#addrow').click(function(e) {
$('#tab_logic tr:last').after('<tr><td><input type="text" list="inppara" id="inpparameter" ><datalist id="inppara"><option value="TypeRating">TypeRating</option><option value="Operation Check">Operation Check</option><option value="Ext.Apperance">Ext.Apperance</option><option value="Verify TC">Verify TC</option><option value="Material">Material</option><option value="Dimension Check">Dimension Check</option><option value="Threads Check">Threads Check</option><option value="Visual Check">Visual Check</option><option value="Specification">Specification</option><option value="Batch no">Batch no</option><option value="Mfg.Date">Mfg.Date</option><option value="Exp.Date">Exp.Date</option></datalist><td><input type="text" list="inpsepci" id="inpspec" ><datalist id="inpsepci"><option value="AsperPO">AsperPO</option><option value="Damage">Damage</option><option value="OK">OK</option><option value="Stainless Steel">Stainless Steel</option><option value="Gaues">Gaues</option><option value="Mild Steel">Mild Steel</option><option value="As per Drawing">As per Drawing</option><option value="Cast Iron">Cast Iron</option><option value="Copper">Copper</option><option value="Aluminium">Aluminium</option><option value="Brass">Brass</option><option value="Spring Steel">Spring Steel</option><option value="Tool Steel">Tool Steel</option><option value="Nylon">Nylon</option><option value="CRGO">CRGO</option><option value="EN1">EN1</option><option value="EN2">EN2</option></datalist></td><td><input type="text" list="act1" id="inpact10" class="tb3"><datalist id="act1"><option value="YES">YES</option><option value="NO">NO</option><option value="OK">OK</option><option value="NOT OK">NOT OK</option></datalist></td><td><input type="text" list="act2" id="inpact20" class="tb3"><datalist id="act2"><option value="YES">YES</option><option value="NO">NO</option><option value="OK">OK</option><option value="NOT OK">NOT OK</option></datalist></td><td><input type="text" list="act3" id="inpact30" class="tb3"><datalist id="act3"><option value="YES">YES</option><option value="NO">NO</option><option value="OK">OK</option><option value="NOT OK">NOT OK</option></datalist></td><td><input type="text" list="act4" id="inpact40" class="tb3"><datalist id="act4"><option value="YES">YES</option><option value="NO">NO</option><option value="OK">OK</option><option value="NOT OK">NOT OK</option></datalist></td><td><input type="text" list="act5" id="inpact50" class="tb3"><datalist id="act5"><option value="YES">YES</option><option value="NO">NO</option><option value="OK">OK</option><option value="NOT OK">NOT OK</option></datalist></td><td><img src="delete.gif" height="42" width="42" alt="idata" class="del"></td></tr>');
});
时,请注册当前时间。
requestPermissions
然后在 mAskedPermissionTime = System.currentTimeMillis();
如果未授予结果,请再次检查时间。
onRequestPermissionsResult
由于用户确实无法在拒绝按钮上点击这么快,我们知道他选择“永不再问”,因为回拨是即时的。
使用风险自负。
答案 14 :(得分:1)
你可以听漂亮的声音。
监听器
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")
}
})
覆盖活动或fragmnet中的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()
}
}
}
答案 15 :(得分:1)
您可以使用
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();
}
}
}
}
答案 16 :(得分:1)
在阅读了很少的答案后,我发现了许多冗长而令人困惑的答案 我的结论是
if (!ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_EXTERNAL_STORAGE))
Toast.makeText(this, "permanently denied", Toast.LENGTH_SHORT).show();
答案 17 :(得分:0)
您可以阅读android官方文档 Request App Permissions
或者您可以在Github上找到许多流行的android权限库
答案 18 :(得分:0)
要精确回答该问题,当用户按下“不再询问”时会发生什么?
被覆盖的方法/函数
onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray)
grantResult数组显示为空,因此您可以在那里做些什么?但不是最佳实践。
如何处理“不再询问”?
我正在使用Fragment,需要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)
}
答案 19 :(得分:0)
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
}
}
}
}
}
}
答案 20 :(得分:0)
OnRequestPermissionResult-free和shouldShowRequestPermissionRationale-free方法
public static void requestDangerousPermission(AppCompatActivity activity, String permission) {
if (hasPermission(activity, permission)) return;
requestPermission();
new Handler().postDelayed(() -> {
if (activity.getLifecycle().getCurrentState() == Lifecycle.State.RESUMED) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
}
}, 250);
}
如果没有出现权限弹出窗口,则在250ms后打开设备设置(如果选择了“不再询问”。
答案 21 :(得分:0)
shouldShowRequestPermissionRationale
根据之前权限请求中的用户偏好返回 true 或 false。
如果用户只是拒绝了权限(不是永远),shouldShowRequestPermissionRationale
将返回 true
。如果永远拒绝权限,则返回 false
。诀窍是,即使用户允许权限,shouldShowRequestPermissionRationale
也会返回 false
。
所以我们可以结合这两个条件来选择或不选择从不再次询问。
因此,如果用户不允许权限并且 shouldShowRequestPermissionRationale
返回 false
,则表示用户选择不再请求权限。
答案 22 :(得分:0)
扩展上面 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);
}
答案 23 :(得分:0)
我必须为相机实现动态权限。如果发生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;
}
}
答案 24 :(得分:0)
您可以使用if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
方法检测是否从未询问过。
更多参考:Check this
要检查多个权限,请使用:
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();
}
上面的代码还会显示一个对话框,它会将用户重定向到应用程序设置屏幕,如果已经选中,则可以给予许可,从不再询问按钮。
答案 25 :(得分:0)
相反,当您在onRequestPermissionsResult()
shouldShowRequestPermissionRationale()
上收到回复作为PERMISSION_DENIED
来自Android doc:
当系统要求用户授予权限时,用户可以选择告知系统不要再次请求该权限。在这种情况下,只要应用程序使用requestPermissions()
再次请求该权限,系统就会立即拒绝该请求。系统会调用您的onRequestPermissionsResult()
回调方法并传递PERMISSION_DENIED
,就像用户再次明确拒绝您的请求一样。这意味着当您致电requestPermissions()
时,您无法假设与用户进行任何直接互动。
答案 26 :(得分:0)
我还希望获得用户是否已选择&#34;再也不再询问&#34;的信息。我已经实现了一个几乎解决方案&#39;带着难看的旗帜,但在我告诉你如何之前,我会告诉你我的动机:
我想最初提供权限引用功能。如果用户使用它并且没有权限,他/她将获得上面的第1个对话框或第2个和第3个对话框。当用户选择“永不再问”时我想禁用该功能并以不同方式显示它。 - 我的操作是由微调文本条目触发的,我还想添加&#39;(权限已撤销)&#39;到显示的标签文本。这向用户显示:&#39;由于我的权限设置,有功能但我无法使用它。&#39;但是,这似乎不可能,因为我无法检查是否“再也不会再问”。已被选中。
我通过主动权限检查启用了我的功能,从而找到了我可以忍受的解决方案。我在onRequestPermissionsResult()中显示Toast消息,如果是否定响应,但仅当我没有显示我的自定义原理弹出窗口时。因此,如果用户选择了“再也不要再问”了。他只得到一个祝酒词。如果用户不愿意选择“再也不要再问”了。他只获得操作系统弹出的自定义理由和权限请求,但没有吐司,因为连续三个通知会太麻烦。