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개의 댓글