Android Runtime Permission을 RxJava로 처리하기
Android 6.0 API 23 Marshmallow 버전 이상 부터는 Danger Level 권한에 대해서 Runtime Permission 요청 / 처리 를 해야합니다.
위험한 권한 및 권한 그룹
| 권한 그룹 | 권한 |
|---|---|
CALENDAR |
READ_CALENDAR, WRITE_CALENDAR |
CAMERA |
CAMERA |
CONTACTS |
READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS |
LOCATION |
ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION |
MICROPHONE |
RECORD_AUDIO |
PHONE |
READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG ,WRITE_CALL_LOG, ADD_VOICEMAIL, USE_SIP, PROCESS_OUTGOING_CALLS |
SENSORS |
BODY_SENSORS |
SMS |
SEND_SMS, RECEIVE_SMS, READ_SMS, RECEIVE_WAP_PUSH, RECEIVE_MMS |
STORAGE |
READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE |
권한 사용
예를 들어, SMS메시지를 수신 해야하는 경우 애플리케이션은 다음과 같이 권한을 지정해야합니다. (런타임권한이 나오기 전인 안드로이드 6.0미만 버전에서는 이것으로 충분했습니다.)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp" >
<uses-permission android:name="android.permission.RECEIVE_SMS" />
...
</manifest>
권한 여부 확인하기
6.0을 기준으로 상위버전과 하위 버전 호환을 위해 ActivityCompat이 존재합니다.
권환 확인 메소드
ActivityCompat.checkSelfPermission(activity:Activity, permission: String) : Int 메소드를 이용하면 권한여부를 확인할 수 있습니다.
반환값으로는 Boolean 이 아닌 Int가 반환되는데, 권한이 이미 승인된경우 0, 권한이 없거나 거부된경우 -1로 반환됩니다
이미 정의된 리터럴 상수를 이용하여 조건식을 만들 수 있습니다.
권한 허가됨, 값 0 : PackageManager.PERMISSION_GRANTED
권한 거부됨, 값 1 : PackageManager.PERMISSION_DENIED
파라미터 설명
activity : 권한확인을 필요로 하는 액티비티 객체
예) this@MainActivity
permission : 권한 이름, Manifest.permission에 정의 되어있습니다.
런타임에 권한 요청하기
권한요청 메소드
ActivityCompat.requestPermission(activity:Activity, permissions:Array
파라미터 설명
activity : 권한을 필요로 하는 액티비티 객체
permissions : 필요한 권한 목록, String 타입의 배열.
예) arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.Manifest.permission.RECEIVE_SMS)
requestCode : 권한 요청을 구분할 수 있는 코드, 보통 개발자가 직접 리터럴 상수를 정의해서 씀.
예) val REQUEST_PERMISSION_CODE = 0
권한 요청 후 콜백 받기
콜백메서드
권한요청하는 requestPermission 메소드 호출시에 OnRequestPermissionsResultCallback 인터페이스를 구현한 액티비티를 파라미터로 넣었다면 Activitiy 내에서
onRequestPermissionsResult(requestCode: Int, permissions: Array
콜백 메소드를 override할 수 있습니다.
FragmentActivity부터 OnRequestPermissionsResultCallback이 구현되어있으며, 일반적으로 FragmentActivity를 상속한 AppcompatActivity를 사용하신다면 onRequestPermissionsResult 콜백 이벤트를 받을 수 있습니다.
콜백 파라미터
requestCode : 권한 요청시 쓰인 requestCode가 들어오입니다. 어디서 언제 요청했는지를 이 코드로 구분할 수 있습니다.
permissions : 요청했던 권한 목록
grantResults : 권한 여부 목록
permissions 와 grantResults에서 같은 인덱스로 참조하면서 권한이 허가 되었는지 여부를 확인할 수 있습니다.
소스 코드 전문
class MainActivity:AppCompatActivity(){
//요청하고 싶은 권한들을 String 타입의 배열로 선언
private val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
//요청 코드 선언
private val REQUEST_PERMISSION_CODE = 0
//Rx이용시 메모리 누수 방지를 위한 Disposable
private val disposalBag = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
reqPermissions(this, getPermissionList(permissions))
}
//권한 목록을 Single<List<String>>로 변환
private fun getPermissionList(permissions:Array<String>): Single<List<String>> {
return permissions.toObservable()
.filter { permission ->
PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(this, permission)
}.toList()
}
private fun reqPermissions(activity: Activity, list: Single<List<String>>) {
val disposal = list.subscribe { list ->
if (list.isNotEmpty()) {
ActivityCompat.requestPermissions(activity, list.toTypedArray(), REQUEST_PERMISSION_CODE)
} else {
//이미 이전에 권한을 획득했음.
}
}
disposalBag.add(disposal)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_PERMISSION_CODE) {
val disposal = Observables.zip(permissions.toObservable(), grantResults.toObservable())
.all {
it.second == PackageManager.PERMISSION_GRANTED
}.subscribe { t1: Boolean, t2: Throwable? ->
if (t2 != null || !t1) {
//권한 획득 못함
} else {
//권한 획득
}
}
disposalBag.add(disposal)
}
}
//메모리 누수 방지
override fun onDestroy() {
super.onDestroy()
disposalBag.dispose()
}
}
0개의 댓글