Skip to content

Instantly share code, notes, and snippets.

@pennya
Created December 11, 2018 08:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pennya/5b77a1bd2c99e73bad0b6d8d32f817e1 to your computer and use it in GitHub Desktop.
Save pennya/5b77a1bd2c99e73bad0b6d8d32f817e1 to your computer and use it in GitHub Desktop.
안드로이드 런타임 퍼미션

액티비티마다 런타임 퍼미션을 구현하는 것이 너무 번거롭기 때문에 빌더패턴 형태로 액티비티마다 런타임 퍼미션을 적용하는 라이브러리

TedPermission 참고(https://github.com/ParkSangGwon/TedPermission), 코드를 분석하여 필요한 부분만 가져다가 적용중

  1. 런타임 퍼미션 클래스(MyPermission.kt), 투명한 창을 가진 액티비티 생성(MyPermissionActivity.kt, AppCompatActivity 상속)
  2. AndroidManifest에 투명한 창을 가진 액티비티 추가
  3. styles.xml에 아래와같이 투명한 창을 만드는 스타일 생성
<style name="Theme.Transparent.Permission" parent="Theme.AppCompat.Light.NoActionBar"> true @android:color/transparent @null true false false true true false </style>
  1. AndroidManifest에 스타일 추가
class DuziPermission(private val context: Context) {
private lateinit var listener: PermissionListener
private lateinit var permissions: Array<String>
private lateinit var rationaleTitle: CharSequence
private lateinit var rationaleMessage: CharSequence
private lateinit var denyTitle: CharSequence
private lateinit var denyMessage: CharSequence
private var requestedOrientation: Int = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED // 시스템이 화면 모드를 정함
fun setPermissionListener(listener: PermissionListener): DuziPermission {
this.listener = listener
return this
}
fun setRationaleTitle(stringRes: Int): DuziPermission {
rationaleTitle = getText(stringRes)
return this
}
fun setRationaleMessage(stringRes: Int): DuziPermission {
rationaleMessage = getText(stringRes)
return this
}
fun setDeniedTitle(stringRes: Int): DuziPermission {
denyTitle = getText(stringRes)
return this
}
fun setDeniedMessage(stringRes: Int): DuziPermission {
denyMessage = getText(stringRes)
return this
}
fun setScreenOrientation(requestedOrientation: Int): DuziPermission {
this.requestedOrientation = requestedOrientation
return this
}
fun setPermissions(vararg permissions: String): DuziPermission {
this.permissions = permissions.asList().toTypedArray()
return this
}
fun checkPermissions() {
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
listener.onPermissionGranted()
return
}
Intent(context, DuziPermissionActivity::class.java).apply {
putExtra(EXTRA_PERMISSIONS, permissions)
putExtra(EXTRA_RATIONALE_TITLE, rationaleTitle)
putExtra(EXTRA_RATIONALE_MESSAGE, rationaleMessage)
putExtra(EXTRA_DENY_TITLE, denyTitle)
putExtra(EXTRA_DENY_MESSAGE, denyMessage)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) //새로운 테스크를 만들고 그 테스크에 액티비티를 추가한다.
addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION) //onUserLeaveHint 호출되지 않게
DuziPermissionActivity.startActivity(context, this, listener)
}
}
private fun getText(stringRes: Int): CharSequence {
if(stringRes <= 0) {
throw IllegalArgumentException("Invalid String resource id")
}
return context.getText(stringRes)
}
companion object {
private var INSTANCE: DuziPermission? = null
fun with(context: Context): DuziPermission =
INSTANCE ?: synchronized(DuziPermission::class.java) {
INSTANCE ?: DuziPermission(context).also { INSTANCE = it }
}
}
interface PermissionListener {
fun onPermissionGranted()
fun onPermissionDenied(deniedPermission: List<String>)
}
}
class DuziPermissionActivity: AppCompatActivity() {
private lateinit var permissions: Array<String>
private lateinit var rationaleTitle: CharSequence
private lateinit var rationaleMessage: CharSequence
private lateinit var denyTitle: CharSequence
private lateinit var denyMessage: CharSequence
private var orientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
override fun onCreate(savedInstanceState: Bundle?) {
overridePendingTransition(0, 0) //startActivity 또는 finish 이후에 호출해야됨. 애니메이션 적용
super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) // 잠시 원하는 시간에 터치가 안되도록
with(intent) {
permissions = getStringArrayExtra(EXTRA_PERMISSIONS)
rationaleTitle = getCharSequenceExtra(EXTRA_RATIONALE_TITLE)
rationaleMessage = getCharSequenceExtra(EXTRA_RATIONALE_MESSAGE)
denyTitle = getCharSequenceExtra(EXTRA_DENY_TITLE)
denyMessage = getCharSequenceExtra(EXTRA_DENY_MESSAGE)
orientation = getIntExtra(EXTRA_SCREEN_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
}
if(!isGranted(this, permissions)) {
checkPermissions()
} else {
listener?.onPermissionGranted()
finish()
overridePendingTransition(0, 0)
}
requestedOrientation = orientation
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when(requestCode) {
REQ_CODE_PERMISSION_REQUEST -> {
if(grantResults.isNotEmpty()) {
listener?.onPermissionGranted()
finish()
overridePendingTransition(0, 0)
}
}
}
}
override fun onDestroy() {
super.onDestroy()
overridePendingTransition(0, 0)
}
private fun checkPermissions() {
ActivityCompat.requestPermissions(this, permissions, REQ_CODE_PERMISSION_REQUEST)
}
private fun isGranted(context: Context, permissions: Array<String>): Boolean {
for(permission in permissions) {
if(!isGranted(context, permission)) {
return false
}
}
return true
}
private fun isGranted(context: Context, permission: String): Boolean =
ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
private fun canRequestPermission(activity: Activity, permissions: Array<String>) {
for(permission in permissions) {
if(ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
}
}
}
companion object {
fun startActivity(context: Context, intent: Intent, listener: DuziPermission.PermissionListener) {
this.listener = listener
context.startActivity(intent)
}
private var listener: DuziPermission.PermissionListener? = null
val EXTRA_PERMISSIONS = "permissions"
val EXTRA_RATIONALE_TITLE = "rationale_title"
val EXTRA_RATIONALE_MESSAGE = "rationale_message"
val EXTRA_DENY_TITLE = "deny_title"
val EXTRA_DENY_MESSAGE = "deny_message"
val EXTRA_SCREEN_ORIENTATION = "screen_orientation"
val REQ_CODE_PERMISSION_REQUEST = 1000
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val permissionlistener = object: DuziPermission.PermissionListener {
override fun onPermissionGranted() {
Toast.makeText(this@MainActivity, "permission granted", Toast.LENGTH_SHORT).show()
}
override fun onPermissionDenied(deniedPermission: List<String>) {
}
}
DuziPermission.with(this)
.setPermissionListener(permissionlistener)
.setRationaleTitle(R.string.app_name)
.setRationaleMessage(R.string.app_name)
.setDeniedTitle(R.string.app_name)
.setDeniedMessage(R.string.app_name)
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.setPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION)
.checkPermissions()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment