android: Android 权限管理小结
一. 概述
感谢郭神,自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装的事情,也不会再不征求用户授权的情况下,就可以任意的访问用户隐私,而且即使在授权之后也可以及时的更改权限。这就是6.0版本做出的更拥护和注重用户的一大体现。
1.1 Android 6.0 权限
- 以前,申请一个子权限会自动获取权限组中其他子权限。组内其他子权限可以直接使用。
- 现在,申请一个子权限,组内其他子权限不会自动获取。使用组内其他子权限的时候。需要再次申请。(但是这种情况不会弹出系统的权限申请框)如果不申请。会FC。
- 同组权限一起申请。当我们申请权限时。申请同组的多个权限时,也只会弹出一次申请框。所以建议一起申请。
- 6.0以下版本(系统自动申请)
- 暂时发现vivo、oppo、魅族的6.0以上版本
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
第二步:检测当前权限是否已授权
通过 ContextCompat.checkSelfPermission(context,permission) 方法,方法返回值为 PackageManager.PERMISSION_GRANTED or PackageManager.PERMISSION_DENIED :
第三步:请求权限
通过 ActivityCompat.requestPermissions(activity,permissions,requestCode) ,第二个参数是一个String数组,第三个参数是请求码,便于在 onRequestPermissionsResult() 方法中根据requestCode进行判断:
第四步:处理权限申请的结果
当请求权限后,界面会显示一个对话框提示用户让用户选择是否同意我们申请的权限,在用户处理完毕后,系统会回调 onRequestPermissionsResult 方法,我们需要在在activity中重写 onRequestPermissionsResult(requestCode,permissions,grantResults) 方法, grantResults 是int类型的数组,每个值为 PackageManager.PERMISSION_GRANTED or PackageManager.PERMISSION_DENIED 分别对应 申请的每个permissions 的每个请求(比如申请了6个权限,那这个grantResult数组的值就会有6个,按顺序分别代表每个权限是否已被用户同意)。
这里存在几种情况需要注意:
1)用户同意了我们的申请:
2)用户拒绝了我们的申请。
这个时候为了良好的用户体验,我们可以向用户阐明我们为什么需要这个权限,提醒用户这个权限的必要性。 ActivityCompat.shouldShowRequestPermissionRationale(activity,permission) 这个方法是在用户拒绝权限后返回true。什么意思呢,也就是说:用户第一次点击一个需要权限的地方,该方法返回false(因为用户没拒绝~),当用户拒绝掉该权限,下次点击此权限处,该方法会返回true。可在里面进行对该权限的说明,然后弹出权限让用户选择,并且对话框有don't ask again选项:
3) 用户选择don't ask again 后
我们已经向用户阐明我们为什么需要这个权限,但是用户依然置之不理,并且还选择了don't ask again 复选框,那这个时候 ActivityCompat.shouldShowRequestPermissionRationale(activity,permission) 会一直返回false, 并且 ActivityCompat.requestPermissions 不会弹出对话框,系统直接deny,并回调 onRequestPermissionsResult 方法:
<用户拒绝时>
<用户接受时>
三. 代码演示
比如我要申请以下4种权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
为了最大程度给予用户自由,我在首界面,也就是SplashActivity去申请这些权限,我们约定只有定位权限是必须的,只要用户同意定位权限,我们就允许用户进入主界面。实际的代码如下:
package com.yongdaimi.android.androidapitest; import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class SplashActivity extends AppCompatActivity { private String[] mNeedGrantedPermissionArr = null; private static final int REQUEST_CODE_GRANT_PERMISSION = 10001; public static final String TAG = "xp.chen"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
initNeedGrantedPermissionArr();
} private void initNeedGrantedPermissionArr() {
mNeedGrantedPermissionArr = new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
};
} @Override
protected void onStart() {
super.onStart();
checkRuntimePermissions();
} private void checkRuntimePermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
List<String> needApplyPermissionList = new ArrayList<String>();
for (String s : mNeedGrantedPermissionArr) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), s) != PackageManager.PERMISSION_GRANTED) {
needApplyPermissionList.add(s);
}
} if (needApplyPermissionList.size() > 0) {
ActivityCompat.requestPermissions(this, needApplyPermissionList.toArray(new String[0]), REQUEST_CODE_GRANT_PERMISSION);
} else {
skip2MainActivity();
Log.i(TAG, "checkRuntimePermissions: needApplyPermissionList num is 0");
}
} else {
skip2MainActivity();
}
} @Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_GRANT_PERMISSION) { for (String permission: permissions) {
Log.i(TAG, "onRequestPermissionsResult: permission: "+permission);
}
for (int grantRet : grantResults) {
Log.i(TAG, "onRequestPermissionsResult: grantRet: "+ grantRet);
} List<String> permissionList = Arrays.asList(permissions);
if (permissionList.contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
int pos = permissionList.indexOf(Manifest.permission.ACCESS_FINE_LOCATION);
if (grantResults[pos] != PackageManager.PERMISSION_GRANTED) {
mNeedGrantedPermissionArr = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Tips")
.setMessage("I really need Location Permission to work")
.setCancelable(false)
.setNegativeButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
checkRuntimePermissions();
}
})
.create();
dialog.show();
} else {
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Tips")
.setMessage("The Location permission is not yet enabled, It is necessary, you can open it in the settings ui")
.setCancelable(false)
.setNegativeButton("Close App", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setPositiveButton("Go Open", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
})
.create();
dialog.show();
}
} else {
skip2MainActivity();
Log.i(TAG, "checkRuntimePermissions: grantResults[pos] != PackageManager.PERMISSION_GRANTED");
}
} else {
skip2MainActivity();
Log.i(TAG, "checkRuntimePermissions: not necessary");
} }
} private void skip2MainActivity() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(getApplicationContext(), BLEBluetoothApiUseDemoActivity.class);
startActivity(intent);
finish();
}
}, 1000);
} }
参考链接:
1. Android 权限管理
android: Android 权限管理小结的更多相关文章
- 大约Android 了解权限管理
如Android应用程序开发人员.为android权限机制一直觉得很奇怪.为什么要这个东西权限?为什么要AndroidManifest里面写的uses-permission 这样的事情?我一直搞不清楚 ...
- Android 开发 权限管理
Android 开发 权限管理 https://sspai.com/post/42779 $ adb shell pm list permissions -d -g https://zhuanlan. ...
- [Android Pro] android 4.4 Android原生权限管理:AppOps
reference : http://m.blog.csdn.net/blog/langzxz/45308199 reference : http://blog.csdn.net/hyhyl1990/ ...
- android 自定义权限管理
在Android6.0后有些权限就需要进行询问,虽然可以将targetSdkVersion设置成小于等于23,但是这样可能有些东西无法使用,所以要进行权限的管理. 实现逻辑:打开页面就询问权限,如果没 ...
- android sdcard 权限管理策略研究
自从android4.4 以来,第三方应用程序是不能再随便的访问sdcard了,从开发者的角度而言,研究一下android系统到底是怎么样来实现这样的控制还是比较有价值的. 首先分析下现状,现在已知, ...
- mysql 用户及权限管理 小结
MySQL 默认有个root用户,但是这个用户权限太大,一般只在管理数据库时候才用.如果在项目中要连接 MySQL 数据库,则建议新建一个权限较小的用户来连接. 在 MySQL 命令行模式下输入如下命 ...
- Android应用权限管理总结
访问登记属性 android.permission.ACCESS_CHECKIN_PROPERTIES ,读取或写入登记check-in数据库属性表的权限 获取错略位置 android.permi ...
- android 手机权限管理——PermissionsDispatcher
Android6.0 之后某些权限需要动态申请,相比于之前版本复杂了许多.不过已经有大神给我们写好了框架(PermissionsDispatcher),我们用起来还是很方便. 1.添加引用 根据 gr ...
- 第一篇、Android Supersu 权限管理定制,隐藏过滤权限,指定APP最高权限
近期有个需求,在预装ROM的时候,须要权限,可是又不同意全部的应用都有权限,仅仅同意自己的应用有最高的权限(当然没有系统签名情况下). 所以.编译了CM 提取了supersu进行了二次定制,让他进行权 ...
随机推荐
- wince窗口被静态的焦点挡住
效果如下图: 问题:文本框被挡住了 解决办法如下: 找到该窗体,设置属性Menu值为无即可解决
- KVM之virsh管理虚拟机硬盘配置
新建raw格式虚拟盘 [root@ubuntu ~]# qemu-img create -f raw /data/raw/disk02.raw 5G Formatting '/data/raw/dis ...
- [基础累积] C#计算时间差
TimeSpan nowTime = new TimeSpan(DateTime.Now.Ticks); TimeSpan nextTime = new TimeSpan(nextDispatcher ...
- 关于PPP拨号 和 AT指令实现GPRS模块联网的疑问
以下内容摘抄自互联网: ppp拨号 与 at命令的疑问 GPRS模块在Linux平台上ppp拨号上网总结与心得 以PPP拨号实现GPRS与因特网的数据通信的具体实现流程 问: 我刚接触GPRS,了解A ...
- [Python][pythonchallenge][TBC]古老的python在线挑战赛,很有意思 (C0-C4)
预计阅读时间:15分钟 背景:搜索资料时候偶然发现的,很有意思,每一关都覆盖了很多知识点 Python版本:3.0 Talking is cheap,show me the code 主页: http ...
- 深度解析Graph Embedding
Graph Embedding是推荐系统.计算广告领域最近非常流行的做法,是从word2vec等一路发展而来的Embedding技术的最新延伸:并且已经有很多大厂将Graph Embedding应用于 ...
- Maya mel maya档出现未知插件解决方法
Maya mel maya档出现未知插件解决方法 以下 mel 代码,拷贝到 maya 的脚本编辑器的 mel 中,最好运行两次 string $unknownNodes[] = `ls -type ...
- JDK源码那些事儿之HashMap.TreeNode
前面几篇文章已经讲解过HashMap内部实现以及红黑树的基础知识,今天这篇文章就讲解之前HashMap中未讲解的红黑树操作部分,如果没了解红黑树,请去阅读前面的两篇文章,能更好的理解本章所讲解的红黑树 ...
- java- 泛型类到底是类还是接口,<T extends Comparable>的写法中为什么没有用implements
java-core P533 public static <T extands Comparable> T min(T[] a ) 这里产生了一个疑问,就是 泛型类的英文是generic ...
- JVM之Java运行时数据区(线程共享区)
JVM运行时区域各线程共享的区域包括堆区和方法区. 堆区 堆区最最主要的功能是存储对象实例[上篇也提到过],因此Java垃圾回收的主要战场就是在堆区,因此也有称为GC堆区.如果堆区的内存不够会出现Ou ...