Android6.0动态权限申请

前言

在6.0之前的版本上安装应用,必须要接受应用申请的所有权限,否则就无法安装使用。但实际中有些应用用户只需要它们的部分权限,只有特殊情况下才会使用一些关于用户隐私的权限,比如有些评论用户只喜欢添加文本评论不喜欢晒图,这时就没有必要一开始就赋予应用查看图片库的功能。Android6.0开始支持动态权限申请功能,它把所有的权限分成了两大类,普通权限和危险权限,普通权限还像以前以前一样写到AndroidManifest文件里就可以,危险权限需要用户手动确认,用户也可以到应用设置里随时取消赋予的权限。现在就来学习一下动态权限管理使用的接口。

权限说明

普通权限的申请方式和以前的相同就不再介绍了,这里主要介绍危险权限,Android对危险权限做了详细的分组,一旦用户启用了某个组的某个权限,那么应用就自动获取到了这个权限组里的权限。权限组的分配如下表所示:

权限组说明权限
android.permission-group.CONTACTS联系人权限android.permission.WRITE_CONTACTS
android.permission.GET_ACCOUNTS
android.permission.READ_CONTACTS
android.permission-group.PHONE电话权限android.permission.READ_CALL_LOG
android.permission.READ_PHONE_STATE
android.permission.CALL_PHONE
android.permission.WRITE_CALL_LOG
android.permission.USE_SIP
android.permission.PROCESS_OUTGOING_CALLS
com.android.voicemail.permission.ADD_VOICEMAIL
android.permission-group.CALENDAR日历权限android.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR
android.permission-group.CAMERA相机权限android.permission.CAMERA
android.permission-group.SENSORS传感器权限android.permission.BODY_SENSORS
android.permission-group.LOCATION定位权限android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
android.permission-group.STORAGE外部存储权限android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE
android.permission-group.MICROPHONE麦克风音频权限android.permission.RECORD_AUDIO
android.permission-group.SMS短消息权限android.permission.READ_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECEIVE_MMS
android.permission.RECEIVE_SMS
android.permission.SEND_SMS
android.permission.READ_CELL_BROADCASTS

除了上面的危险权限外还有两种特殊的权限SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS,它们属于特殊权限不在普通权限和危险权限里面,申请它们除了要在清单文件里写入权限申请还要到设置界面里人工授权。

危险权限申请

首先简单的实现拍照然后将照片保存到本地,再展示到界面上。首先需要在AndroidManifest文件中声明需要android.permission.WRITE_EXTERNAL_STORAGE权限,在6.0之前可以直接调用ACTION_CAPTURE_IMAGE使用Android提供的拍照应用拍照,通过onActivityResult里的intent.getExtra(“data”)获取到Bitmap对象,然后保存到外部sdcard文件中。

private void startTakePhoto() {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(intent, REQUEST_TAKE_PHOTO);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_TAKE_PHOTO && resultCode == Activity.RESULT_OK) {
        Bitmap bitmap = (Bitmap) data.getExtras().get("data");
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "photo.jpg");
        FileOutputStream fos = null;
        try {
            if (!file.exists()) file.createNewFile();
            fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.close(fos);
        }

        Bitmap bmp = BitmapFactory.decodeFile(file.getAbsolutePath());
        imageView.setImageBitmap(bmp);
    }
}

但是在6.0以上版本直接调用保存会报下面的错误:

java.io.FileNotFoundException: /storage/emulated/0/Pictures/photo.jpg: open failed: EACCES (Permission denied)
    at libcore.io.IoBridge.open(IoBridge.java:452)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
    at com.example.permisswion.MainActivity.onActivityResult(MainActivity.java:83)

这个错误提示的很明确找不到文件,没有权限访问对应文件。现在开始使用系统提供的接口申请外部存储写入权限,整体过程如下:首先检查当前系统版本是否是6.0以上,如果是通过ContextCompat.checkSelfPermission判断应用是否已经有了外部写入权限,如果有就直接调用拍照功能,没有就通过ActivityCompat.requestPermissions申请权限;如果不是6.0以上版本直接调用照相功能即可。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
        startTakePhoto();
    } else {
        ActivityCompat.requestPermissions(this,
                new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_STORAGE);
    }
} else {
    startTakePhoto();
}

调用ActivityCompat.requestPermissions之后会弹出一个对话框提示用户是否授权,点击确定或者取消都会进入Activity.onRequestPermissionsResult回调中去,在回调里会有一个permissionResult数组对象,数组索引和申请的permission一一对应,这里只申请了Manifest.permission.WRITE_EXTERNAL_STORAGE权限,所以permissionResult也只有一个结果。通过对比权限申请结果是PackageManager.PERMISSION_GRANTED表明获得申请权限,PackageManager.PERMISSION_DENIED表明用户没有授予权限。

if (requestCode == REQUEST_WRITE_STORAGE && grantResults != null && grantResults.length > 0) {
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        startTakePhoto();
    } else {
        Toast.makeText(getApplicationContext(), R.string.has_no_permission, Toast.LENGTH_SHORT).show();
    }
}

WRITE_SETTINGS权限申请

很多电子书应用都会分白天和黑夜模式,如果黑夜模式特别亮用户就会觉得很刺眼,可以通过调整屏幕的亮度来解决刺眼的问题。这种调整屏幕亮度的需求就属于写入系统设置的范畴,在6.0以上的版本如果直接设置系统亮度会报没有权限的异常。接下来通过代码来实现6.0以上版本的权限动态申请。

首先在AndroidManifest中声明android.permission.WRITE_SETTINGS权限,在XML中定义一个SeekBar控件并且为它注册SeekBar.OnSeekBarChangeListener回调,接下来在onProgressChanged回调方法里首先判断是否是6.0以上版本,如果是判断能否写入Settings,不能则需要到Settings设置界面设置授权当前应用写入Settings。授权成功后设置屏幕亮度模式为人工设置模式,同时更新当前屏幕的亮度值,拖动SeekBar的调整句柄就会看到屏幕亮度随之发生了变化。

<SeekBar
    android:id="@+id/seekbar"
    android:layout_marginTop="50dp"
    android:max="255"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (!Settings.System.canWrite(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
            intent.setData(Uri.parse("package:" + getPackageName()));
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        } else {
            changeScreenBrightness(progress);
        }
    } else {
        changeScreenBrightness(progress);
    }
}

private void changeScreenBrightness(int progress) {
    Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE,
            Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
    Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, progress);
}

ALERT_SYSTEM_WINDOW权限申请

有一些应用比如像素尺子,它们需要把自己的界面悬浮在其他的应用界面之上,为了实现悬浮效果,就需要向系统申请 ALERT_SYSTEM_WINDOW权限。对于6.0以上版本如果没有动态申请这个权限,系统也会报异常。现在通过代码来说明如何申请这个权限,首先在AndroidManifest中添加android.permission.SYSTEM_ALERT_WINDOW权限声明。然后在通过Settings.canDrawOverlays判断是否有SYSTEM_ALERT_WINDOW权限,如果没有需要到Settings的设置界面请求授予权限,最后在onActivityResult回调中测试用户是否授权成功。

public void requestPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST);
        } else {
            Intent intent = new Intent(this, RulerService.class);
            startService(intent);
        }
    }
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == OVERLAY_PERMISSION_REQUEST) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(this, "权限授予失败,无法开启悬浮窗", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "权限授予成功!", Toast.LENGTH_SHORT).show();
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于 Android 6.0 以上权限问题,可能是由于您的应用没有正确申请权限导致的。您可以通过以下步骤检查和解决该问题: 1. 在 AndroidManifest.xml 文件中声明应用需要的权限。例如,如果您的应用需要访问网络,则需要添加以下权限声明: ``` <uses-permission android:name="android.permission.INTERNET" /> ``` 2. 在运行时检查权限。您可以使用以下代码检查是否拥有所需权限: ``` if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { // Permission is not granted, request it ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INTERNET}, REQUEST_CODE); } else { // Permission is granted, continue with the task } ``` 3. 处理用户的权限请求响应。当您使用 `ActivityCompat.requestPermissions()` 请求权限时,系统会显示一个对话框,询问用户是否授予权限。您需要在 `onRequestPermissionsResult()` 回调方法中处理用户的响应,例如: ``` @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission is granted, continue with the task } else { // Permission is denied, show a message to the user } } } ``` 至于 TBS 内核加载失败的问题,可能是由于权限问题导致的。您可以尝试按照上述步骤检查和解决权限问题,如果仍然无法解决问题,请提供更多详细信息,以便我更好地帮助您解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值