iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
Mobile Development

重新瞭解Android硬體控制系列 第 10

110/14 - EasyPermissions與他的快樂伙伴

  • 分享至 

  • xImage
  •  

講到硬體控制,總有一天要面對權限管理,不過Google有個權限的第三方EasyPermissions,今天就簡單講一下怎麼安裝和使用。

安裝

https://github.com/googlesamples/easypermissions

dependencies {
    implementation 'pub.devrel:easypermissions:3.0.0'
}    

Activity繼承PermissionCallbacks

  • 使用者同意權限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)

}

權限中文化

不管是onPermissionsGrantedonPermissionsDenied,傳出來的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,就是使用者提供權限時,onPermissionsGrantedrequestCode就會有100

if (!EasyPermissions.hasPermissions(this, *permissionList)) {
    EasyPermissions.requestPermissions(
        this,
        "請提供讀寫檔案權限",
        100,
        *permissionList
    )
}

上一篇
110/13 - 把照片儲存在Pictures/應用程式名稱資料夾 - 3
下一篇
110/16 - 整合Android 6到Android 11
系列文
重新瞭解Android硬體控制14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言