背景:
众所周知,国内的android是在google之上,各大手机厂商加了一层,诸如MIUI、EUI,之类的系统。因此在我们开发过程中想调出某应用的权限设置页面,调出的是google原生的权限控制界面,但是我们在此页授予应用权限后,实际上应用还是没有权限,只是在google眼里,我已经给你权限了。其实,是被手机厂商系统给拦截了,通俗来讲,中国的手机厂商觉得原生的不好看,或者突出自己系统等原因,会在原生之上加一个壳子,有些东西原生可以决定,有些东西,原生决定了没有用,还是要壳子同意才行。
目的:
因此我们想跳转的是各大手机厂商系统的应用权限设置界面,这就需要知道类名+包名,而且各大手机厂商的类名+包名肯定不一样,也不保证它们会一成不变。
在此https://www.jianshu.com/p/58c6ca8173c4文章的基础上,完善了一个工具类,经过测试:
华为:OK
小米:OK
锤子:OK
一加:OK
vivo:OK,vivo有自己的提示,再次点击后也是会跳出提示,有瑕疵,但是还可以
oppo:OK,自己会提示
魅族:暂时跳转没反应
酷派:无6.0以上的版本笑哭
中兴:OK
联想:OK
PS:
总体来讲,不敢保证肯定能跳过去的,可以采用捕获异常的方式,是在调不到该应用的权限管理页,跳到该应用详情页也可以,反正就是要引导用户在拒绝权限后可以找到在哪授予权限。
当然我这里采用的是startActivityForResult,返回时我想知道权限是否已经授予,如果授予了,那么继续干其他的事情,如果没授予,那么继续提示。
因为使用startActivityForResult若跳的是应用详情页,用户再次点击权限,其实已经跳出该活动了,再返回,再返回到我们的页面,其实并没有效果,因此考虑区分应用详情页和权限详情页
最终确定方案:若打开的是应用详情页,则在onResume中检测权限
核心代码:
public static void GoToSetting(Activity activity){
switch (Build.MANUFACTURER){
case MANUFACTURER_HUAWEI://华为
Huawei(activity);
break;
case MANUFACTURER_MEIZU://魅族
Meizu(activity);
break;
case MANUFACTURER_XIAOMI://小米
Xiaomi(activity);
break;
case MANUFACTURER_SONY://索尼
Sony(activity);
break;
case MANUFACTURER_OPPO://oppo
OPPO(activity);
break;
case MANUFACTURER_LG://lg
LG(activity);
break;
case MANUFACTURER_LETV://乐视
Letv(activity);
break;
default://其他
try {//防止应用详情页也找不到,捕获异常后跳转到设置,这里跳转最好是两级,太多用户也会觉得麻烦,还不如不跳
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}catch (Exception e){
SystemConfig(activity);
}
break;
}
}
总体的思路是:尝试跳应用权限页————>失败------->应用详情页。尽量引导嘛
附送工具类
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.v7.appcompat.BuildConfig;
import static com.lxkh.PermissionsManager.PERMISSION_SETTING_FOR_RESULT;
/**
* Created by zyy on 2018/3/12.
* 直接跳转到权限后返回,可以监控权限授权情况,但是,跳转到应用详情页,无法监测权限情况
* 是否要加以区分,若是应用详情页,则跳转回来后,onRestart检测所求权限,如果授权,则收回提示,如果没授权,则继续提示
*/
public class permissionUtil {
/**
* Build.MANUFACTURER判断各大手机厂商品牌
*/
private static final String MANUFACTURER_HUAWEI = "Huawei";//华为
private static final String MANUFACTURER_MEIZU = "Meizu";//魅族
private static final String MANUFACTURER_XIAOMI = "Xiaomi";//小米
private static final String MANUFACTURER_SONY = "Sony";//索尼
private static final String MANUFACTURER_OPPO = "OPPO";
private static final String MANUFACTURER_LG = "LG";
private static final String MANUFACTURER_VIVO = "vivo";
private static final String MANUFACTURER_SAMSUNG = "samsung";//三星
private static final String MANUFACTURER_LETV = "Letv";//乐视
private static final String MANUFACTURER_ZTE = "ZTE";//中兴
private static final String MANUFACTURER_YULONG = "YuLong";//酷派
private static final String MANUFACTURER_LENOVO = "LENOVO";//联想
public static boolean isAppSettingOpen=false;
/**
* 跳转到相应品牌手机系统权限设置页,如果跳转不成功,则跳转到应用详情页
* 这里需要改造成返回true或者false,应用详情页:true,应用权限页:false
* @param activity
*/
public static void GoToSetting(Activity activity){
switch (Build.MANUFACTURER){
case MANUFACTURER_HUAWEI://华为
Huawei(activity);
break;
case MANUFACTURER_MEIZU://魅族
Meizu(activity);
break;
case MANUFACTURER_XIAOMI://小米
Xiaomi(activity);
break;
case MANUFACTURER_SONY://索尼
Sony(activity);
break;
case MANUFACTURER_OPPO://oppo
OPPO(activity);
break;
case MANUFACTURER_LG://lg
LG(activity);
break;
case MANUFACTURER_LETV://乐视
Letv(activity);
break;
default://其他
try {//防止应用详情页也找不到,捕获异常后跳转到设置,这里跳转最好是两级,太多用户也会觉得麻烦,还不如不跳
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}catch (Exception e){
SystemConfig(activity);
}
break;
}
}
/**
* 华为跳转权限设置页
* @param activity
*/
public static void Huawei(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");
intent.setComponent(comp);
activity.startActivityForResult(intent,PERMISSION_SETTING_FOR_RESULT);
isAppSettingOpen=false;
} catch (Exception e) {
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 魅族跳转权限设置页,测试时,点击无反应,具体原因不明
* @param activity
*/
public static void Meizu(Activity activity) {
try {
Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 小米,功能正常
* @param activity
*/
public static void Xiaomi(Activity activity) {
try { // MIUI 8 9
Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", activity.getPackageName());
activity.startActivityForResult(localIntent, PERMISSION_SETTING_FOR_RESULT);
isAppSettingOpen=false;
// activity.startActivity(localIntent);
} catch (Exception e) {
try { // MIUI 5/6/7
Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", activity.getPackageName());
activity.startActivityForResult(localIntent, PERMISSION_SETTING_FOR_RESULT);
isAppSettingOpen=false;
// activity.startActivity(localIntent);
} catch (Exception e1) { // 否则跳转到应用详情
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
//这里有个问题,进入活动后需要再跳一级活动,就检测不到返回结果
// activity.startActivity(getAppDetailSettingIntent());
}
}
}
/**
* 索尼,6.0以上的手机非常少,基本没看见
* @param activity
*/
public static void Sony(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.sonymobile.cta", "com.sonymobile.cta.SomcCTAMainActivity");
intent.setComponent(comp);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* OPPO
* @param activity
*/
public static void OPPO(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.color.safecenter", "com.color.safecenter.permission.PermissionManagerActivity");
intent.setComponent(comp);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* LG经过测试,正常使用
* @param activity
*/
public static void LG(Activity activity) {
try {
Intent intent = new Intent("android.intent.action.MAIN");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$AccessLockSummaryActivity");
intent.setComponent(comp);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 乐视6.0以上很少,基本都可以忽略了,现在乐视手机不多
* @param activity
*/
public static void Letv(Activity activity) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.PermissionAndApps");
intent.setComponent(comp);
activity.startActivity(intent);
isAppSettingOpen=false;
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 只能打开到自带安全软件
* @param activity
*/
public static void _360(Activity activity) {
try {
Intent intent = new Intent("android.intent.action.MAIN");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
ComponentName comp = new ComponentName("com.qihoo360.mobilesafe", "com.qihoo360.mobilesafe.ui.index.AppEnterActivity");
intent.setComponent(comp);
activity.startActivity(intent);
}catch (Exception e){
openAppDetailSetting(activity);
// activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
}
}
/**
* 系统设置界面
* @param activity
*/
public static void SystemConfig(Activity activity) {
Intent intent = new Intent(Settings.ACTION_SETTINGS);
activity.startActivity(intent);
}
/**
* 获取应用详情页面
* @return
*/
private static Intent getAppDetailSettingIntent(Activity activity) {
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", activity.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", activity.getPackageName());
}
return localIntent;
}
public static void openAppDetailSetting(Activity activity){
activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
isAppSettingOpen=true;
}
}
暂时想到的处理判断授权结果的思路就是,应用权限页--->startActivityForResult 应用详情页--->resume中检测
有更好的思路欢迎留言讨论交流