本文目錄
動態權限概述
從Android6.0
開始,Google調整了應用的權限申請方案。調整之後將權限分級,分成了普通權限
和危險權限
,普通權限的授權方式跟之前一樣,只需要在Manifest
文件中申明即可,危險權限不僅需要在Manifest
文件中聲明,還需要在程序中調用官方提供的Api主動申請。
動態權限分類
Android6.0
以後,一共將動態權限分成了9組,每組只要有一個權限申請成功了,就默認整組權限都可以使用了。這九組權限分別如下:
權限組名稱 | 權限組 | 權限組權限成員 |
---|---|---|
讀寫聯繫人 | group:android.permission-group.CONTACTS | permission:android.permission.WRITE_CONTACTS permission:android.permission.GET_ACCOUNTS permission:android.permission.READ_CONTACTS |
電話 | group:android.permission-group.PHONE | 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 | 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 | permission:android.permission.ACCESS_FINE_LOCATION permission:android.permission.ACCESS_COARSE_LOCATION |
存儲卡 | group:android.permission-group.STORAGE | permission:android.permission.READ_EXTERNAL_STORAGE permission:android.permission.WRITE_EXTERNAL_STORAGE |
多媒體 | group:android.permission-group.MICROPHONE | permission:android.permission.RECORD_AUDIO |
SMS | group:android.permission-group.SMS | 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 |
動態權限申請方法
方法1:官方API提供的方法
步驟1:檢查是否有權限
由於低於API 23
是不需要使用動態權限申請的,我們需要先判斷一下系統版本,代碼如下是Android 6.0以上
的系統還是Android 6.0以下
的系統。用ContextCompat
類中的checkSelfPermission
方法進行是否有權限判斷。
public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
return context.checkPermission(permission, android.os.Process.myPid(), Process.myUid());
}
具體使用方法如下:
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//無該權限,需要申請
}
} else { //低於23 不需要處理
}
步驟2:申請權限
在步驟的的checkSelfPermission
方法中如果判斷沒有權限,就需要用到ActivityCompat
類中的requestPermissions
方法進行動態權限申請,該方法需要傳一個需要申請權限名稱的權限permissions
數組。
public static void requestPermissions(final @NonNull Activity activity,
final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode) {
}
申請方法如下:先定一個需要申請權限的權限數組PERMISSIONS_STORAGE
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"};
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
步驟3:回調函數的處理
由於權限申請是異步的,用戶完成了以後,需要回調函數處理,
Activity
中提供了一個回調處理方法onRequestPermissionsResult
,只需要重寫該方法即可
case 中的參數REQUEST_EXTERNAL_STORAGE
即步驟2申請權限中定一個的參數
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_EXTERNAL_STORAGE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "授權成功!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "授權被拒絕!", Toast.LENGTH_SHORT).show();
}
}
}
}
完整代碼
我們以申請SD卡讀寫權限爲例,完整代碼如下:
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 23) {
checkPermission();
}
}
private void checkPermission() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission
.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "請開通相關權限,否則無法正常使用本應用!", Toast.LENGTH_SHORT).show();
}
//申請權限
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
} else {
Toast.makeText(this, "已授權成功!", Toast.LENGTH_SHORT).show();
dothings();
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_EXTERNAL_STORAGE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
dothings();
Toast.makeText(this, "授權成功!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "授權被拒絕!", Toast.LENGTH_SHORT).show();
}
}
}
}
public void dothings() {
}
}
AndroidManifest.xml聲明權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
方法2:RxPermission
RxPermission
可以幫助開發者簡化獲取權限的相關處理操作,而且內部也自動幫我們判斷了版本是否需要申請權限。同時結合RxJava
可以方便的回調各種結果。
官網:https://github.com/tbruyelle/RxPermissions
引入依賴
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
}
由於rxpermissions
需要用到rxjava,所有rxjava
的包也一起引入。
聲明權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA"/>
申請單個權限
RxPermissions permissions = new RxPermissions(this);
permissions.request(Manifest.permission.CAMERA)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) {
if (aBoolean ) {
Toast.makeText(MainActivity.this, "授權成功!", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this, "授權失敗!", Toast.LENGTH_SHORT).show();
}
}
});
申請多個權限
RxPermissions permissions = new RxPermissions(this);
permissions.request(Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) {
if (aBoolean ) {
Toast.makeText(MainActivity.this, "授權成功!", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this, "授權失敗!", Toast.LENGTH_SHORT).show();
}
}
});
方法3:AndPermission
AndPermission
跟前面的RxPermission
使用方法類似
官網:https://github.com/yanzhenjie/AndPermission
引入依賴
implementation 'com.yanzhenjie:permission:2.0.3'
申請單個或多個權限
AndPermission.with(this)
.runtime()
.permission(Permission.WRITE_EXTERNAL_STORAGE,Permission.CAMERA)
.onGranted(permissions -> {
Toast.makeText(MainActivity.this, "授權成功!", Toast.LENGTH_SHORT).show();
})
.onDenied(permissions -> {
Toast.makeText(MainActivity.this, "授權失敗!", Toast.LENGTH_SHORT).show();
})
.start();
效果如下: