[TOC]
動態(tài)權(quán)限適配方案
1. 權(quán)限管理的更改
- Android 6.0之前,權(quán)限的申請在清單文件中注冊即可(用戶安裝App時會列出安裝的App的訪問權(quán)限铃剔,而且只有安裝時會出現(xiàn)一次)
- Android 6.0開始锣杂,權(quán)限除了在清單文件中注冊脂倦,部分危險權(quán)限需要在使用時主動向用戶發(fā)起確認(rèn)
6.0之前,App如果申請了各種隱私權(quán)限并在安裝的時候被忽略而允許元莫, 就可以在用戶毫不知曉的情況下訪問權(quán)限內(nèi)的所有東西,比如用戶的通信信息蝶押、用戶的位置等踱蠢,這會侵犯用戶的隱私。這項改動避免了app濫用權(quán)限棋电,也消除了流氓應(yīng)用(不給權(quán)限不讓用)的存在
2. 危險權(quán)限的申請方案
一般開發(fā)中權(quán)限的使用有這么兩種情況:
- 需要讀取設(shè)備信息茎截、讀寫存儲信息權(quán)限,且在應(yīng)用運行立刻需要的赶盔,不立即授予無法正常使用企锌;
- 需要相機、錄音等權(quán)限于未,在應(yīng)用使用到該功能時才需要的撕攒,不立即授予也能正常使用。
因此可以得出申請方案:在應(yīng)用啟動時烘浦,對所有需要的危險權(quán)限進行權(quán)限申請抖坪,立即需要的權(quán)限未被授予的情況下,彈出詢問闷叉,一再拒絕的情況下強制跳應(yīng)用權(quán)限設(shè)置頁面要求開啟擦俐,不授予不能正常使用;其他非立即需要權(quán)限啟動時詢問被拒絕后不在詢問握侧,在使用到該功能時要求授予蚯瞧,不授予不能正常使用該功能
2.1 基本的權(quán)限申請
最基本的權(quán)限申請使用(官方做法在此處)
-
權(quán)限檢查
通過checkSelfPermission(this, Manifest.permission.CAMERA)拿到當(dāng)前申請權(quán)限的授予狀態(tài) -
權(quán)限申請
通過ActivityCompat.requestPermissions(final Activity activity,final String[] permissions, final int requestCode)進行申請權(quán)限 -
申請結(jié)果
通過onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)接收申請結(jié)果 -
申請被拒絕處理
通過ActivityCompat.shouldShowRequestPermissionRationale(Activity activity,String permission)再次申請,該方法返回false時表明本次申請權(quán)限被禁止詢問申請品擎,此時需要進行手動開啟 -
應(yīng)用設(shè)置頁手動允許
各種方案跳轉(zhuǎn)
If your application is targeting an API level before 23 (Android M) then both:ContextCompat.CheckSelfPermission and Context.checkSelfPermission doesn't work and always returns 0 (PERMISSION_GRANTED). Even if you run the application on Android 6.0 (API 23).
在targetSdkVersion小于23(Android M)的時候埋合,ContextCompat.CheckSelfPermission 和Context.checkSelfPermission方法都不能正常工作并且始終返0(PERMISSION_GRANTED),即使你的應(yīng)用運行在Android6.0(API 23)的設(shè)備上孽查。
當(dāng)編譯targetSDKVersion < 23時使用
ContextCompat.checkSelfPermission and Context.checkSelfPermission將會不起作用
需要使用
PermissionChecker.checkSelfPermission
同樣targetSDKVersion >= 23時PermissionChecker.checkSelfPermission也會無效饥悴,
需要使用ContextCompat.checkSelfPermission
2.2 權(quán)限申請方案封裝
將申請方法全部封裝到基類PermissionActivity中,子類通過調(diào)用父類的方法進行權(quán)限的申請判斷
requestPermission(Manifest.permission.CAMERA, "需要拍照(此處解釋下為啥需要這個權(quán)限)", new PermissionActivity.PermissionCallback() {
@Override
public void granted() {
Toast.makeText(TestPermissionActivity.this,"獲取成功",Toast.LENGTH_SHORT).show();
}
@Override
public void denied() {
Toast.makeText(TestPermissionActivity.this,"獲取失敗",Toast.LENGTH_SHORT).show();
}
@Override
public void waitUserInitiativeSet() {
Toast.makeText(TestPermissionActivity.this,"用戶設(shè)置中",Toast.LENGTH_SHORT).show();
}
});
PermissionActivity
package com.sj.d_1_adaptiveversion.version_6;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.PermissionChecker;
public class PermissionActivity extends AppCompatActivity {
private int permissionResultCode = 1;
private PermissionCallback permissionCallback;
/**
* 權(quán)限申請入口
* @param permission 權(quán)限名
* @param permissionReason 獲取理由
* @param permissionCallback 結(jié)果回調(diào)
*/
public void requestPermission(final String permission, String permissionReason, PermissionCallback permissionCallback) {
this.permissionCallback=permissionCallback;
if (!hasPermission(permission)) {
if (needExplainPermissionReason(permission)) {
new AlertDialog.Builder(this)
.setTitle("")
.setMessage(permissionReason)
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermission(permission);
}
})
.show();
} else {
requestPermission(permission);
}
}else {
if (this.permissionCallback != null) {
this.permissionCallback.granted();
}
}
}
/**
* 申請權(quán)限的有無狀態(tài)
* @param permission
* @return
*/
private boolean hasPermission(String permission) {
int targetSdkVersion = getApplicationInfo().targetSdkVersion;
if (targetSdkVersion >= Build.VERSION_CODES.M) {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
} else {
return PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED;
}
}
/**
* 是否需要解釋該權(quán)限
* 權(quán)限需要解釋的條件:上一次請求被拒絕盲再,且沒有點擊不再詢問
* @param permission
* @return true 需要解釋后再次進行詢問西设;false:不需詢問有兩種情況 用戶禁止詢問了,從未詢問過
*/
private boolean needExplainPermissionReason(String permission) {
return ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
}
/**
* 申請權(quán)限
* @param permission
*/
private void requestPermission(String permission) {
ActivityCompat.requestPermissions(PermissionActivity.this, new String[]{permission}, permissionResultCode);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull final String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == permissionResultCode) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//權(quán)限通過
} else {
if (!needExplainPermissionReason(Manifest.permission.CAMERA)) {
//解釋理由 跳轉(zhuǎn)去應(yīng)用信息頁設(shè)置
new AlertDialog.Builder(this)
.setTitle("提示")
.setMessage("主動詢問已被禁止答朋,需要到應(yīng)用權(quán)限配置頁面主動授予是否允許贷揽?")
.setPositiveButton("跳轉(zhuǎn)", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
toAppPermissionSet();
if (permissionCallback != null) {
permissionCallback.waitUserInitiativeSet();
}
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (permissionCallback != null) {
permissionCallback.denied();
}
}
})
.show();
}
}
return;
}
}
/**
* 跳轉(zhuǎn)應(yīng)用權(quán)限配置頁面
*/
private void toAppPermissionSet() {
AppPermissionSettingPageUtils.toPermissionSettingPage(this);
}
public interface PermissionCallback{
/**
* 獲取權(quán)限成功
*/
void granted();
/**
* 獲取權(quán)限失敗
*/
void denied();
/**
* 用戶跳轉(zhuǎn)配置頁配置中
*/
void waitUserInitiativeSet();
}
}
3 危險權(quán)限清單
Dangerous Permissions:
group:android.permission-group.CONTACTS //聯(lián)系人相關(guān)
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
group:android.permission-group.PHONE //手機相關(guān)
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR //日歷相關(guān)
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
group:android.permission-group.CAMERA //相機
permission:android.permission.CAMERA
group:android.permission-group.SENSORS //傳感器
permission:android.permission.BODY_SENSORS
group:android.permission-group.LOCATION //位置相關(guān)
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
group:android.permission-group.STORAGE //存儲相關(guān)
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
group:android.permission-group.MICROPHONE //麥克風(fēng)
permission:android.permission.RECORD_AUDIO
group:android.permission-group.SMS //短信相關(guān)
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS