一、6.0發布權限變化
1.Android需要手動加入權限申請原因:
1)權限分為了兩類:一類是Normal Permissions,這類權限一般不涉及用戶隱私,是不需要用戶進行授權的,比如手機震動、訪問網絡等;另一類是Dangerous Permission,一般是涉及到用戶隱私的,需要用戶進行授權,比如讀取sdcard、訪問通訊錄等。
- Normal Permissions如下
ACCESS_LOCATION_EXTRA_COMMANDS ACCESS_NETWORK_STATE ACCESS_NOTIFICATION_POLICY ACCESS_WIFI_STATE BLUETOOTH BLUETOOTH_ADMIN BROADCAST_STICKY CHANGE_NETWORK_STATE CHANGE_WIFI_MULTICAST_STATE CHANGE_WIFI_STATE DISABLE_KEYGUARD EXPAND_STATUS_BAR GET_PACKAGE_SIZE INSTALL_SHORTCUT INTERNET KILL_BACKGROUND_PROCESSES MODIFY_AUDIO_SETTINGS NFC READ_SYNC_SETTINGS READ_SYNC_STATS RECEIVE_BOOT_COMPLETED REORDER_TASKS REQUEST_INSTALL_PACKAGES SET_ALARM SET_TIME_ZONE SET_WALLPAPER SET_WALLPAPER_HINTS TRANSMIT_IR UNINSTALL_SHORTCUT USE_FINGERPRINT VIBRATE WAKE_LOCK WRITE_SYNC_SETTINGS
- Dangerous Permissions:
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 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
2)權限不是所有的都自動允許給你的app的,默認是沒有Dangerous Permission的,需要用戶手動去申請,否則功能不能使用,例如:拍照、選取相冊、下載、錄音、打電話、發短信等等,可能會造成Crash崩潰。
3)6.0及之后系統不會自動去申請權限,也不會給提示,故需要手動自己添加申請。
二、Android程序內部加入6.0權限申請
1.確定自己App哪些地方需要申請?
針對自己對應的地方去寫權限請求。
例如:拍照、選取相冊、下載、錄音、打電話、發短信等等;
android.Manifest.permission.CAMERA;
android.Manifest.permission.READ_EXTERNAL_STORAGE
Manifest.permission.WRITE_EXTERNAL_STORAGE;
android.Manifest.permission.READ_PHONE_STATE
android.Manifest.permission.PROCESS_OUTGOING_CALLS;
android.Manifest.permission.RECORD_AUDIO;
等等,
注意:Manifests里邊必須注冊權限,低版本手機才能用,高版本手機才可以申請。
2.申請權限並處理
1)在AndroidManifest文件中添加需要的權限,例:
<uses-permission android:name="android.permission.CAMERA"/>
2)加入檢查權限的判斷,例:
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
}else{
//
}
這里涉及到一個API,ContextCompat.checkSelfPermission,主要用於檢測某個權限是否已經被授予,方法返回值
3)沒有這個權限,去請求權限
ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
該方法是異步的,第一個參數是Context;第二個參數是需要申請的權限的字符串數組;第三個參數為requestCode,主要用於回調的時候檢測。可以從方法名requestPermissions以及第二個參數看出,是支持一次性申請多個權限的,系統會通過對話框逐一詢問用戶是否授權。
4)處理權限申請回調
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // contacts-related task you need to do. } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } } }
對於權限的申請結果,首先驗證requestCode定位到你的申請,然后驗證grantResults對應於申請的結果,這里的數組對應於申請時的第二個權限字符串數組。如果你同時申請兩個權限,那么grantResults的length就為2,分別記錄你兩個權限的申請結果。如果申請成功,就可以做你的事情了~
3.針對大部分權限申請封裝
1)權限工具類:PermissionUtils
package com.up366.mobile.common.utils;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.View;
import com.up366.common.log.Logger;
import com.up366.mobile.R;
import com.up366.mobile.common.ui.baseui.BaseActivity;
import com.up366.mobile.common.ui.baseui.BaseFragmentActivity;
import com.up366.mobile.common.ui.baseui.IPermissionsCallback;
/**
* @author 王靜
* @description 權限申請公用類
* @date 2017年3月9日 下午1:55:37
*/
public class PermissionUtils {
public static int permisionIndexCount = 1;
public static final int PERMISSION_ALL = 0;
public static final int PERMISSION_CAMERA = 1;
public static final int PERMISSION_READ_EXTERNAL_STORAGE = 2;
public static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 3;
public static final int PERMISSION_READ_PHONE_STATE = 4;
public static final int PERMISSION_RECORD_AUDIO = 5;
/**
* 檢查權限
*
* @param context
* @param permissionsCallback:回調做后續操作
*/
public static void requestToUserPermission(Context context, IPermissionsCallback permissionsCallback) {
//BaseActivity將PermissionsCallback傳入,應用同一個callBack做同樣的后續操作
if (context instanceof BaseActivity) {
((BaseActivity) context).setPermissionsCallback(permissionsCallback);
} else if (context instanceof BaseFragmentActivity) {
((BaseFragmentActivity) context).setPermissionsCallback(permissionsCallback);
} else {
throw new IllegalStateException("not Activity context");
}
//判斷是哪種類型權限申請
switch (permisionIndexCount) {
case PERMISSION_ALL://所有的,針對小米6.0手機權限有問題,啟動不了項目,故去掉剛剛進入app的MainVkActivity就調用申請,可寫到內部的Fragment
int i = 0;
String[] permissionStr = new String[6];
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = android.Manifest.permission.CAMERA;
}
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = android.Manifest.permission.READ_EXTERNAL_STORAGE;
}
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = Manifest.permission.WRITE_EXTERNAL_STORAGE;
}
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = android.Manifest.permission.READ_PHONE_STATE;
permissionStr[i++] = android.Manifest.permission.PROCESS_OUTGOING_CALLS;
}
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = android.Manifest.permission.RECORD_AUDIO;
}
if (permissionStr.length != 0)
ActivityCompat.requestPermissions((Activity) context, permissionStr, 100);//去請求所有權限
break;
case PERMISSION_CAMERA://相機權限也要有存儲權限
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
//沒有此權限,去請求權限
ActivityCompat.requestPermissions((Activity) context, new String[]{android.Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
} else {
//有權限,直接回去做后續操作
handleResult(context, permisionIndexCount);
}
break;
case PERMISSION_READ_EXTERNAL_STORAGE:
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
} else {
handleResult(context, permisionIndexCount);
}
break;
case PERMISSION_WRITE_EXTERNAL_STORAGE:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
} else {
handleResult(context, permisionIndexCount);
}
break;
case PERMISSION_READ_PHONE_STATE:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.PROCESS_OUTGOING_CALLS}, 100);
} else {
handleResult(context, permisionIndexCount);
}
break;
case PERMISSION_RECORD_AUDIO:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.RECORD_AUDIO}, 100);
} else {
handleResult(context, permisionIndexCount);
}
break;
}
}
/**
* 有權限,直接去做后續操作
*
* @param context
* @param permisionIndexCount:權限類型index
*/
private static void handleResult(Context context, int permisionIndexCount) {
IPermissionsCallback permissionsCallback = null;
if (context instanceof BaseActivity) {
permissionsCallback = ((BaseActivity) context).getPermissionsCallback();
} else if (context instanceof BaseFragmentActivity) {
permissionsCallback = ((BaseFragmentActivity) context).getPermissionsCallback();
} else {
throw new IllegalStateException("not Activity context");
}
if (permissionsCallback == null) {
Logger.warn("沒有注冊IPermissionsCallback");
} else {
permissionsCallback.onResult(permisionIndexCount);
}
}
/**
* 申請權限,回調
*
* @param requestCode:code碼=100成功
* @param permissions:所請求的權限名稱
* @param grantResults:請求結果:PackageManager.PERMISSION_DENIED申請被用戶點禁用;PERMISSION_GRANTED申請成功
* @param context:上下文
* @param result:回調,回去做后續操作
*/
public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults, final Context context, doSomethingResult result) {
if (requestCode == 100) {
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {//拒絕啦
String msg = "";
String permissionName = "";
switch (permisionIndexCount) {//根據請求的類型,彈提示“您已禁用應用所需權限,有些功能將無法使用,請返回重新嘗試,並選擇允許權限。”
case PERMISSION_ALL:
msg = context.getString(R.string.permission_all);
permissionName = "相關權限";
break;
case PERMISSION_CAMERA:
msg = context.getString(R.string.permission_camera);
permissionName = "相機權限";
break;
case PERMISSION_READ_EXTERNAL_STORAGE:
msg = context.getString(R.string.permission_read_exteranal_storage);
permissionName = "存儲權限";
break;
case PERMISSION_WRITE_EXTERNAL_STORAGE:
msg = context.getString(R.string.permission_write_exteranal_storage);
permissionName = "存儲權限";
break;
case PERMISSION_READ_PHONE_STATE:
msg = context.getString(R.string.permission_read_phone_state);
permissionName = "電話權限";
break;
case PERMISSION_RECORD_AUDIO:
msg = context.getString(R.string.permission_read_exteranal_storage);
permissionName = "錄音權限";
break;
}
//這個用戶拒絕了權限請求,並且選擇了不再提示!跳轉至設置頁面
//shouldShowRequestPermissionRationale方法只能在23及以上版本調用
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !((Activity) context).shouldShowRequestPermissionRationale(permissions[i])) {
new CuDialog(context).create(R.layout.permission_denyed_forerer_to_setting)
.setText(R.id.dialog_msg, "無法獲取" + permissionName + ",需要手動授權,否則該功能無法使用。")
.setOnClickListener(new int[]{R.id.dialog_leftbtn, R.id.dialog_rightbtn}, new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_rightbtn) {//去設置
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", context.getPackageName(), null);
intent.setData(uri);
((Activity) context).startActivityForResult(intent, 1024);
return;
} else if (v.getId() == R.id.dialog_leftbtn) {//取消
}
}
}).show();
} else {
CuDialog.showOkDialog((Activity) context, msg);
}
return;
}
}
//權限被同意,做后續操作
result.onResult(permisionIndexCount);
}
}
}
/**
* 做后續操作接口
*/
public interface doSomethingResult {
void onResult(int permisionIndexCount);
}
}
PermissionUtils的gist鏈接:https://gist.github.com/wangjing0311/bf33938d2a762870d406a1b10ace75fe
2)所用接口:IPermissionsCallback
package com.up366.mobile.common.ui.baseui;
public interface IPermissionsCallback {
void onResult(int permisionIndexCount);
}
3)BaseActivity與BaseFragmentActivity加入
onRequestPermissionsResult回調處理,還有IPermissionsCallback變量及get,set方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (permissionsCallback != null)
PermissionUtils.onRequestPermissionsResult(requestCode, permissions, grantResults, this, new PermissionUtils.doSomethingResult() {
@Override
public void onResult(int permisionIndexCount) {
permissionsCallback.onResult(permisionIndexCount);
}
});
}
private IPermissionsCallback permissionsCallback;
public void setPermissionsCallback(IPermissionsCallback permissionsCallback) {
this.permissionsCallback = permissionsCallback;
}
public IPermissionsCallback getPermissionsCallback() {
return permissionsCallback;
}
4)Activity中權限申請的調用:
PermissionUtils.permisionIndexCount = PermissionUtils.PERMISSION_CAMERA;
PermissionUtils.requestToUserPermission(AlertUserInfoActivity.this, permissionsCallback);
及回調處理:
private IPermissionsCallback permissionsCallback = new IPermissionsCallback() {
@Override
public void onResult(int permisionIndexCount) {
switch (permisionIndexCount) {
case 1:
takePictureToPhoto();
break;
case 2:
getLocalPicToPhoto();
break;
}
}
};
本人封裝處理,已用感覺比較好用,敬請使用。
