1.概述
不知道大家有沒有遇到過這種情況器一,開發(fā)app的時候發(fā)現(xiàn)自己手機選擇照片是正常的课锌,測試那邊的一臺手機怎么搞都不行,然后查看版本之后才發(fā)現(xiàn)是6.0的手機祈秕。
隨著Android 6.0 7.0 我們開發(fā)者所要應(yīng)對的主要就是新版本SDK帶來的一些變化渺贤,既然是程序員那么我們肯定就特別關(guān)注開發(fā)部分的變化,其中之一就是權(quán)限處理请毛。那么在6.0及以上版本我們的危險權(quán)限都需要在運行的時候去申請志鞍,之前都是在清單文件中配置即可,現(xiàn)在就不行了需要加代碼申請方仿。
2.運行時權(quán)限的檢測
2.1. Android6.0之后的權(quán)限差別
對于6.0以下的權(quán)限及在安裝的時候固棚,根據(jù)權(quán)限聲明產(chǎn)生一個權(quán)限列表街州,用戶只有在同意之后才能完成app的安裝。而在6.0以后玻孟,我們可以直接安裝,當(dāng)app需要權(quán)限是會給予用戶提示用戶可以選擇同意和拒絕鳍征。
新的權(quán)限機制更好的保護了用戶的隱私黍翎,Google將權(quán)限分為兩類,一類是Normal Permissions艳丛,這類權(quán)限一般不涉及用戶隱私匣掸,是不需要用戶進行授權(quán)的,比如訪問網(wǎng)絡(luò)等氮双;另一類是Dangerous Permission碰酝,一般是涉及到用戶隱私的,需要用戶進行授權(quán)戴差,比如讀取sdcard送爸、打電話等等。
看幾個Normal Permissions:
INTERNET
GET_PACKAGE_SIZE
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
CHANGE_WIFI_STATE
VIBRATE
看幾組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
group:android.permission-group.CAMERA
permission:android.permission.CAMERA
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
你會發(fā)現(xiàn)dangerous permissions暖释,危險權(quán)限都是一組一組的袭厂,這是個什么概念呢?又或是有什么用呢球匕?如果app運行在Android 6.x的機器上纹磺,對于授權(quán)機制是這樣的。如果你申請某個危險的權(quán)限亮曹,假設(shè)你的app早已被用戶授權(quán)了同一組的某個危險權(quán)限橄杨,那么系統(tǒng)會立即授權(quán),而不需要用戶去點擊授權(quán)照卦。比如你的app對READ_CONTACTS已經(jīng)授權(quán)了式矫,當(dāng)你的app申請WRITE_CONTACTS時,系統(tǒng)會直接授權(quán)通過窄瘟。此外衷佃,對于申請時彈出的dialog上面的文本說明也是對整個權(quán)限組的說明,而不是單個權(quán)限(ps:這個dialog是不能進行定制的)蹄葱。
2.2. 代碼變化
2.2.1.之前寫都是老套路直接上代碼(已電話撥打為例):
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + mPhoneNumber);
intent.setData(data);
startActivity(intent);
2.2.2.但是現(xiàn)在不行啦氏义,我們需要去檢測該權(quán)限有沒有背用戶授予過,如果沒有則需要申請打電話權(quán)限图云,如果有授予過可以直接撥打電話惯悠。
ContextCompat.checkSelfPermission:檢測權(quán)限
ActivityCompat.requestPermissions:申請權(quán)限
// ContextCompat.checkSelfPermission()
// 方法返回值為PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。
// 當(dāng)返回GRANTED表示有該權(quán)限竣况,DENIED表示沒有該權(quán)限克婶。
if(ContextCompat.checkSelfPermission(this,Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED){
// 沒有該權(quán)限 申請打電話權(quán)限
// 三個參數(shù) 第一個參數(shù)是 Context , 第二個參數(shù)是用戶需要申請的權(quán)限字符串?dāng)?shù)組,第三個參數(shù)是請求碼 主要用來處理用戶選擇的返回結(jié)果
ActivityCompat.requestPermissions(this,new String[]{"Manifest.permission.CALL_PHONE"},CALL_PHONE_REQUEST_CODE);
}else {
// 有該權(quán)限,直接打電話
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + 137XXXXXXXX);
intent.setData(data);
startActivity(intent);
}
2.2.3. 處理回調(diào)
如果用戶同意或是拒絕那么會回調(diào)onRequestPermissionsResult()情萤,別看錯了不是onActivityResult()
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(requestCode == CALL_PHONE_REQUEST_CODE){
if (grantResults !=null&&grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted 通過 打電話
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + 137XXXXXXXX);
intent.setData(data);
startActivity(intent);
} else {
// Permission Denied 被拒絕
Toast.makeText(this,"權(quán)限被拒絕了",Toast.LENGTH_SHORT).show();
}
}
}
2.2.4. 簡單的例子
public class MainActivity extends AppCompatActivity {
// 打電話權(quán)限申請的請求碼
private static final int CALL_PHONE_REQUEST_CODE = 0x0011;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void phoneClick(View view){
if(ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED){
Toast.makeText(this, "申請權(quán)限", Toast.LENGTH_SHORT).show();
ActivityCompat.requestPermissions(this,
new String[]{"Manifest.permission.CALL_PHONE"}, CALL_PHONE_REQUEST_CODE);
}else {
callPhone();
}
}
/**
* 撥打電話
**/
private void callPhone() {
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:147****2514");
intent.setData(data);
startActivity(intent);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == CALL_PHONE_REQUEST_CODE){
if (grantResults !=null&&grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
callPhone();
} else {
// Permission Denied
Toast.makeText(this,"權(quán)限被拒絕了",Toast.LENGTH_SHORT).show();
}
}
}
}
上面就是6.0以上的版本運行時權(quán)限處理鸭蛙,但是我們會發(fā)現(xiàn)一個問題,如果都得這么干那需要些多少代碼量筋岛?下面我們就利用反射加注解的方式封裝我們的權(quán)限處理框架娶视,請看這里Android 6.0 運行時權(quán)限封裝框架
項目的代碼不能夠發(fā)給大家,里面涉及到后臺接口以及數(shù)據(jù)加密睁宰,如果大家感興趣可以看一下我錄的視頻:http://pan.baidu.com/s/1bpqqkGn 肪获。