我们在做Android开发时,经常会用到一些系统的权限,比如读写外部存储、读写联系人信息、调用电话短信、访问网络等。在Android 6.0之前,对于这些权限调用的声明,只需要在AndroidManifest文件中声明即可,就像下面这样:
读取权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
在android 6.0 (包括6.0)棉花糖版本之后,系统不会在软件安装的时候就赋予该app所有其申请的权限,对于一些危险级别的权限,app需要在运行时一个一个询问用户授予权限。这就是所谓的“权限动态授权”。(先在AndroidManifest中声明,再到代码中声明)
下面以读取权限为例(写了一个读取手机中多媒体文件的标题):
1在AndroidManifest声明
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
2在代码中动态授权:
Main3Activity中
package com.zhh.quanxian;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.orhanobut.logger.Logger;
/**
* android自带的授权
*/
public class Main3Activity extends Activity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
initView();
initClick();
}
private void initView() {
button = findViewById(R.id.button);
}
private void initClick() {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 代码编译时的目标 sdk
int targetSdkVersion = Main3Activity.this.getApplicationInfo().targetSdkVersion;
// 当前运行设备的sdk的版本号(即当前手机系统的版本号)
int devicesSdkVersion = Build.VERSION.SDK_INT;
// 安卓6.0对应的sdk是23,即这个值就是23
int androidSdk23 = Build.VERSION_CODES.M;
// 同时满足这两个条件,需要动态申请权限(注意很多资料都是只判断了一个条件)
if (targetSdkVersion >= androidSdk23 && devicesSdkVersion >= androidSdk23) {
Logger.t("111").d("6.0以上动态授权");
checkPermission();
} else {
Logger.t("111").d("6.0以下在主清单文件中授权");
obtainMediaInfo();
}
}
});
}
/**
* 检查授权
*/
private void checkPermission() {
//检查当前权限(若没有该权限,值为-1;若有该权限,值为0)
//授权读取权限,READ_EXTERNAL_STORAGE
int hasReadExternalStoragePermission = ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.READ_EXTERNAL_STORAGE);
Log.e("PERMISION_CODE", hasReadExternalStoragePermission + "***");
if(hasReadExternalStoragePermission== PackageManager.PERMISSION_GRANTED){
Logger.t("111").d("已授权");
// 处理自己的逻辑
obtainMediaInfo();
}else{
Logger.t("111").d("没有授权");
//若没有授权,会弹出一个对话框(这个对话框是系统的,开发者不能自己定制),用户选择是否授权应用使用系统权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
}
/**
* 用户选择是否同意授权后,会回调这个方法
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if(requestCode==1){
if(permissions[0].equals(Manifest.permission.READ_EXTERNAL_STORAGE)&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
//用户同意授权,执行读取文件的代码
Logger.t("111").d("同意授权");
obtainMediaInfo();
}else{
//若用户不同意授权,直接暴力退出应用。
// 当然,这里也可以有比较温柔的操作。
Logger.t("111").d("不同意授权");
finish();
}
}
}
/**
* 自己的业务逻辑
* 拿到手机中多媒体资源的名称
*/
private void obtainMediaInfo() {
// 自己的业务逻辑
// 拿到手机中多媒体资源的名称
Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
cursor.moveToFirst();
do {
String title = cursor.getString(cursor.getColumnIndex("title"));
Logger.t("111").d("标题:"+title);
}while (cursor.moveToNext());
}
}
activity_main3中
<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"
tools:context="com.zhh.quanxian.Main3Activity">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="授权" />
</LinearLayout>
3build.gradle文件中把targetSdkVersion的值改动到大于22测试即可
defaultConfig {
applicationId "com.zhh.quanxian"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
参考文章:
https://blog.csdn.net/jasper_success/article/details/78836899
源码下载:
https://download.csdn.net/download/zhaihaohao1/10591230
上面是一次申请一个权限:
一次申请多个权限例子:----------------------------------------------------------------------
主清单文件:
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.CAMERA"/>
MainActivity中:
package com.zhh.apppermission;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.orhanobut.logger.Logger;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity {
public int myRequestCode = 100;
String[] permissions = new String[]{
Manifest.permission.CAMERA,
Manifest.permission.CALL_PHONE
};
// 声明一个集合,在后面的代码中用来存储用户拒绝授权的权
List<String> mPermissionList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
Button button2 = (Button) findViewById(R.id.btn2);
Button button3 = (Button) findViewById(R.id.btn3);
Button button4 = (Button) findViewById(R.id.btn4);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 代码编译时的目标 sdk
int targetSdkVersion = MainActivity.this.getApplicationInfo().targetSdkVersion;
// 当前运行设备的sdk的版本号(即当前手机系统的版本号)
int devicesSdkVersion = Build.VERSION.SDK_INT;
// 安卓6.0对应的sdk是23,即这个值就是23
int androidSdk23 = Build.VERSION_CODES.M;
Logger.t("111").d(targetSdkVersion+">>>"+devicesSdkVersion+">>>"+androidSdk23);
// 同时满足这两个条件,需要动态申请权限(注意很多资料都是只判断了一个条件)
if (targetSdkVersion >= androidSdk23 && devicesSdkVersion >= androidSdk23) {
Logger.t("111").d("6.0动态授权");
checkPermissions();
}else{
Logger.t("111").d("主清单授权");
}
}
});
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(camera, 1);
}
});
button4.setOnClickListener(new View.OnClickListener() {
@SuppressLint("MissingPermission")
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + "10086");
intent.setData(data);
startActivity(intent);
}
});
}
private void checkPermissions(){
for (int i = 0; i < permissions.length; i++) {
if (ContextCompat.checkSelfPermission(MainActivity.this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
mPermissionList.add(permissions[i]);
}
}
if (mPermissionList.isEmpty()) {
//未授予的权限为空,表示都授予了
Toast.makeText(MainActivity.this, "已经授权", Toast.LENGTH_LONG).show();
} else {
//请求权限方法
String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);
//请求权限
ActivityCompat.requestPermissions(MainActivity.this, permissions, myRequestCode);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == myRequestCode) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
//判断是否勾选禁止后不再询问
boolean showRequestPermission = ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permissions[i]);
if (showRequestPermission) {
Toast.makeText(MainActivity.this, "权限未申请", Toast.LENGTH_SHORT).show();
}
}
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="获取多个权限"
/>
<Button
android:id="@+id/btn3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="拍照"
/>
<Button
android:id="@+id/btn4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="电话"
/>
</LinearLayout>
build.gradle文件中把targetSdkVersion的值改动到大于22测试即可
defaultConfig {
applicationId "com.zhangqie.jurisdiction"
minSdkVersion 21
targetSdkVersion 23
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
源码下载:源码是一个module
https://download.csdn.net/download/zhaihaohao1/11646603
参考文章:
https://blog.csdn.net/DickyQie/article/details/78058969