Android权限管理
1.1、静态权限

Android6.0(API 23)之前的权限,是静态权限, 开发者只要在AndroidManifest.xml中写上需要的权限,如下:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

AndroidManifest.xml中写上需要的权限,这有两个作用:

1、用户在安装软件的时候,操作系统会把开发者写的这些权限列表展示给用户,但是,通常,用户在安装的过程中根本不关心到底这些权限是干啥的、有啥影响。如下:

2、如果某个API需要的权限,开发者没有在AndroidManifest.xml中写,系统就会抛出SecurityException异常, 如果用户没有捕获该异常,程序就会奔溃掉。

1.2、动态权限

Android6.0(API 23)开始增加了动态权限,不仅仅要求开发者在AndroidManifest.xml中写明确需要的权限, 某些涉及到用户隐私的权限,要求在调用该API之前,必须让用户确认授权这个权限。而且弹出的授权界面是操作系统本身的功能,不能绕过去。如下:

Android6.0(API 23)开始增加的动态权限申请API实在太难用了,非常繁琐, 我们通常会使用RxPermissions简化开发。

常见的需要动态申请的权限:

  • android.permission.CALL_PHONE
  • android.permission.READ_PHONE_STATE
  • android.permission.WRITE_EXTERNAL_STORAGE
  • android.permission.READ_EXTERNAL_STORAGE
1.2.1、android.permission.CALL_PHONE

android.permission.CALL_PHONE权限动态申请和处理示例:

public static void call(Activity activity, String phoneNumber) {
    new RxPermissions(activity).request(Manifest.permission.CALL_PHONE).subscribe(granted -> {
        if (granted) {
            try {
                Uri uri = Uri.parse("tel:" + phoneNumber);
                Intent intent = new Intent(Intent.ACTION_CALL, uri);
                activity.startActivity(intent);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(activity, "您没有授予打电话的权利,所以无法拨打电话", Toast.LENGTH_LONG).show();
        }
    });
}
1.2.2、android.permission.READ_PHONE_STATE

android.permission.READ_PHONE_STATE权限动态申请和处理示例:

public static void readIMEI(Context context) {
    new RxPermissions(activity).request(Manifest.permission.READ_PHONE_STATE).subscribe(granted -> {
        if (granted) {
            try {
                TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                String imei = tm.getDeviceId();
                //TODO
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(context, "您没有授予获取电话状态相关的权限", Toast.LENGTH_LONG).show();
        }
    });
}
1.2.3、android.permission.READ_EXTERNAL_STORAGE

android.permission.READ_EXTERNAL_STORAGE权限动态申请和处理示例:

private void readFile(Activity activity) {
    new RxPermissions(activity).request(Manifest.permission.READ_EXTERNAL_STORAGE).subscribe(granted -> {
        if (granted) {
            try {
                BufferedSource bufferedSource = Okio.buffer(Okio.source(new File(activity.getExternalCacheDir(), "xx.txt")));
                String content = bufferedSource.readString(Charset.forName("UTF-8"));
                //TODO
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(activity, "您没有授予读取SD卡的权利,所以无法查看SD中的内容", Toast.LENGTH_LONG).show();
        }
    });
}

此处使用了使用Okio简化读取文件的操作。

1.2.4、android.permission.WRITE_EXTERNAL_STORAGE

android.permission.WRITE_EXTERNAL_STORAGE权限动态申请和处理示例:

private void writeFile(Activity activity) {
    new RxPermissions(activity).request(Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(granted -> {
        if (granted) {
            try {
                BufferedSink bufferedSink = Okio.buffer(Okio.sink(new File(activity.getExternalCacheDir(), "xx.txt")));
                bufferedSink.writeUtf8("Hello");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(activity, "您没有授予写入SD卡的权利", Toast.LENGTH_LONG).show();
        }
    });
}

此处使用了使用Okio简化写文件的操作。

1.3、自定义权限