項目地址:https://github.com/googlesamples/easypermissions
有什么用?
方便開發(fā)者為App申請權(quán)限
情況是這樣的
試想一下,一個App在未經(jīng)允許的情況下,能獲取你的聯(lián)系人資料,用相機給你拍照上傳,這是多么危險的一件事情.支付寶就有這么一個操作,用前置相機悄悄的給你拍照上傳.某個版本還能聽到"卡擦"一聲
Android在發(fā)布6.0時,加入了這樣一個功能,對于手機的某些敏感資源,如相機,麥克風(fēng),聯(lián)系人資料,電話,短信,相冊...需要用戶同意,App才能擁有使用相關(guān)資源的能力
哪些是權(quán)限是需要申請的?
官方文檔:https://developer.android.google.cn/guide/topics/security/permissions.html#normal-dangerous
- CALENDAR(日歷)
- CAMERA(相機)
- CONTACTS(聯(lián)系人)
- MICROPHONE(音頻錄制)
- PHONE(手機相關(guān))
- SENSORS(傳感器)
- SMS(短信)
- STORAGE(存儲)
Note:
Android 6.0以前,在項目Manifest.xml文件中添加權(quán)限,說明這個App已經(jīng)有這個權(quán)限了,而現(xiàn)在,對于這些危險權(quán)限來說,在Manifest中只能算是聲明,去告訴系統(tǒng),這個App需要這個權(quán)限,但有沒有這個權(quán)限,用戶來決定.
在Android 6.0版本不寫權(quán)限申請會怎樣?
如果一個App沒有相機的權(quán)限而去直接調(diào)用相機的功能.直接的結(jié)果是:導(dǎo)致App崩潰,所以,時常會在App評論中看到:"太流氓了,不給權(quán)限就崩潰",類似的評論
怎么用?
1. 引入EasyPermission
dependencies {
compile 'pub.devrel:easypermissions:0.3.0'
}
2. 重寫Activity或Fragment中的onRequestPermissionsResult方法
并在其中調(diào)用EasyPermissions.onRequestPermissionsResult來請求回調(diào),必需加
public class UseEasyPermissionMainActivity extends AppCompatActivity {
private static final String TAG = "UseEasyPermission";
private static final int RC_CAMERA_AND_RECORD_AUDIO = 10000;
@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);
}
}
3. 實現(xiàn)EasyPermissions.PermissionCallbacks接口,實現(xiàn)兩個方法:
- onPermissionsGranted權(quán)限申請成功的回調(diào)
- onPermissionsDenied權(quán)限申請拒絕的回調(diào)
實際情況是這樣,如果我要用相機,首先要去判斷有沒有相機權(quán)限,有就直接開啟相機,沒有就去申請權(quán)限
public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_requst).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
requestPermissions();
}
});
}
@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);
}
/**
* 去申請權(quán)限
*/
private void requestPermissions() {
String[] perms = {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
//判斷有沒有權(quán)限
if (EasyPermissions.hasPermissions(this, perms)) {
// 如果有權(quán)限了, 就做你該做的事情
openCamera();
} else {
// 如果沒有權(quán)限, 就去申請權(quán)限
// this: 上下文
// Dialog顯示的正文
// RC_CAMERA_AND_RECORD_AUDIO 請求碼, 用于回調(diào)的時候判斷是哪次申請
// perms 就是你要申請的權(quán)限
EasyPermissions.requestPermissions(this, "寫上你需要用權(quán)限的理由, 是給用戶看的", RC_CAMERA_AND_RECORD_AUDIO, perms);
}
}
/**
* 權(quán)限申請成功的回調(diào)
*
* @param requestCode 申請權(quán)限時的請求碼
* @param perms 申請成功的權(quán)限集合
*/
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
Log.i(TAG, "onPermissionsGranted: ");
openCamera();
}
/**
* 權(quán)限申請拒絕的回調(diào)
*
* @param requestCode 申請權(quán)限時的請求碼
* @param perms 申請拒絕的權(quán)限集合
*/
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
Log.i(TAG, "onPermissionsDenied: ");
}
}
這時候可以把打開相機調(diào)用的代碼放在onPermissionsGranted中,如果你同時申請了多個權(quán)限,也可以在回調(diào)中判斷做相應(yīng)的操作:
/**
* 權(quán)限申請成功的回調(diào)
*
* @param requestCode 申請權(quán)限時的請求碼
* @param perms 申請成功的權(quán)限集合
*/
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
Log.i(TAG, "onPermissionsGranted: ");
if (requestCode != RC_CAMERA_AND_RECORD_AUDIO) {
return;
}
for (int i = 0; i < perms.size(); i++) {
if (perms.get(i).equals(Manifest.permission.CAMERA)) {
Log.i(TAG, "onPermissionsGranted: " + "相機權(quán)限成功");
openCamera();
} else if (perms.get(i).equals(Manifest.permission.RECORD_AUDIO)) {
Log.i(TAG, "onPermissionsGranted: " + "錄制音頻權(quán)限成功");
}
}
}
/**
* 權(quán)限申請拒絕的回調(diào)
*
* @param requestCode 申請權(quán)限時的請求碼
* @param perms 申請拒絕的權(quán)限集合
*/
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
Log.i(TAG, "onPermissionsDenied: ");
if (requestCode != RC_CAMERA_AND_RECORD_AUDIO) {
return;
}
for (int i = 0; i < perms.size(); i++) {
if (perms.get(i).equals(Manifest.permission.CAMERA)) {
Log.i(TAG, "onPermissionsDenied: " + "相機權(quán)限拒絕");
} else if (perms.get(i).equals(Manifest.permission.RECORD_AUDIO)) {
Log.i(TAG, "onPermissionsDenied: " + "錄制音頻權(quán)限拒絕");
}
}
}
還有一個問題是:如果權(quán)限申請對話一直彈,用戶也覺得煩,這時候Android在對話框上加了一個不在詢問的勾選框,這時候在怎么requestPermission都不會彈出那個讓用戶選擇允許或者拒絕的對話框了.App還需要使用相機的權(quán)限只能去:設(shè)置->應(yīng)用->當(dāng)前應(yīng)用->權(quán)限,里面去開啟權(quán)限,這時候可以在申請拒絕的回調(diào)onPermissionsDenied中做相應(yīng)的引導(dǎo)操作:轉(zhuǎn)跳到設(shè)置頁面去手動開啟權(quán)限.
/**
* 權(quán)限申請拒絕的回調(diào)
*
* @param requestCode 申請權(quán)限時的請求碼
* @param perms 申請拒絕的權(quán)限集合
*/
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
Log.i(TAG, "onPermissionsDenied: ");
//如果有一些權(quán)限被永久的拒絕, 就需要轉(zhuǎn)跳到 設(shè)置-->應(yīng)用-->對應(yīng)的App下去開啟權(quán)限
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this)
.setTitle("權(quán)限已經(jīng)被您拒絕")
.setRationale("如果不打開權(quán)限則無法使用該功能,點擊確定去打開權(quán)限")
.setRequestCode(10001)//用于onActivityResult回調(diào)做其它對應(yīng)相關(guān)的操作
.build()
.show();
}
}
最后,從設(shè)置頁面轉(zhuǎn)跳回來也可以做一些相應(yīng)的操作
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 10001) {
Toast.makeText(this, " 從開啟權(quán)限的頁面轉(zhuǎn)跳回來 ", Toast.LENGTH_SHORT).show();
}
}
所有流程圖大致如下
圖中1,2,3所指情況:
- App從未申請過權(quán)限,第一次申請權(quán)限時
- App權(quán)限申請被拒絕過
- App申請權(quán)限時,用戶勾選了不在詢問選項,并拒絕
最后EasyPermission還提供了一個可供選擇的注解:AfterPermissionGranted
方法注解,注解中參數(shù)是申請權(quán)限的請求碼.
被@AfterPermissionGranted注解的方法會在請求碼中的所有權(quán)限申請成功之后被調(diào)用
/**
* 去申請權(quán)限
*/
@AfterPermissionGranted(RC_CAMERA_AND_RECORD_AUDIO)
private void requestPermissions() {
String[] perms = {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
//判斷有沒有權(quán)限
if (EasyPermissions.hasPermissions(this, perms)) {
// 如果有權(quán)限了, 就做你該做的事情
// doing something
openCamera();
} else {
// 如果沒有權(quán)限, 就去申請權(quán)限
// this: 上下文
// Dialog顯示的正文
// RC_CAMERA_AND_RECORD_AUDIO 請求碼, 用于回調(diào)的時候判斷是哪次申請
// perms 就是你要申請的權(quán)限
EasyPermissions.requestPermissions(this, "寫上你需要用權(quán)限的理由, 是給用戶看的", RC_CAMERA_AND_RECORD_AUDIO, perms);
}
}