개발자 모드가 필요한 이유
개발자 모드를 통해서 서버 모드(상용, QA, Test)를 앱 내에서 변경할 수도 있고, 에러 발생 시 로그를 기록해줄 수도 있습니다.
또한 토큰 정보나 디바이스 정보 등과 같이 개발 및 테스트에 필요한 정보들을 바로 확인할 수 있게 됩니다.
프로젝트 특성에 따라 테스트를 위한 여러 기능들을 추가할 수도 있습니다.
이처럼 개발자 모드를 이용하면 다른 파트와의 협업 및 오류 추적, 테스트 등이 용이해집니다.
개발자 모드에 필요한 항목
- 사용자 정보
- 계정 정보
- Access Token
- Refresh Token
- FCM Token
- AD_ID
- 디바이스 정보
- 안드로이드 버전
- 모델 명
- 기기 이름
- 기기 uuid
- 앱 버전
- 화면 비율
- 해상도
- 가로 너비
- 리소스 버킷 (ex: xxxhdpi)
- 서버 Url 변경
개발자 모드를 추가할 때 일반적으로 들어갈 수 있는 항목들은 위와 같습니다.
예시로 추려낸 목록이므로 프로젝트 특성에 맞게 필요한 항목을 골라서 넣어주면 좋을 것 같습니다.
PreferencesFragment를 이용한 화면 구성
먼저 개발자 모드를 만들 때 사용되는 PreferencesFragment에 대해서 간단하게 정리할텐데, 이미 알고 있는 내용이라면 다음 게시물을 참고하면 좋을 것 같습니다.
개발자 모드는 일반적으로 PreferencesFragment를 이용하는 경우가 많은 것 같습니다.
간단한 정보들을 표기하기에 좋고, 관리도 편하기 때문입니다. 물론 프로젝트의 디자인에 맞게 일반 Fragment로도 구성을 할 수 있으니 팀 스타일에 맞게 적용하시면 됩니다.
태그 소개
카테고리 구분
<PreferenceCategory> 태그를 이용하여 카테고리를 만들 수 있습니다.
<PreferenceCategory
android:title="서버 모드 설정"
app:iconSpaceReserved="false">
/*...*/
</PreferenceCategory>
텍스트 메뉴
텍스트를 가지는 일반적인 메뉴입니다.
Title (제목)과 Summary (내용)으로 나뉩니다.
<Preference
android:key="dev_pref_key_normal_menu"
android:title="title 값"
app:iconSpaceReserved="false" />
리스트 메뉴
클릭 시 여러 아이템을 리스트로 보여줄 수 있고, 라디오 버튼으로 선택 가능합니다.
<ListPreference
android:defaultValue="0"
android:key="dev_pref_key_api_mode"
android:title="서버 모드 설정"
app:iconSpaceReserved="false" />
체크박스 메뉴
체크박스를 포함한 메뉴도 추가 가능합니다.
<CheckBoxPreference
android:key="dev_pref_key_mmt_fake_server"
android:title="모멘토 내부 파일 로드"
app:iconSpaceReserved="false" />
입력 필드 메뉴
메뉴를 클릭하면 EditText를 통해 값을 변경할 수도 있습니다.
<EditTextPreference
android:key="dev_pref_key_log_db_end"
android:title="종료 기준"
app:iconSpaceReserved="false" />
사용 예시
텍스트 메뉴에 값을 할당할 때, 저는 아래와 같이 메소드를 만들어 사용하고 있습니다.
private fun setPreferenceSummary(key: String, value: String) {
findPreference<Preference>(key)?.let { pref ->
pref.summary = value
pref.setOnPreferenceClickListener {
copyToText(value)
}
}
}
setPreferenceSummary("dev_pref_key_access_token", accessToken)
setPreferenceSummary("dev_pref_key_refresh_token", refreshToken)
이런식으로 간단하게 값을 할당해줄 수 있으며, 텍스트 메뉴는 기본적으로 클릭 시 복사되도록 하였습니다.
> 클립보드 코드
private fun copyToText(text: String): Boolean {
val clipData = ClipData.newPlainText(CLIPBOARD_LABEL, text)
clipboardManager?.setPrimaryClip(clipData)
context?.let {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
RunnectToast.createToast(it, getString(R.string.dev_mode_copy_to_text)).show()
}
}
return true
}
안드로이드 12 이하에서는 클립보드 복사 시 자동으로 토스트 메세지가 출력되지 않습니다.
토스트 메세지 출력 시 버전 분기 처리가 필요합니다.
화면 실행 방법
일반적인 화면과 크게 다르지 않습니다.
Activity, Fragment를 만들고 onCreatePreferences 메소드를 오버라이드 합니다.
해당 메소드 내에서 setPreferencesFromResource 메소드를 통해 화면을 불러올 수 있습니다.
Fragment는 일반 Fragment가 아닌 PreferenceFragmentCompat()을 사용합니다.
(PreferenceFragment를 사용하는 경우에만 해당 됩니다. 일반 Fragment로 개발자 모드를 구성한다면 기존과 동일하게 작성해주면 됩니다.)
class DeveloperActivity : AppCompatActivity(R.layout.activity_developer_main) {
class DeveloperFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
}
}
AndroidrManifest.xml
저는 Scheme을 통해 개발자 모드를 실행할 것이므로 아래와 같이 activity 내에 intent-filter와 scheme, host 명을 추가 해주었습니다.
<activity
android:name=".developer.RunnectDeveloperActivity"
android:exported="true"
android:label="개발자 모드"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:host="devmode"
android:scheme="runnect"/>
</intent-filter>
</activity>
이렇게 하면 아래와 같이 Scheme으로 실행 가능합니다.
Fragment만 만들고 일반 Fragment 처럼 실행할 수도 있습니다.
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("runnect://devmode")
startActivity(intent)
전체 코드
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:title="사용자 정보"
app:iconSpaceReserved="false">
<Preference
android:key="dev_pref_key_access_token"
android:title="엑세스 토큰"
app:iconSpaceReserved="false" />
<Preference
android:key="dev_pref_key_refresh_token"
android:title="리프레시 토큰"
app:iconSpaceReserved="false" />
</PreferenceCategory>
<PreferenceCategory
android:title="디바이스 정보"
app:iconSpaceReserved="false">
<Preference
android:key="dev_pref_android_version"
android:title="안드로이드 버전"
app:iconSpaceReserved="false" />
<Preference
android:key="dev_pref_sdk_version"
android:title="SDK 버전"
app:iconSpaceReserved="false"/>
<Preference
android:key="dev_pref_model_name"
android:title="모델 명"
app:iconSpaceReserved="false" />
</PreferenceCategory>
</PreferenceScreen>
디버그 모드용 패키지 만들기
개발자 모드에는 민감한 정보가 들어가게 되므로 일반 사용자에게 노출되는 것은 위험할 수 있습니다.
상용 앱에서 메뉴가 노출되지 않아야하는 것은 당연하지만 코드조차 노출되지 않는 것이 좋습니다.
이를 위해 debug 모드에서만 보이는 패키지를 추가하여 해당 패키지 내에 코드를 넣어주면 됩니다.
Project 모드로 변경
안드로이드 스튜디오의 패키지 모드를 Project로 변경하면 debug [main]과 main이 보입니다.
선언된 build variants마다 main 패키지가 존재하니 원하는 패키지를 선택하면 됩니다.
debug[main] 우클릭 > New > Directory > java 를 먼저 추가해 줍니다.
추가된 java 패키지 내에 developer 패키지를 추가 해주면 됩니다.
디버그 용 AndroidManifest.xml 추가
DeveloperActivity를 추가해주기 위해 Debug 패키지에도 AndroidManifest.xml 을 추가합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".application.ApplicationClass"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_runnect_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_runnect_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Runnect"
android:usesCleartextTraffic="true"
tools:targetApi="tiramisu">
<activity
android:name=".developer.RunnectDeveloperActivity"
android:exported="true"
android:label="개발자 모드"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="devmode"
android:scheme="runnect" />
</intent-filter>
</activity>
</application>
</manifest>
빌드 가능하게 설정
혹시나 AndroidManifest.xml (debug)를 추가한 후 빌드가 되지 않는다면 build.gradle(app)에서 android 블록 내에 아래의 코드를 추가해주세요
packagingOptions {
exclude 'AndroidManifest.xml'
}
여기까지 간단하게 개발자 모드를 추가하는 방법을 작성해보았습니다.
다음 게시글엔 좀 더 구체적으로 필요한 정보를 넣는 방법에 대해서 작성 해두었으니 참고 부탁드립니다.
'안드로이드 > 이론' 카테고리의 다른 글
[ 안드로이드 ] 앱 내에 개발자 모드 추가하기 2 (0) | 2023.12.29 |
---|---|
[ 안드로이드 ] 개발자의 실수를 줄여주는 어노테이션 (0) | 2023.12.12 |
[ 안드로이드 ] style.xml을 이용하여 공통 속성 정의하기 (0) | 2023.10.10 |
[ 안드로이드 ] View에 블러처리 하기 - BlurView 라이브러리 (0) | 2023.09.17 |
[ 안드로이드 ] Fragment에서 onBackPressed(뒤로가기 이벤트) 처리하기 (0) | 2023.09.09 |