转载请注明出处,谢谢:http://blog.csdn.net/harryweasley/article/details/72928860
Android M(6.0)以上是动态权限,google官方推出了一个开源项目EasyPermissions 来方便集成动态权限的功能。
本篇博客先翻译一下github的内容,然后给出一个例子,看看具体怎么使用EasyPermissions 。
EasyPermissions 的github地址是:https://github.com/googlesamples/easypermissions
附上DEMO源码下载地址:https://github.com/HarryWeasley/DynamicPermissionDemo
在Android M(6.0)或更高版本,EasyPermissions 是一个封装好的用来简化基本系统权限逻辑的库。
EasyPermissions 通过在build.gradle写入下面的依赖,来进行安装。
dependencies {
compile 'pub.devrel:easypermissions:0.4.0'
}
为了开始使用EasyPermissions,你需要在你的Activity (或者Fragment)中重写onRequestPermissionsResult 方法:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Forward results to EasyPermissions
//将结果传入EasyPermissions中
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
}
下面的例子展示了如何获取权限,通过一个方法获取CAMERA和ACCESS_FINE_LOCATION权限,有几个点需要注意:
@AfterPermissionGranted(RC_CAMERA_AND_LOCATION)
private void methodRequiresTwoPermission() {
String[] perms = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION};
if (EasyPermissions.hasPermissions(this, perms)) {
// Already have permission, do the thing
//如果已经获取权限,在这里做一些事情
// ...
} else {
// Do not have permissions, request them now
//如果没有获取到权限,在这里获取权限,其中RC_CAMERA_AND_LOCATION是自己定义的一个唯一标识int值
EasyPermissions.requestPermissions(this, getString(R.string.camera_and_location_rationale),
RC_CAMERA_AND_LOCATION, perms);
}
}
当然,为了一个更好的控制,可以让Activity / Fragment实现PermissionCallbacks 接口,如下所示:
public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Forward results to EasyPermissions
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsGranted(int requestCode, List list) {
// Some permissions have been granted
// 请求权限已经被授权
// ...
}
@Override
public void onPermissionsDenied(int requestCode, List list) {
// Some permissions have been denied
// 请求权限被拒绝
// ...
}
}
有一些案例,如果你的应用没有这些权限,有些功能将不能正常使用。如果用户点击了“不再询问”框,并且拒绝授权权限,你的应用将不能从用户那里获取到权限,除非用户去应用设置里更改状态。在这种情况下,你可以用EasyPermissions.somePermissionPermanentlyDenied(…)这个方法来判断,最终展示一个Dialog,指导用户去系统设置界面,为你的应用开启权限。
@Override
public void onPermissionsDenied(int requestCode, List perms) {
Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size());
// (Optional) Check whether the user denied any permissions and checked "NEVER ASK AGAIN."
// This will display a dialog directing them to enable the permission in app settings.
//(可选的)检查用户是否拒绝授权权限,并且点击了“不再询问”
//下面的语句,展示一个对话框指导用户在应用设置里授权权限
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this).build().show();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {
// Do something after user returned from app settings screen, like showing a Toast.
// 当用户从应用设置界面返回的时候,可以做一些事情,比如弹出一个土司。
Toast.makeText(this, R.string.returned_from_app_settings_to_activity, Toast.LENGTH_SHORT)
.show();
}
}
下面是EasyPermissions的通用动态获取权限的实现方法,文末有源码下载地址:
package demo.lgx.com.dynamicpermissiondemo;
import android.Manifest;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import pub.devrel.easypermissions.AfterPermissionGranted;
import pub.devrel.easypermissions.AppSettingsDialog;
import pub.devrel.easypermissions.EasyPermissions;
/**
* Created by Harry on 2017/6/8.
*/
public class DynamicActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks{
ImageView imageView;
/**
* 随便赋值的一个唯一标识码
*/
public static final int WRITE_EXTERNAL_STORAGE=100;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
Toast.makeText(DynamicActivity.this, "保存成功", Toast.LENGTH_LONG).show();
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamit);
Button save = (Button) findViewById(R.id.save);
imageView = (ImageView) findViewById(R.id.image);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkPerm();
}
});
}
/**
* 检查权限
*/
@AfterPermissionGranted(WRITE_EXTERNAL_STORAGE)
private void checkPerm() {
String[] params={Manifest.permission.WRITE_EXTERNAL_STORAGE};
if(EasyPermissions.hasPermissions(this,params)){
saveImage();
}else{
EasyPermissions.requestPermissions(this,"需要读写本地权限",WRITE_EXTERNAL_STORAGE,params);
}
}
private void saveImage() {
//请忽略我这个子线程的优化问题,这里主要是为了实现动态权限的功能,哈哈!
new Thread(new Runnable() {
@Override
public void run() {
//获取到bitmap
BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
Bitmap bitmap = drawable.getBitmap();
//创建文件夹保存图片
File file = DynamicActivity.this.getExternalFilesDir(null).getAbsoluteFile();
String imageName = "test.jpg";
File imageFile = new File(file, imageName);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//保存成功后发送message
handler.sendEmptyMessage(1);
}
}).start();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode,permissions,grantResults,this);
}
@Override
public void onPermissionsGranted(int requestCode, List perms) {
//如果checkPerm方法,没有注解AfterPermissionGranted,也可以在这里调用该方法。
}
@Override
public void onPermissionsDenied(int requestCode, List perms) {
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
//这里需要重新设置Rationale和title,否则默认是英文格式
new AppSettingsDialog.Builder(this)
.setRationale("没有该权限,此应用程序可能无法正常工作。打开应用设置屏幕以修改应用权限")
.setTitle("必需权限")
.build()
.show();
}
}
}
之前看过一些app的功能,如果用户拒绝该权限,那么该app将不允许用户使用,直接退出,下面这个例子来实现这样的一个功能。
如果用户拒绝权限授权,则app退出该页面,如下图所示:
package demo.lgx.com.dynamicpermissiondemo;
import android.Manifest;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.List;
import pub.devrel.easypermissions.AfterPermissionGranted;
import pub.devrel.easypermissions.AppSettingsDialog;
import pub.devrel.easypermissions.EasyPermissions;
/**
* Created by Harry on 2017/6/8.
*/
public class MustPermissionActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks {
ImageView imageView;
/**
* 随便赋值的一个唯一标识码
*/
public static final int WRITE_EXTERNAL_STORAGE = 100;
private boolean isFirst = false;
//权限参数
String[] params = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
Toast.makeText(MustPermissionActivity.this, "保存成功", Toast.LENGTH_LONG).show();
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("MustPermissionActivity", "onCreate执行");
setContentView(R.layout.activity_dynamit);
isFirst = true;
Button save = (Button) findViewById(R.id.save);
imageView = (ImageView) findViewById(R.id.image);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkPerm();
}
});
}
@Override
protected void onResume() {
super.onResume();
if (isFirst) {
//因为要通过一个Fragment来弹出弹出框,所以activity这里的onResume执行了两次,这里进行判断
isFirst = false;
if (!EasyPermissions.hasPermissions(this, params)) {
EasyPermissions.requestPermissions(this, "需要读写本地权限", WRITE_EXTERNAL_STORAGE, params);
}
}
}
/**
* 检查权限
*/
@AfterPermissionGranted(WRITE_EXTERNAL_STORAGE)
private void checkPerm() {
if (EasyPermissions.hasPermissions(this, params)) {
//已经获取到权限
Toast.makeText(MustPermissionActivity.this, "获取到权限,正常进入", Toast.LENGTH_LONG).show();
} else {
EasyPermissions.requestPermissions(this, "需要读写本地权限", WRITE_EXTERNAL_STORAGE, params);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsGranted(int requestCode, List perms) {
}
@Override
public void onPermissionsDenied(int requestCode, List perms) {
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
//这个方法有个前提是,用户点击了“不再询问”后,才判断权限没有被获取到
new AppSettingsDialog.Builder(this)
.setRationale("没有该权限,此应用程序可能无法正常工作。打开应用设置界面以修改应用权限")
.setTitle("必需权限")
.build()
.show();
} else if (!EasyPermissions.hasPermissions(this, params)) {
//这里响应的是除了AppSettingsDialog这个弹出框,剩下的两个弹出框被拒绝或者取消的效果
finish();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {
if (!EasyPermissions.hasPermissions(this, params)) {
//这里响应的是AppSettingsDialog点击取消按钮的效果
finish();
}
}
}
}
1.一定要记得要先在AndroidManifest.xml声明权限。
2.例子中的Context.getExternalFilesDir()的绝对路径是SDCard/Android/data/应用包名/files/,在api<19的时候,需要写入权限,但是在api>=19后,就不需要写入权限,也可以写入数据了。本篇文章例子,是为了写easyPermissions的功能,所以不要在意Context.getExternalFilesDir()该路径。关于该权限官网链接是https://developer.android.com/reference/android/content/Context.html#getExternalFilesDir(java.lang.String)
附上源码下载地址:https://github.com/HarryWeasley/DynamicPermissionDemo