Android 6.0动态权限 Runtime Permission API使用

本文介绍了Android 6.0引入的动态权限获取机制Runtime Permission,详细阐述了适配特点、调用步骤,并提供了一个简单的Demo实现。适配特点是针对不同targetAPI版本的应用有不同的权限管理策略。调用步骤包括判断API版本、检查权限状态和调用接口获取权限。在Activity中,通过checkSelfPermission和requestPermissions进行权限检查和请求,同时在onRequestPermissionsResult回调中处理权限获取结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Runtime Permission

Android 6.0版本引入了动态权限获取机制(Runtime Permission),并引入了新的API来让开发者使用这一功能。
开发者使用相应API后,系统会自动弹出对话框,提示用户授予权限。

在以往的Android版本中,checkPermission接口主要是读取Manifest文件中的权限声明,来判断当前应用权限的;对于很多手机内置手机管家中的权限管理功能,无法正确判断。新的API就可以解决这样的问题(仅限6.0版本)。

适配特点

新增的API以及系统机制,对于老版本APP适配也有一定策略,总的来说如下:
在Android 6.0中,若安装APP的targetAPI 小于23,则默认不限制权限。用户需要通过系统设置手工控制权限;
若安装APP的targetAPI为23,则需要开发者编写代码,适配Runtime Permission。在恰当处调用,以弹出对话框提示用户授权。若不适配则默认权限关闭。

调用步骤

Runtime Permission不仅提供了API函数供开发者主动调用,在Activity中也提供了回调函数供我们实现业务逻辑,大体来说,适配的步骤如下:
1. 判断系统API版本,检查权限状态,决定是否调用动态权限接口
2. 调用接口获取权限
3. Activity回调函数中实现业务逻辑

Demo实现

这里使用API实现一个简单的Demo。首先我们在默认Activity中添加一个按钮:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.runtimepermissiontest.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <Button
        android:id="@+id/runtimePermissionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="RuntimePermission"/>

</LinearLayout>

这里用READ_PHONE_STATE权限来作为示例,在Activity中,添加按钮的监听器,点击按钮调用一个自定义函数:

runtimeButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        getPhoneNumber();
    }
});

private void getPhoneNumber() {
    //TODO implements method
}

getPhoneNumber是我们实现的获取电话信息的函数,在这里假设其中使用了相关的系统权限。
由于Android 6.0的动态权限获取机制,若点击事件的函数这样编写,则APP无法正常获取权限,会导致相关功能不能正常使用。

按照上述步骤,我们首先来通过API判断,调用检查权限接口,并调用接口获取权限(步骤1,2)。在这里使用的是新API:
checkSelfPermission——检查权限
requestPermissions——请求权限

runtimeButton.setOnClickListener(new View.OnClickListener() {
    // 添加注解,避免Studio报错
    @TargetApi(23)
    @Override
    public void onClick(View v) {
        // 判断API版本
        if (Build.VERSION.SDK_INT >= 23) {
            // 检查是否获取权限
            if (mContext.checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
                    != PackageManager.PERMISSION_GRANTED) {
                // 未获得权限,调用接口获取
                requestPermissions(new String[] {Manifest.permission.READ_PHONE_STATE}, 2016);
            } else {
                getPhoneNumber();
                return;
            }
        }
        getPhoneNumber();
    }
});

requestPermissions这个函数中的第二个参数是自定义的int值,例如在这里我们传入了2016
实际这里比较像message中的what:需要开发者自己定义数值,在handleMessage中编写不同case分支处理。在这里,Activity中的新增回调函数onRequestPermissionsResult就相当于handler中的handleMessage。
也就是步骤中的第三步:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch(requestCode) {
        case 2016:
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                getPhoneNumber();
            } else {
                Log.d(TAG, "read phone state permission denied");
            }
            break;
        default:
            break;
    }
}

通过参数grantResults数组,就可以得到每个相应权限的获取状态了。
需要说明的是,这个回调函数是在用户点击系统自动弹出的对话框后才会调用,因此需要分别实现权限获取成功与失败时的逻辑。

完整的代码如下:

package com.example.runtimepermissiontest;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";

    private Button runtimeButton;

    private Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mContext = this;

        runtimeButton = (Button) findViewById(R.id.runtimePermissionButton);
        runtimeButton.setOnClickListener(new View.OnClickListener() {
            @TargetApi(23)
            @Override
            public void onClick(View v) {
                if (Build.VERSION.SDK_INT >= 23) {
                    if (mContext.checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
                            != PackageManager.PERMISSION_GRANTED) {
                        requestPermissions(new String[] {Manifest.permission.READ_PHONE_STATE}, 2016);
                    } else {
                        getPhoneNumber();
                    }
                }
                getPhoneNumber();
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch(requestCode) {
            case 2016:
                if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    getPhoneNumber();
                } else {
                    Log.d(TAG, "read phone state permission denied");
                }
                break;
            default:
                break;
        }
    }

    private void getPhoneNumber() {
        //TODO implements method
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值