728x90
AccountManager
- 안드로이드 기기의 '설정 > 계정 및 백업 > 계정 관리'에 들어가보면 여러 앱에서 로그인한 계정이 등록된것을 확인할 수 있는데 이 계정 목록에 접근하거나 계정을 추가하는 작업을 도와주는 것이 AccountManager 입니다.
- AccountManager를 사용해 자신의 앱에서 사용할 '맞춤 계정 유형(Account Type)'을 생성하고 이를 통해 계정 목록에서 '계정 유형'에 해당하는 계정을 불러올 수 있습니다.
- AccountManager는 암호화 서비스나 키체인이 아니고 개발자가 전달한 사용자 인증 정보를 '일반 텍스트로 저장'합니다.
- 루트에서만 액세스 가능한 데이터베이스에 저장하기 때문에 대부분의 기기에서는 특별히 우려할 사안은 아님
- 단, 루팅된 기기에서는 adb 권한이 있는 누구나 사용자 정보를 읽을 수 있음
- 예제 프로젝트
- 기본적인 주석은 다 추가했습니다.
- https://github.com/JhDroid/accountmanager-sample.git
AccountManager 계정 추가하기
- 사용자 계정 추가를 위한 권한 추가
<!--맞춤 사용자 유형 추가를 위한 권한-->
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
- AccountManager 객체 생성 및 사용자 계정 추가 함수 생성
- 예제에서는 AccountManager 객체를 관리할 object 클래스를 생성해서 사용했습니다.
object AccountHelper {
private var accountManager: AccountManager? = null
/**
* AccountManager에 계정 이름을 쿼리할 때 계정 유형별로 필터링 가능
* 계정 유형은 계정을 발급한 주체를 고유하게 식별하는 문자열
* Google의 계정 유형은 'com.google', Twitter의 계정 유형은 'com.twitter.android.auht.login'
* */
private const val MY_ACCOUNT_TYPE = "com.jhdroid.auth.login"
fun initAccountManager(context: Context) {
accountManager = AccountManager.get(context)
}
fun getAccountManager(): AccountManager? = accountManager
// 사용자 계정 추가 함수
fun addAccount(id: String, pw: String) {
Account(id, MY_ACCOUNT_TYPE).also { account ->
accountManager?.addAccountExplicitly(account, pw, null)
}
}
}
- 맞춤 계정 유형은 자신의 앱에서 추가한 계정을 불러오기 위한 'Key' 역할을 합니다.
- AccountManager 클래스의 addAccountExplicitly() 함수를 통해 계정 추가가 가능합니다.
- id, pw는 사용자로 부터 입력받아야 하며 입력을 받기위한 로그인 화면이 필요합니다.
- 로그인 화면 만들기
- 로그인 화면은 간단하게 EditText 2개와 버튼 하나로만 구성했습니다.
- 예제 프로젝트이기 때문에 계정 정보를 따로 암호화하지는 않지만 계정 정보는 암호화해서 등록하는 것을 추천드립니다.
class AuthenticatorActivity : AppCompatActivity() {
private val binding by lazy { ActivityLoginBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.loginSubmitBtn.setOnClickListener {
val accountId = binding.loginIdEdt.text.toString()
val accountPw = binding.loginPwEdt.text.toString()
// 사용자 계정 추가
AccountHelper.addAccount(accountId, accountPw)
setResult(RESULT_OK)
finish()
}
}
}
- AbstractAccountAuthenticator 확장 및 addAccount() 추상 메소드 구현
class Authenticator(
private val context: Context
): AbstractAccountAuthenticator(context) {
/**
* '설정 > 계정 및 백업 > 계정 관리 > 계정 추가'에서 자신의 앱을 선택하면 KEY_INTENT로 넘겨주는 Intent를 실행해줌
* 보통은 인증 정보를 받기위해 로그인 화면으로 이동시킨다. (ex: 네이버, 페이코)
* */
override fun addAccount(
response: AccountAuthenticatorResponse,
accountType: String,
accountTokenType: String,
requiredFeatures: Array<out String>,
options: Bundle
): Bundle {
Timber.d("addAccount()")
val intent = Intent(context, AuthenticatorActivity::class.java).apply {
putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType)
putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
}
return Bundle().also {
it.putParcelable(AccountManager.KEY_INTENT, intent)
}
}
...
}
- 인증자 서비스 생성
/**
* 인증자 서비스
* 인증자는 여러 애플리케이션에서 사용할 수 있어야 하고 백그라운드에서 작동해야 하므로 Service내에서 실행해야 하며 이를 '인증자 서비스'라고 함
* 인증자 서비스는 AbstractAccountAuthenticator를 확장한 클래스(Authenticator)의 getIBinder()를 리턴해주면 된다.
* */
class AuthenticatorService : Service() {
override fun onBind(intent: Intent?): IBinder? {
val authenticator = Authenticator(this)
return authenticator.iBinder
}
}
- 계정 목록에서 자신의 앱을 나타낼 리소스 생성
- 해당 목록에서 자신의 앱을 나타내기 위한 아이콘과 앱 이름을 설정해 줘야 합니다.
- 리소스 폴더에 'xml' 폴더를 생성하고 'authenticator.xml' 파일을 생성합니다.(이름은 상관 없습니다.)
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/account_type"
android:icon="@mipmap/ic_launcher"
android:smallIcon="@mipmap/ic_launcher"
android:label="@string/account_label" />
- accountType : 자신의 앱에서 사용하는 맞춤 계정 유형
- icon, smallIcon : 자신의 앱을 나타내는 아이콘
- label : 자신의 앱 이름
- 계정 추가 및 확인
계정 정보 불러오기
- 위에서 추가한 계정 정보를 불러오는 방법을 알아보겠습니다.
- 계정 목록을 불러오기 위한 권한 추가
<!--기기의 계정 목록을 가져오기 위한 권한-->
<uses-permission android:name="android.permission.GET_ACCOUNTS"
android:maxSdkVersion="22" />
- 계정 목록 반환 함수 추가
- 위에서 추가한 object 클래스(AccountHelper)에 계정 목록을 불러오는 함수 추가
- AccountManager의 getAccountsByType(<AccountType>) 함수와 getAccounts() 함수로 계정 목록을 불러올 수 있습니다.
private const val MY_ACCOUNT_TYPE = "com.jhdroid.auth.login"
/**
* 사용자 계정 목록을 가져옴
* 해당 API에서 개인 정보 및 민감한 사용자 데이터를 반환하므로 이를 사용자에게 명확하게 공개해야함
* @Account Account 객체 자체는 데이터를 보호하지 않으며 사용자 계정 이름 이외의 다른 항목에 액세스할 권한을 부여하지 않음
* */
fun getMyAccounts(): Array<out Account>? = accountManager?.getAccountsByType(MY_ACCOUNT_TYPE)
/**
* 접근 가능한 모든 계정 목록을 불러옴
* */
fun getAccounts(): Array<out Account>? = accountManager?.accounts
- 반환된 계정 정보 확인
- 계정 정보는 'Account' 객체로 확인 가능합니다.
- Account 클래스는 name과 type으로만 이루어진 간단한 데이터 클래스입니다.
- name은 계정을 등록할 때 ID이고 type도 authenticator.xml에서 등록한 accountType 입니다.
- MainActivity에 버튼을 추가하고 textView에 계정 정보를 출력해서 확인해봅니다.
binding.mainMyAccountBtn.setOnClickListener {
AccountHelper.getMyAccounts().takeIf { !it.isNullOrEmpty() }?.forEach { account ->
appendLog("name : ${account.name}\ntype : ${account.type}")
} ?: appendLog("계정 정보 없음")
}
private fun appendLog(msg: String) {
binding.mainAccountInfoTv.append("$msg\n\n")
}
기타
- 계정 비밀번호 확인
- 비밀번호는 AccountManager의 getPassword() 함수로 확인 가능합니다.
fun getPassword(account: Account?): String? {
return try {
accountManager?.getPassword(account)
} catch (e: Exception) {
""
}
}
다음 글은 AccountManager를 사용해 토큰을 관리하는 예제 입니다.
* 글에 틀린 부분이 있으면 댓글 부탁드립니다 :D
728x90
'개발 > Android' 카테고리의 다른 글
[Android] RecyclerView 키보드 스크롤 처리 - 카톡과 비슷한 스크롤 처리 (2) | 2021.11.29 |
---|---|
[Android] FragmentDirections 클래스가 생성되지 않을 때 (0) | 2021.04.09 |
[Android] MVVM + Navigation Graph 사용 시 프래그먼트 이동 처리 방법 (0) | 2021.04.09 |
[Android] BottomNavigationView 선택되지 않은 메뉴의 라벨이 보이지 않을 때 (0) | 2021.04.03 |
[Android] 클래시 오브 클랜 맵(배치) 복사 앱을 만드는 방법 (0) | 2021.01.25 |