講到硬體控制,總有一天要面對權限管理,不過Google
有個權限的第三方EasyPermissions
,今天就簡單講一下怎麼安裝和使用。
https://github.com/googlesamples/easypermissions
dependencies {
implementation 'pub.devrel:easypermissions:3.0.0'
}
onPermissionsGranted
會被執行onPermissionsDenied
會被執行class CropLensActivity : AppCompatActivity(), PermissionCallbacks {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_crop_lens)
}
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
}
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
}
}
ctrl + O
叫出Override Members
頁面,尋找onRequestPermissionsResult
,點選OK
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
不管是onPermissionsGranted
或onPermissionsDenied
,傳出來的perms
都是一串英文android.permission.CAMERA
,所以我們要請使用者去設定開啟相對應的權限,所以要把這些中文化。
class PermissionsTransformer {
companion object {
const val CALENDAR = "日曆"
const val CAMERA = "相機"
const val ACCOUNTS = "聯絡人"
const val LOCATION = "位置"
const val AUDIO = "麥克風"
const val CALLS = "電話"
const val SENSORS = "人體感應器"
const val SMS = "簡訊"
const val STORAGE = "儲存"
const val ELSE = "未知的權限"
const val READ_CALENDAR = "android.permission.READ_CALENDAR"
const val WRITE_CALENDAR = "android.permission.WRITE_CALENDAR"
const val PERMISSION_CAMERA = "android.permission.CAMERA"
const val READ_CONTACTS = "android.permission.READ_CONTACTS"
const val WRITE_CONTACTS = "android.permission.WRITE_CONTACTS"
const val GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"
const val ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION"
const val ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION"
const val RECORD_AUDIO = "android.permission.RECORD_AUDIO"
const val READ_PHONE_STATE = "android.permission.READ_PHONE_STATE"
const val CALL_PHONE = "android.permission.CALL_PHONE"
const val READ_CALL_LOG = "android.permission.READ_CALL_LOG"
const val WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG"
const val VOICEMAIL_ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL"
const val ADD_VOICEMAIL = "android.permission.ADD_VOICEMAIL"
const val USE_SIP = "android.permission.USE_SIP"
const val PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS"
const val BODY_SENSORS = "android.permission.BODY_SENSORS"
const val RECEIVE_SMS = "android.permission.RECEIVE_SMS"
const val READ_SMS = "android.permission.READ_SMS"
const val SEND_SMS = "android.permission.SEND_SMS"
const val RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH"
const val RECEIVE_MMS = "android.permission.RECEIVE_MMS"
const val READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE"
const val WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"
}
fun getText(perms: String): String {
when (perms) {
READ_CALENDAR,
WRITE_CALENDAR -> return CALENDAR
PERMISSION_CAMERA -> return CAMERA
READ_CONTACTS,
WRITE_CONTACTS,
GET_ACCOUNTS -> return ACCOUNTS
ACCESS_FINE_LOCATION,
ACCESS_COARSE_LOCATION -> return LOCATION
RECORD_AUDIO -> return AUDIO
READ_PHONE_STATE,
CALL_PHONE,
READ_CALL_LOG,
WRITE_CALL_LOG,
VOICEMAIL_ADD_VOICEMAIL,
ADD_VOICEMAIL,
USE_SIP,
PROCESS_OUTGOING_CALLS -> return CALLS
BODY_SENSORS -> return SENSORS
RECEIVE_SMS,
READ_SMS,
RECEIVE_WAP_PUSH,
SEND_SMS,
RECEIVE_MMS -> return SMS
READ_EXTERNAL_STORAGE,
WRITE_EXTERNAL_STORAGE -> return STORAGE
else -> return ELSE
}
}
fun getPermissionsList(perms: List<String>): StringBuilder {
val permissionsList = HashSet<String>()
val permissionsText = StringBuilder()
perms.forEach { it ->
permissionsList.add(getText(it))
}
permissionsList.forEach { it ->
permissionsText.append(it)
permissionsText.append("\n")
}
return permissionsText
}
}
順手寫個測試吧
class PermissionsTransformerTest {
@Test
fun permissions_text_return_storage() {
val text = PermissionsTransformer().getText(PermissionsTransformer.WRITE_EXTERNAL_STORAGE)
assertEquals(PermissionsTransformer.STORAGE, text)
}
}
然後還需要一個AlertDialog
,跟使用者說要開啟設定頁面的什麼權限
class PermissionsDeniedAlertDialog(val context: Context) {
companion object {
const val PACKAGE = "package"
const val STRING_EMPTY = ""
}
fun show(title: String = STRING_EMPTY, message: String = STRING_EMPTY) {
AlertDialog
.Builder(context)
.setTitle(title)
.setCancelable(false)
.setMessage(message)
.setPositiveButton(R.string.confirm) { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
val uri = Uri.fromParts(PACKAGE, context.packageName, null)
this.data = uri
}
context.startActivity(intent)
}
.show()
}
}
基本設定完成後,可以來寫程式了
onRequestPermissionsResult
的地方新增EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
,把權限控管交給EasyPermissions
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
}
onPermissionsDenied
的地方新增PermissionsDeniedAlertDialog(this).show()
,當使用者拒絕提供權限時,顯示AlertDialog
,跟使用者說要開啟設定頁面的權限。
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
PermissionsDeniedAlertDialog(this).show(
"權限不足",
"請開啟以下權限:\n${PermissionsTransformer().getPermissionsList(perms)}"
)
}
假設我們要求讀取和寫入的權限,首先建立陣列
val permissionList = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
如果要做的事情沒有權限,啟動EasyPermissions.requestPermissions()
,其中有個100
,就是使用者提供權限時,onPermissionsGranted
的requestCode
就會有100
if (!EasyPermissions.hasPermissions(this, *permissionList)) {
EasyPermissions.requestPermissions(
this,
"請提供讀寫檔案權限",
100,
*permissionList
)
}