何时在运行时请求 Android Marshmallow 6.0 的权限?
Posted
技术标签:
【中文标题】何时在运行时请求 Android Marshmallow 6.0 的权限?【英文标题】:When to request permission at runtime for Android Marshmallow 6.0? 【发布时间】:2016-03-13 00:43:51 【问题描述】:我正在Marshmallow 6.0
上测试我的应用程序,它正在强制关闭android.permission.READ_EXTERNAL_STORAGE
,即使它已经在清单中定义。我在某处读过,如果我在运行时请求许可,那么它不会强制关闭您的应用程序。我也读过this android document,它用于请求运行时权限。
所以,我才知道我们可以请求下面的权限,这在 android 文档中有所提及。
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED)
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS))
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
else
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]Manifest.permission.READ_CONTACTS,
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
上面的代码有一个回调方法onRequestPermissionsResult
可以得到结果。
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults)
switch (requestCode)
我的问题是在哪里准确地向用户请求权限?我们应该在应用启动时使用请求权限还是应该在需要权限时使用?
【问题讨论】:
观看此视频:youtu.be/iZqDdvhTZj0 - 解释了一些最佳实践。 在需要权限时执行。此外,验证 M 清单中的权限 l-o-c;<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
因此在需要时请求权限是最佳做法。
试试这个可能有用***.com/a/41221852/5488468
另见***.com/a/41978011/3496570
【参考方案1】:
一般来说,只要您需要,就立即请求所需的权限。通过这种方式,您可以告知用户您需要权限的原因,并且更容易处理权限拒绝。
想想用户在您的应用运行时撤消权限的场景:如果您在启动时请求它并且以后不再检查它,这可能会导致意外行为或异常。
【讨论】:
所以你说我必须在我们不需要的时候请求许可。 是的。您不知道用户是否在您的应用运行期间撤销了权限。【参考方案2】:在我看来,您的问题没有一个正确答案。强烈建议你看看这个官方permissions patterns page。
谷歌建议的几件事:
“您的权限策略取决于您请求的权限类型的清晰度和重要性。这些模式提供了向用户介绍权限的不同方式。”
“应预先请求关键权限。可以在上下文中请求辅助权限。”
“不太清楚的权限应该提供有关权限所涉及内容的教育,无论是预先完成还是在上下文中完成。”
This illustration 可能会让你更好地理解。
也许这里最关键的一点是,无论您是预先还是在上下文中请求权限,您都应该始终牢记,用户可以随时撤销这些权限(例如,您的应用仍在后台运行)。
您应该确保您的应用不会因为您在应用一开始就请求权限并假设用户没有更改他/她对该权限的偏好而崩溃。
【讨论】:
这也是我的看法,这个问题没有正确的遮阳篷,ux 的人应该根据产品来决定【参考方案3】:这对我有用!!! 在应用程序的 Splash Activity 中执行以下操作,
1) 为请求代码声明一个int变量,
private static final int REQUEST_CODE_PERMISSION = 2;
2) 用你需要的权限数声明一个字符串数组,
String[] mPermission = Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE;
3) 接下来检查 onCreate 方法的运行时权限条件,
try
if (ActivityCompat.checkSelfPermission(this, mPermission[0])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[1])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[2])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[3])
!= MockPackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this,
mPermission, REQUEST_CODE_PERMISSION);
// If any permission aboe not allowed by user, this condition will execute every tim, else your else part will work
catch (Exception e)
e.printStackTrace();
4) 现在声明 onRequestPermissionsResult 方法来检查请求代码,
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.e("Req Code", "" + requestCode);
if (requestCode == REQUEST_CODE_PERMISSION)
if (grantResults.length == 4 &&
grantResults[0] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[1] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[2] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[3] == MockPackageManager.PERMISSION_GRANTED)
// Success Stuff here
【讨论】:
没有得到你的代码,你说在两个地方做你的事情。应该只有一个地方可以做我的事情,而不是两个,onRequestPermissionsResult
怎么称呼???
对不起,只需在 onRequestPermissionResult 中执行代码,然后告诉我你的结果【参考方案4】:
可以在这里找到很好的解释和操作方法:
https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
我编写这段代码是为了在运行时检查和请求 BaseActivity.class 中的权限,它是我实现的所有其他 Activity.class 的父级:
public static final int PERMISSION_REQUEST = 42;
public static final int MULTIPLE_PERMISSION_REQUEST = 43;
//Marshmallow Permission Model
public boolean requestPermission(String permission /* Manifest.permission...*/)
if (ContextCompat.checkSelfPermission(this,
permission) != PackageManager.PERMISSION_GRANTED)
if (Utils.hasMarshmallow())
ActivityCompat.requestPermissions(this,
new String[]permission, PERMISSION_REQUEST
);
else
requestPermissions(new String[]permission,
PERMISSION_REQUEST);
return false;
else
return true;
public boolean requestPermission(String... permissions)
final List<String> permissionsList = new ArrayList<String>();
for (String perm : permissions)
addPermission(permissionsList, perm);
if (permissionsList.size() > 0)
if (Utils.hasMarshmallow())
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
MULTIPLE_PERMISSION_REQUEST);
else
ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[permissionsList.size()]),
MULTIPLE_PERMISSION_REQUEST);
return false;
else
return true;
private boolean addPermission(List<String> permissionsList, String permission)
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED)
permissionsList.add(permission);
// Check for Rationale Option
if (Utils.hasMarshmallow())
if (!shouldShowRequestPermissionRationale(permission))
return false;
return true;
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults)
switch (requestCode)
case PERMISSION_REQUEST:
case MULTIPLE_PERMISSION_REQUEST:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
// permission was granted, yay! Do the
// contacts-related task you need to do.
else
// permission denied, boo! Disable the
// functionality that depends on this permission.
return;
// other 'case' lines to check for other
// permissions this app might request
简单示例调用:
activity.requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);
返回结果会让你知道权限是否已经被授予。
【讨论】:
【参考方案5】:if ( ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CAMERA) ||
ActivityCompat.shouldShowRequestPermissionRationale (this,
Manifest.permission.RECORD_AUDIO) )
Toast.makeText (this,
R.string.permissions_needed,
Toast.LENGTH_LONG).show ();
else
ActivityCompat.requestPermissions (
this,
new String[]Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO,
CAMERA_MIC_PERMISSION_REQUEST_CODE);
【讨论】:
您的代码缺少 cmets,您的回答有何不同?和你之前的答案?【参考方案6】:调用此函数,我们可以允许用户打开对话框,询问是否允许摄像头和录制音频。
if ( ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CAMERA) ||
ActivityCompat.shouldShowRequestPermissionRationale (this,
Manifest.permission.RECORD_AUDIO) )
Toast.makeText (this,
R.string.permissions_needed,
Toast.LENGTH_LONG).show ();
else
ActivityCompat.requestPermissions (
this,
new String[]Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO,
CAMERA_MIC_PERMISSION_REQUEST_CODE);
【讨论】:
【参考方案7】:这样做
private static final int REQUEST_ACCESS_FINE_LOCATION = 111;
在你的 onCreate 中
boolean hasPermissionLocation = (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
if (!hasPermissionLocation)
ActivityCompat.requestPermissions(ThisActivity.this,
new String[]Manifest.permission.ACCESS_FINE_LOCATION,
REQUEST_ACCESS_FINE_LOCATION);
然后查看结果
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode)
case REQUEST_ACCESS_FINE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
Toast.makeText(ThisActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();
//reload my activity with permission granted
finish();
startActivity(getIntent());
else
Toast.makeText(ThisActivity.this, "The app was not allowed to get your location. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
【讨论】:
【参考方案8】:https://material.io/guidelines/patterns/permissions.html 此链接将为您提供可以询问权限的不同类型的场景。根据您的需要进行选择。
【讨论】:
【参考方案9】:为了请求运行时权限,我使用GitHub Library
在Build.gradle
文件中添加库
dependencies
compile 'gun0912.ted:tedpermission:1.0.3'
创建Activity并添加PermissionListener
public class MainActivity extends AppCompatActivity
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
PermissionListener permissionlistener = new PermissionListener()
@Override
public void onPermissionGranted()
Toast.makeText(RationaleDenyActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
//Camera Intent and access Location logic here
@Override
public void onPermissionDenied(ArrayList<String> deniedPermissions)
Toast.makeText(RationaleDenyActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
;
new TedPermission(this)
.setPermissionListener(permissionlistener)
.setRationaleTitle(R.string.rationale_title)
.setRationaleMessage(R.string.rationale_message) // "we need permission for access camera and find your location"
.setDeniedTitle("Permission denied")
.setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
.setGotoSettingButtonText("Settings")
.setPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.check();
字符串.xml
<resources>
<string name="rationale_title">Permission required</string>
<string name="rationale_message">we need permission for read <b>camera</b> and find your <b>location</b></string>
</resources>
【讨论】:
【参考方案10】:我喜欢短代码。我使用RxPermission 获取权限。
RxPermission 是最好的库,它使权限代码意外只有 1 行。
RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
.request(Manifest.permission.CAMERA,
Manifest.permission.READ_PHONE_STATE) // ask single or multiple permission once
.subscribe(granted ->
if (granted)
// All requested permissions are granted
else
// At least one permission is denied
);
添加您的build.gradle
allprojects
repositories
...
maven url 'https://jitpack.io'
dependencies
implementation 'com.github.tbruyelle:rxpermissions:0.10.1'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
这不容易吗?
【讨论】:
【参考方案11】: Android Easy Runtime Permissions with Dexter:
1. Dexter Permissions Library
To get started with Dexter, add the dependency in your build.gradle
dependencies
// Dexter runtime permissions
implementation 'com.karumi:dexter:4.2.0'
1.1 Requesting Single Permission
To request a single permission, you can use withPermission() method by passing the required permission. You also need a PermissionListener callback to receive the state of the permission.
> onPermissionGranted() will be called once the permission is granted.
> onPermissionDenied() will be called when the permission is denied. Here you can check whether the permission is permanently denied by using response.isPermanentlyDenied() condition.
The below code requests CAMERA permission.
Dexter.withActivity(this)
.withPermission(Manifest.permission.CAMERA)
.withListener(new PermissionListener()
@Override
public void onPermissionGranted(PermissionGrantedResponse response)
// permission is granted, open the camera
@Override
public void onPermissionDenied(PermissionDeniedResponse response)
// check for permanent denial of permission
if (response.isPermanentlyDenied())
// navigate user to app settings
@Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token)
token.continuePermissionRequest();
).check();
1.2 Requesting Multiple Permissions
To request multiple permissions at the same time, you can use withPermissions() method. Below code requests STORAGE and LOCATION permissions.
Dexter.withActivity(this)
.withPermissions(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_FINE_LOCATION)
.withListener(new MultiplePermissionsListener()
@Override
public void onPermissionsChecked(MultiplePermissionsReport report)
// check if all permissions are granted
if (report.areAllPermissionsGranted())
// do you work now
// check for permanent denial of any permission
if (report.isAnyPermissionPermanentlyDenied())
// permission is denied permenantly, navigate user to app settings
@Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token)
token.continuePermissionRequest();
)
.onSameThread()
.check();
【讨论】:
以上是关于何时在运行时请求 Android Marshmallow 6.0 的权限?的主要内容,如果未能解决你的问题,请参考以下文章
PreApplicationStartMethod 何时真正被触发运行?