安卓6.0以后动态申请权限的详细过程以及详解
几乎每个人都知道都知道,Google为了提高Android系统的安全在6.0系统加上了动态申请权限。权限不在是像6.0以前那样是默认给应用的。在5.1.1的系统上面,有些手机虽然可以在设置中找到权限管理,或者是在自己的应用中设置了禁止权限,但是依然是可以取到用户信息。我测试的是一个华为的手机,系统是5.1.1。我在禁止了或者设备信息之后,依然是可以获取设备信息的。顿时感觉这些事很操蛋。
6.0权限的基本知识,以下是需要单独申请的权限,共分为9组,每组只要有一个权限申请成功了,就默认整组权限都可以使用了。还有一些普通权限,我们只需要在清单文件中配置就可以直接使用。
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
group:android.permission-group.PHONE
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
group:android.permission-group.CAMERA
permission:android.permission.CAMERA
group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS
group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO
group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS
一、动态申请权限的实现流程
1.清单文件中配置你的权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.adwan.persiondemo">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2.判断应用所运行手机的系统版本,如果系统的版本是低于6.0的,可以直接去处理你的业务逻辑;否则就要动态申请权限。权限状态一般是三种状态(允许、提示、禁止)。
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
</pre>3. 判断是否已经获取权限,如果已经获得权限,接去处理你的业务逻辑。
//权限有三种状态(1、允许 2、提示 3、禁止)
int permission = ActivityCompat.checkSelfPermission(getApplication(), Manifest.permission.READ_PHONE_STATE);
// 2、提示 3、禁止
if (permission != PackageManager.PERMISSION_GRANTED)
4.如果没有获得权限。则先判断我们所需权限的状态。
boolean is=ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.READ_PHONE_STATE);
5.根据权限的状态去判断怎么处理,如果第四步返回的是true,代表的是提示,表示我们可以动态去申请权限。如果是禁止的话,我们就不可以去动态申请权限,此时则只能去通过用户,去手动更改权限(设置成为允许或者是提示)。这个下面也有代码。但是不同的机型打开设置界面的代码是不一样的,需要去做机型适配。
6.请求权限
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.READ_PHONE_STATE},REQUEST_CODE_PRESSION_PHONE_STATE);
7.在onRequestPermissionsResult()处理请求权限的结果,是拒绝,还是允许。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions,grantResults);
switch (requestCode){
case REQUEST_CODE_PRESSION_PHONE_STATE:
if (grantResults[0] == 0){
getDeviceId();
}else {
}
break;
default:
break;
}
}
8.通过结果去走不过的业务。
二 、通过引导用户,手动更改禁止的权限。(需要机型适配)
这个就是在用户是禁止获取我们申请的权限时,需要我们引导用户去更改设置。我们要跳转到权限管理界面或者是设置界面。在这我写出了小米、华为、魅族的方法。动态申请权限的完整代码如下
public class MainActivity extends AppCompatActivity {
public static final String TAG = "xing";
public static final int REQUEST_CODE_PRESSION_PHONE_STATE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View view) {
//版本号的判断
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
String deviceId = getDeviceId();
} else {
//权限有三种状态(1、允许 2、提示 3、禁止)
int permission = ActivityCompat.checkSelfPermission(getApplication(), Manifest.permission.READ_PHONE_STATE);
// 2、提示 3、禁止
if (permission != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "click: -------sdk>23---------------------没有获得权限");
//如果设置中权限是禁止的咋返回false;如果是提示咋返回的是true
boolean is = ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.READ_PHONE_STATE);
Log.i(TAG, "click: ------is----------------------" + is);
if (is) {
Log.i(TAG, "click: ------提示----------------------");
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.READ_PHONE_STATE},
REQUEST_CODE_PRESSION_PHONE_STATE);
} else {
Log.i(TAG, "click: ------禁止----------------------");
gotoHuaweiPermission();
}
} else {
//1、允许
getDeviceId();
}
}
}
private String getDeviceId() {
TelephonyManager manager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
Toast.makeText(this, "" + manager.getDeviceId(), Toast.LENGTH_LONG).show();
return manager.getDeviceId();
}
//始终允许
// --permissions--------android.permission.READ_PHONE_STATE
// : --------grantResults-------0
//禁止 和 始终禁止
// --permissions--------android.permission.READ_PHONE_STATE
// : --------grantResults-------1
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CODE_PRESSION_PHONE_STATE:
if (grantResults[0] == 0) {
getDeviceId();
} else {
}
break;
default:
break;
}
}
// 华为的权限管理页面
private void gotoHuaweiPermission() {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");//华为权限管理
intent.setComponent(comp);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "gotoHuaweiPermission: ------------------");
}
}
// 跳转到系统的设置界面
//获取应用详情页面intent
private Intent getAppDetailSettingIntent() {
Intent localIntent = new Intent();
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {
localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
localIntent.setData(Uri.fromParts("package", getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {
localIntent.setAction(Intent.ACTION_VIEW);
localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
localIntent.putExtra("com.android.settings.ApplicationPkgName", getPackageName());
}
return localIntent;
}
// 跳转到魅族的权限管理系统
private void gotoMeizuPermission() {
Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
try {
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
gotoHuaweiPermission();
}
}
//跳转到miui的权限管理页面
private void gotoMiuiPermission() {
Intent i = new Intent("miui.intent.action.APP_PERM_EDITOR");
ComponentName componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
i.setComponent(componentName);
i.putExtra("extra_pkgname", getPackageName());
try {
startActivity(i);
} catch (Exception e) {
e.printStackTrace();
gotoMeizuPermission();
}
}
}
三、总结
我们只有在用户没有禁止我们所申请的权限的时候才能调用申请权限的方法,我们根据第四步中的返回值去判断是禁止还是提示(ture:提示 false:禁止)如果用户禁止之后,我们可以通过隐式意图引导用户打开手机设置权限,将权限更改成不是禁止。如果是提示,则调用动态请求权限的方法,就是流程中的第六步。然后再通过第七步中的返回结果去处理。
也可以同时去申请多个权限,可以详细去看下申请过程的几个方法,方法中的参数是数组类型的。如果需要申请多个权限,可以去自己更改下参数。