
오월이 끝나갈 때쯤... 이제 유월이 소리도 없이 다가오려고 한다. 길가에 장미는 왜 이러도 많은 지...
계절의 여왕이라는 오월을 보내며... 난 또 새로운 계절 맞이 준비를 해야 할 것 같다.
장미의 이쁜 얼굴 아래 가려진 가시에 내 손이 상처를 입지 않도록 조심조심... 오늘도 난 내 길을 가려한다.
오늘도 잘 살았으니, 파이팅...

오월이 끝나갈 때쯤... 이제 유월이 소리도 없이 다가오려고 한다. 길가에 장미는 왜 이러도 많은 지...
계절의 여왕이라는 오월을 보내며... 난 또 새로운 계절 맞이 준비를 해야 할 것 같다.
장미의 이쁜 얼굴 아래 가려진 가시에 내 손이 상처를 입지 않도록 조심조심... 오늘도 난 내 길을 가려한다.
오늘도 잘 살았으니, 파이팅...
https://medium.com/@cybercoder.naj/compose-navigation-in-3-minutes-5cff3c57c34e
Compose Navigation in 3 Minutes
Quick guide for navigation between composables in a Compose project
medium.com
나름대로 이제 배움을 정리해 가고 있기는 하나, 아직도 갈 길이 멀어 보이기는 하다.
오늘은 navigation 을 구현해 볼 준비를 해야 겠다. 이글을 읽어 보면서 말이다.
이전 posting 에서 구현해 보려고 했던 것들은 아직 미 완성인지라, 글로 옮겨 오기에는 무리가 있어 보인다.
잘 읽어 보고 오늘도 도전 !!!
2022.05.28 코딩으로 옮겨 보면서...
implementation "androidx.navigation:navigation-compose:2.5.0-rc01"gradle 파일에 추가는 그대로 따라해 본다. 다만, 버전이 달라졌다.
먼저 NavigationItem class 는 그대로 따라서 만들어 보았다. 다만, 다른 건 title 을 다국어로 사용하기 위해서
values/string.xml 에 등록된 것을 사용하기 위해서 R.string.이름을 적용했다는 것이다.
sealed class NavigationItem(var route: String, var icon: Int, var title: Int) {
object Chats : NavigationItem("Chats", R.drawable.ic_baseline_chat_24, R.string.titleChatRoom)
object Profile : NavigationItem("Profile", R.drawable.ic_baseline_person_24, R.string.profileImage)
object Menus : NavigationItem("Menus", R.drawable.ic_baseline_menu_24, R.string.title_activity_setting)
}
이제 Mainactivity 에서 구성을 해 보겠다. 일단 onCreate 에 navController 을 선언하고 화면 하단에 appbar 을 설정해 보았다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fontFamily = FontFamily(Font(R.font.poorstory_regular, FontWeight.Normal))
setContent {
val navController = rememberNavController()
MultiChat416Theme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Scaffold(
bottomBar = {
BottomNavigationBar(navController)
}
) { innerPadding ->
var paddingValues = innerPadding
Navigation(navController)
}
}
}
}
}
Navigation 의 구현은 아래와 같이 했는데, NavigationItem 의 route 도 string 으로 구현 되어 있으니, 그것을 이용해 아래와 같이 구현 했다. navigation 이 찾아갈때, route 을 이용해서 찾아가니, 위치에 따라 잘 구현을 해야 한다.
그리고 아래 부분에는 navigation button 을 클릭 했을 때에 따라서 화면에 표시 하는 부분은 그대로 따라하기를 하였으며
title 의 표시 부분만 일부 수정을 해 보았다.
navigation 을 클릭했을 때 동작은 아래 보이는 Navigation 함수에서 처리를 하면 된다.
@Composable
fun Navigation(navController: NavHostController) {
NavHost(navController = navController, startDestination = NavigationItem.Chats.route) {
composable(route = NavigationItem.Chats.route) {
HomeScreen(navController)
}
composable(route = NavigationItem.Profile.route) {
Home2Screen(navController)
}
composable(route = NavigationItem.Menus.route) {
SecondScreen(navController, "Test...")
}
}
}
@Composable
fun BottomNavigationBar(navController: NavHostController) {
val items = listOf(
NavigationItem.Chats,
NavigationItem.Profile,
NavigationItem.Menus
)
BottomNavigation(
backgroundColor = colorResource(id = R.color.softBlue),
contentColor = Color.White
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
var context = LocalContext.current
items.forEach { item ->
BottomNavigationItem(
icon = { Icon(painterResource(id = item.icon), contentDescription = context.getString(item.title)) },
label = { Text(text = context.getString(item.title)) },
selectedContentColor = Color.White,
unselectedContentColor = Color.White.copy(0.4f),
alwaysShowLabel = true,
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route) {
saveState = true
}
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}

구현이 끝난 화면의 예시는 위 그림과 같다. 이제 그 부분에 기능을 구현해 보면 될 것 같다.

점심을 먹고 나서면 이제 제법 낮볓이 뜨겁다. 청사가 가까이에 있어 주변에 조성된 숲길(?)이 이제 제법 시원하게 느껴 지기도 한다. 점심을 먹고 나면 잠깐 낮잠이 오히려 필요한 것 같은 요즘이기는 하나, 갈수록 무거워지는 몸을 지탱하기 위해 오늘도 길을 나섰다. 그래봐야 이제 두달을 조금 넘겨가고 있는 것 같으나, 무거워져 가는 몸뚱이는 변함이 없다.
크~ 오늘 저녁에도 회식이라는 핑계(?)로 마음을 추스리며 한가득 뱃속을 채우고 돌아 왔으니, 가벼워지길 바라는 것은 아무래도...
내일도 난 나의 몸이 가벼워지길 바라며, 길을 나서겠지만... 언제쯤 일까 ? 아직 잘 알 수는 없다.
https://itnext.io/a-comprehensive-guide-to-android-12s-splash-screen-api-644609c811fa
A Comprehensive Guide to Android 12's Splash Screen API
For years Android Devs have always resorted to using a windowBackground or Activity or Fragment for their splash screen. Using the…
itnext.io
스플래쉬 화면 : 앱이 실행 되기 전에 로딩중 보이는 화면 ( 앱이 처리 되는 동안 보이는 progressbar 와는 다른 ...)
오늘은 인터넷에서 퍼온 글 하나를 올려 본다.
요새 배우는중인 jetpack compose 통해서 화면 작업을 해 보고 있는데, splash 화면 만드는 가이드가 나와 있어서 퍼 왔다.
시간이 생기면 작업중인 앱에 적용을 해 보아야 겠다.

일상이 풍요로운 건 아무래도 길가에 핀 꽃들 때문이지 않나 싶다. 여름이 성금더 가까이에 와 있음을 느끼는 오후, 갑천을 따라 걸었다. 가는 길도 멀기도 했고, 오느길도 아득 하기만 했는데, 보라색 아지랭이가 있어 길을 멈추었다.
5월의 따뜻한(?) 햇살을 받으며 피어오르는 아지랭이는 ... 이름도 모르는 들꽃 ... 나만 모르는 건가 ?
그건 뭐 알 수는 없으나, 길가에서 만난 들꽃은 나름의 피로를 날려 버리게 하고, 오늘도 잘 살았으니, 내일도 화이팅 해 보자고...
https://billcorea.tistory.com/198
안드로이드 앱 만들기 : 코드 난독화, 축소의 폐해(?)
https://developer.android.com/studio/build/shrink-code.html?hl=ko#kts 앱 축소, 난독화 및 최적화 | Android 개발자 | Android Developers 사용하지 않는 코드와 리소스를 삭제하기 위해 출시 빌드에서 코..
billcorea.tistory.com
이전에 posting 했던 글처럼, 코드 난독화를 설정하고 릴리즈를 했을 때 발생했던 상황이 정리가 되어, 그 정리 방안을 기록해 두어야겠다.
먼저 gradle 파일에 코드 난독화 설정 하기에 예외 처리 등록하는 방법은 다음과 같이 설정하면 된다.
gradle 파일의 설정
buildTypes {
debug {
buildConfigField "Boolean", "DEBUG_MODE", "true"
}
release {
buildConfigField "Boolean", "DEBUG_MODE", "false"
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}빌드 타입에 따라서 debug 모드에서는 빌드 되는 시간을 절약하기 위해서 설정을 넣지 않았고, release 모드에서 설정이 되도록 추가하였다.
다음은 proguade-rules.pro 파일에 설정을 추가 하였다.
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# Add this global rule
-keepattributes Signature
# This rule will properly ProGuard all the model classes in
# the package com.yourcompany.models.
# Modify this rule to fit the structure of your app.
-keep public class com.bill...........databean.** { *; }-keep public class 뒤에 따라오는 건 내 project 의 package 이름의 경로라고 보면 된다. databean 아래에 있는 모든 class는 난독화를 하지 않겠다고 하는 것이다.

코드 난독화가 된 이후에도 database 구조는 구현된 이름 그대로 저장 되어 있는 것을 볼 수 있었다. 이것으로 난독화를 했을 때 야기될 수 있는 문제점에 대한 이해와 그 해결에 대한 정리를 마무리해 두어야겠다.
https://developers.google.com/identity/one-tap/android/get-saved-credentials#disable-one-tap
저장된 자격 증명으로 사용자 로그인 | One Tap for Android | Google Developers
경고 : 이 데이터는 Google 사용자 데이터 정책에 따라 제공됩니다. 정책을 검토하고 준수하십시오. 그렇게하지 않으면 프로젝트가 정지되거나 계정이 정지 될 수 있습니다. 이 페이지는 Cloud Transl
developers.google.com
16: Caller has been temporarily blocked due to too many canceled sign-in prompts. 이런 오류 메시지을 만나게 되면
당황스럽지 않을까 ? 구글에서 찾아보니 이런 해결책이 있었다. 나의 경우는
참고 : 개발 과정이 24 시간 재사용 대기 기간이 발생하는 경우, 당신은 구글 플레이 서비스 '응용 프로그램 저장을 취소하여 재사용 대기 시간을 초기화 할 수 있습니다. 또한, 테스트 장치에이 재사용 대기 시간 ON / OFF 전환 및 / 또는 에뮬레이터 모두, 단순히 걸기 응용 프로그램 입력에 다음 코드를 이동 : *#*#66382723#*#* . 제출 시 피드백은 없지만 다이얼러는 모든 입력을 지우고 닫힐 수 있습니다. 이 후에는 쿨다운을 해제해야 합니다. 다시 켜려면 같은 코드를 다시 입력하세요.
이런 가이드를 따라 하는 것으로 해결이 완결 되었다.
이 페이지는 다음 주소 검색 페이지를 호출하는 테스트 페이지 입니다. 이 페이지에는 아무것도 없습니다. 숨어 있는 script 가 있습니다. https://billcorea.tistory.com/215 안드로이드 앱 만들기 : 주소 검색을 위...