- 原生 API 的使用
- 實踐中問題
首先介紹一下千劈,Android 6.0 的權(quán)限機制的變化大家都知道寝受,從原來安裝時一次性全部授權(quán)讶踪,變?yōu)樵谶\行時才向用戶申請授權(quán)凿傅。
當然在 6.0 也不是全部的權(quán)限都需要運行時授權(quán),現(xiàn)在的權(quán)限分為兩類:
Normal Permissions焰轻,一般不涉及用戶隱私臭觉,比如手機震動、訪問網(wǎng)絡(luò)等辱志。
Dangerous Permission蝠筑,涉及到用戶隱私的,比如訪問通訊錄等揩懒,這一類的權(quán)限就需要運行時授權(quán)菱肖。
還有比較特別的一點是,這些危險權(quán)限是分組的旭从,比如第一組的權(quán)限和聯(lián)系人有關(guān)稳强,當我們獲取到用戶授予的permission:android.permission.WRITE_CONTACTS
權(quán)限時,同組下的權(quán)限就默認一起獲得和悦,不需要再次申請退疫。
下面是危險權(quán)限一覽,不在這里的權(quán)限的申請和 6.0 以前是一樣的鸽素。
//聯(lián)系人
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
//麥克風(fēng)
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
然后是最后的效果圖:
因為系統(tǒng)原生的 API 中褒繁,如果用戶選擇了「不再提示」則不會再彈出申請權(quán)限的對話框。
但是假設(shè)我的 APP 依靠藍牙向設(shè)備發(fā)送信息馍忽,但用戶未授予藍牙權(quán)限棒坏,則這個 APP 就無作為了燕差,所以要捕獲到這種情況并且彈出對話框。
還有一點比較重要的坝冕,下面一部分代碼在魅族徒探、小米等系統(tǒng)上是無效的,猜測是因為它們有自己的權(quán)限機制喂窟,關(guān)于這些情況的處理后面再說测暗。
原生 API 的實踐
參考官網(wǎng)中文教程:在運行時請求權(quán)限
- 檢查權(quán)限
if(ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
}
checkSelfPermission()
方法傳入 context 和需要申請的權(quán)限,返回值:
public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
當為 PERMISSION_GRANTED
時則已經(jīng)獲取到權(quán)限磨澡。
- 申請權(quán)限
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 10)
requestPermissions()
方法傳入 context碗啄,申請的權(quán)限的字符串數(shù)組,回調(diào)返回的參數(shù)稳摄。
所以該方法可以一次申請多個權(quán)限稚字,并且申請結(jié)果會回調(diào)到 Activity 的 onRequestPermissionsResult()
方法中。
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
//requstCode 是 requestPermissions 傳入的第三個參數(shù)
//permissions[] 是申請的權(quán)限的數(shù)組
//grantResults[] 是申請的結(jié)果
}
- 特殊的方法:
ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION))
方法傳入 context 和 權(quán)限名厦酬,如果用戶在申請權(quán)限對話框中拒絕了申請胆描,則該方法返回 true。
也就是當用戶拒絕了一次申請后弃锐,APP 再次申請的時候應(yīng)該解釋為什么需要申請該權(quán)限袄友。
還有就是如果用戶選擇了「不再提示」殿托,該方法返回 false霹菊。
- 完整代碼
這里用上了 Kotlin 和 Anko,如果看不懂就該補習(xí)了支竹。
fun getPermission(){
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION)){
//此時用戶已經(jīng)拒絕了一次申請旋廷,所以彈出對話框解釋申請的原因
alert("申請開啟定位權(quán)限,如果不打開定位權(quán)限礼搁,將不能運行該 APP","申請權(quán)限"){
positiveButton("同意",{
ActivityCompat.requestPermissions(act,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 10)
})
}.show()
}else {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 10)
}
}else{
toast("已擁有權(quán)限")
}
}
//申請方法的回調(diào)
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 10){
//requestCode 為 10 時饶碘,才是對于申請方法的回調(diào)。
if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
toast("申請權(quán)限成功")
}else{
if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
//在回調(diào)中如果發(fā)現(xiàn)用戶拒絕了申請馒吴,則再一次彈出對話框
//即使用戶選擇了「不再提示」這個對話框也會彈出
alert("如果不打開定位權(quán)限扎运,將不能使用藍牙,是否跳轉(zhuǎn)到應(yīng)用詳情頁面", "申請權(quán)限") {
positiveButton("確定", {
//將會跳轉(zhuǎn)到應(yīng)用的詳情頁面
val localIntent = Intent()
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
localIntent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
localIntent.data = Uri.fromParts("package", packageName, null)
startActivity(localIntent)
})
negativeButton("取消", { dialog -> dialog.dismiss() })
}.show()
}
}
}
}
遇到的問題
就如上面說的,我在魅族和小米的手機上都試了一下饮戳,這里的代碼也不能說完全無用豪治,但是會出很多問題。
比如說在魅族的手機上(魅藍 note 5扯罐,F(xiàn)lyme 6.0.2.1A)负拟,無論授權(quán)與否,checkSelfPermission()
方法都只會返回 0歹河,也就是已授權(quán)的返回值 掩浙。
這種情況下花吟,比如我需要打開藍牙,那就直接執(zhí)行打開藍牙的方法厨姚,假如報錯衅澈、或者隔了一段時間后還是沒有打開,就彈出對話框提示用戶手動打開遣蚀。
if (mBluetoothAdapter == null){
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter = bluetoothManager.adapter
}
var isEnable = bluetoothAdapter?.isEnabled ?: false
if(!isEnable){
//嘗試申請權(quán)限
bluetoothAdapter?.enable()
}
...
//延時五秒后再一次判斷
if (mBluetoothAdapter?.isEnabled == false){
//跳轉(zhuǎn)到應(yīng)用詳情頁面
val localIntent = Intent()
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
localIntent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
localIntent.data = Uri.fromParts("package", packageName, null)
startActivity(localIntent)
}
這應(yīng)該是最笨的方法了矾麻,如果有更好的方法還請告知。