动态权限请求
无    2017-07-24 06:19:58    412    0    0
xianglijiaxing

 

一、文档说明

官方文档:https://developer.android.com/training/permissions/requesting.html#explain

https://commonsware.com/blog/2015/08/17/random-musings-android-6p0-sdk.html

http://jijiaxin89.com/2015/08/30/Android-s-Runtime-Permission/

 

        系统对话窗只会展示请求权限对应的权限组,而不会显示具体的权限。

 

        当我们在targetSdkVersion 低于23的app调用一个需要权限的函数时,这个权限如果被用户取消授权了的话,不抛出异常。但是他将啥都不干,结果导致函数返回值是null或者0.

二、基本使用

一般情况

ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)​

结果为-1的情况下,

如果权限被拒绝过一次(对话框拒绝或者设置中取消权限),下一次请求就会出现“不再提示”的勾选框;

如果是第一次请求权限,或者权限被拒绝,且勾选了”不再提示“,那么调用

ActivityCompat.shouldShowRequestPermissionRationale​()

将返回false;仅仅是上一次否定的情况下返回true。

示例代码如下:

if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
    showMessageOKCancel("You need to allow access to Contacts",
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
               requestPermissions(new String[] {Manifest.permission.WRITE_CONTACT,REQUEST_CODE_ASK_PERMISSION);
            }
    });
}else{
    requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},REQUEST_CODE_ASK_PERMISSIONS);
}
       

 

如果上一次权限被拒绝,且勾选了”不再提示“,则下一次调用

ActivityCompat.requestPermissions​()

请求权限,不会出现系统对话框

直接callback结果为-1

 

特殊情况:

    在手机app权限管理界面中,如果更改了手机的权限,则应用会直接被杀死

    ①授权 --->非授权:                再次请求权限相当于否定了一次权限请求

    ②非授权---> 授权:                权限直接获取到了

    ③非授权--->授权 --->非授权:再次请求权限相当于第一次请求

三、开源解决方案

github开源库:

https://github.com/hotchemi/PermissionsDispatcher

https://github.com/googlesamples/easypermissions

https://github.com/hongyangAndroid/MPermissions

 开源方案对比:

http://www.jianshu.com/p/07e1a1cff5ad

四、动态权限的坑

1.蓝牙扫描需要位置权限:

<!-- Android6.0 蓝牙扫描才需要-->
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>

BluetoothUtils: Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan res

 

2.Fragment中请求权限:

两种解决方案

        在fragment如果使用ActivityCompat.requestPermissions,不会调用onRequestPermissionsResult(),这个大家应该都知道吧,千万注意我遇到的问题,记得在activity的onRequestPermissionsResult()调用super,不然也不会回调

 

---

        在Fragment中申请权限,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的onRequestPermissionsResult,另外在fragment中询问的方法也可以直接使用fragment中的方法shouldShowRequestPermissionRationale方法。

 

---

Fragment嵌套Fragment请求权限的问题:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  List<Fragment> fragments = getChildFragmentManager().getFragments();
  if (fragments != null) {
      for (Fragment fragment : fragments) {
          if (fragment != null) {
              fragment.onRequestPermissionsResult(requestCode,permissions,grantResults);
          }
      }
  }
}

 

3.WRITE_SETTINGS权限怎么处理

   /**
     * An app can use this method to check if it is currently allowed to write or modify system
     * settings. In order to gain write access to the system settings, an app must declare the
     * {@link android.Manifest.permission#WRITE_SETTINGS} permission in its manifest. If it is
     * currently disallowed, it can prompt the user to grant it this capability through a
     * management UI by sending an Intent with action
     * {@link android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}.
     *
     * @param context A context
     * @return true if the calling app can write to system settings, false otherwise
     */
     if(!Settings.System.canWrite(this)){
          Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
                    Uri.parse("package:" + getPackageName()));
          startActivityForResult(intent, REQUEST_CODE);
     } 


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE) {
            if (Settings.System.canWrite(this)) {
                //检查返回结果
                Toast.makeText(MainActivity.this, "WRITE_SETTINGS permission granted", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "WRITE_SETTINGS permission not granted", Toast.LENGTH_SHORT).show();
            }
        }
    }

 

4.悬浮窗权限问题:

    需要动态的引导用户去设置

if (!Settings.canDrawOverlays(this)) {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
    startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}

这个可以参考 

五、危险权限组

https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous

 

This video will give you a better idea about UX, handling Runtime permissions

https://www.youtube.com/watch?v=iZqDdvhTZj0

 

 

 

 

--------------------------------------------------------------------------------------------------------------

额外代码

 

命令:

adb shell dumpsys activity top

 

各大厂商手机调转至应用的权限设置界面:

参考:https://github.com/hkq325800/JumpPermissionManagement

 /**
     * 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 void Huawei(Activity activity) {
        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.startActivity(intent);
    }

    public static void Meizu(Activity activity) {
        Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
        activity.startActivity(intent);
    }

// 如何获取MIUI的版本???
// http://blog.csdn.net/devilkin64/article/details/19415717
    // public static void Xiaomi(Activity activity) {
    //     Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
    //     ComponentName componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
    //     intent.setComponent(componentName);
    //     intent.putExtra("extra_pkgname", BuildConfig.APPLICATION_ID);
    //     activity.startActivity(intent);
    // }
    
     public static void Xiaomi(Context activity) {
        Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
        ComponentName componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
        intent.setComponent(componentName);
        intent.putExtra("extra_pkgname", activity.getPackageName());
        activity.startActivity(intent);
    }

    public static void Sony(Activity activity) {
        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);
    }

    public static void OPPO(Activity activity) {
        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);
    }

    public static void LG(Activity activity) {
        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);
    }

    public static void Letv(Activity activity) {
        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);
    }

    /**
     * 只能打开到自带安全软件
     * @param activity
     */
    public static void _360(Activity activity) {
        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);
    }

  public static void Smartisan(Context activity) {
        Intent intent = new Intent();
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
        ComponentName comp = new ComponentName("com.smartisanos.security", "com.smartisanos.security.MainActivity");
        intent.setComponent(comp);
        activity.startActivity(intent);
    }


    /**
     * 应用信息界面
     * @param activity
     */
    public static void ApplicationInfo(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());
        }
        activity.startActivity(localIntent);
    }

 

 

上一篇: Gradle打包可执行Jar和AAR

下一篇: 笔记

412 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航