billcorea.com
빌코리아의 홈페이지 입니다.
2026/06/29
오늘의 이야기
#스치니1000프로젝트 #재미 #행운기원 #Compose #Firebase
🎯 야 너 토요일마다 로또 확인하냐?
나도 맨날 “혹시나~” 하면서 봤거든 ㅋㅋ
근데 이제는 그냥 안 해
AI한테 맡겼어 🤖✨
그것도 구글 Gemini로다가!
그래서 앱 하나 만들었지
👉 “로또 예상번호 by Gemini” 🎱
AI가 분석해서 번호 딱! 뽑아줌
그냥 보고 참고만 하면 됨
재미로 해도 좋고…
혹시 모르는 거잖아? 😏
https://play.google.com/store/apps/details?id=com.billcorea.gptlotto1127
오늘의 이야기
#billcorea #운동동아리관리앱
🏸 Schneedle, een onmisbare app voor badmintonclubs!
👉 Matchplay - Registreer scores en vind tegenstanders 🎉
Perfect voor overal, alleen, met vrienden of in een club! 🤝
Als je van badminton houdt, probeer het dan zeker
Ga naar appen 👉 https://play.google.com/store/apps/details?id=com.billcorea.matchplay
오늘의 이야기
#스하리1000명프로젝트
오늘 내가 만든앱 하나 알려주고 싶어, 이 앱은 알림수집기 라고 이름을 붙였는 데,
내 폰에 표시 되는 알림을 읽어서 내가 지정한 단어가 들어 있고, 지출기록을 남겨야 하는 알림이
있으면 수집하고, 카카오톡으로 친구에게 전달해 주는 기능을 구현해 줄꺼야. 📲
이번 패치에서는 하루 한번 지정한 시간에 나에게 알림(노티) 하도록 기능을 추가 했어. 🙏
한번 써보고 불편한 거 있으면 말해줘.
앱 바로가기
👉 https://play.google.com/store/apps/details?id=com.nari.notify2kakao
오늘의 이야기
오늘은
우편번호 검색 페이지 무한정 호출해 보기 예제 수정편 입니다.
일상적인 업무에서 주소 검색은 언제든 진행 되어야 합니다. 다만, API 을 사용하게 되면 역시나, 비용 발생이 되는 관계로
다가 무한정 호출 가능한 우편번호/주소 검색 기능을 구현하기 위해... 카카오가 제공하는 주소 검색 스크립트을 이용하는 방법을
정리해 보려고 합니다.
예전 버전을 적용해 사용했던 기억이 있지만, 현재는 해당 기능도 업데이트 되어 수정이 필요 했습니다.
https://postcode.map.kakao.com/guide
Kakao 우편번호 서비스
우편번호 검색과 도로명 주소 입력 기능을 너무 간단하게 적용할 수 있는 방법. Kakao 우편번호 서비스를 이용해보세요. 어느 사이트에서나 무료로 제약없이 사용 가능하답니다.
postcode.map.kakao.com
위 페이지에 기술된 내용을 참고 했습니다.
아래 스크립트 부분은 blogger.com 의 페이지에서 사용할 수 있게 추가한 부분 입니다. html 코드을 지원하는 블로그 페이지는 어디든 지원이 될 것으로 판단 됩니다.
<!--카카오 우편번호 서비스 불러오기-->
<script src="//t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<!--주소검색 버튼과 결과 표시 영역-->
<button onclick="execDaumPostcode()">주소 검색</button>
<div id="result"></div>
<script>
function execDaumPostcode() {
new kakao.Postcode({
oncomplete: function(data) {
// 선택된 주소 정보 표시
const roadAddr = data.roadAddress; // 도로명 주소
const jibunAddr = data.jibunAddress; // 지번 주소
const zonecode = data.zonecode; // 우편번호
const address = data.roadAddress || data.address ;
document.getElementById("result").innerHTML =
"<p><b>도로명 주소:</b> " + roadAddr + "</p>" +
"<p><b>지번 주소:</b> " + jibunAddr + "</p>" +
"<p><b>우편번호:</b> " + zonecode + "</p>";
// 이 부분은 안드로이드 에서 참조 하도록 하기 위함이라 web 에서는 에러 발생됨
window.Android.processDATA(address)
}
}).open();
}
</script>
아래 코드는 kotlin 코드로 작성된 주소 검색 페이지 activity 입니다. 이 페이지의 기능은 주소검색 script 을 androidview 로 호출하고, 결과을 받아 원래 호출 했던 위치로 return 해 주는 기능만 존재 합니다.
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.os.Message
import android.net.Uri
import android.webkit.JavascriptInterface
import android.webkit.WebChromeClient
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import androidx.compose.ui.viewinterop.AndroidView
import com.billcoreatech.multichat416.R
import com.billcoreatech.multichat416.ui.theme.Multichat416Theme
import com.billcoreatech.multichat416.ui.theme.appColorScheme
import com.billcoreatech.multichat416.ui.theme.appTypography
class AddressFindActivity : ComponentActivity() {
inner class MyJavaScriptInterface {
@JavascriptInterface
fun processDATA(data: String?) {
returnAddress(data)
}
@JavascriptInterface
fun postMessage(data: String?) {
returnAddress(data)
}
}
fun returnAddress(data: String?) {
Log.e("TAG", "returnAddress ${data}")
val intent = Intent()
intent.putExtra("data", data)
setResult(AppCompatActivity.RESULT_OK, intent)
finish()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Multichat416Theme(dynamicColor = true) {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
) {
Scaffold(
modifier = Modifier
.fillMaxSize()
.padding(top = 20.dp), topBar = {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(5.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = {
Log.e("", "backArrow")
finish()
}) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = "Close"
)
}
Spacer(modifier = Modifier.padding(5.dp))
Text(
text = stringResource(R.string.foundAddress),
color = appColorScheme.primary,
lineHeight = 1.33.em,
style = appTypography.titleLarge,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(align = Alignment.CenterVertically)
)
}
}, bottomBar = {
}
) { innerPadding ->
Column(modifier = Modifier.padding(innerPadding).fillMaxSize()) {
WebViewForAddress(this@AddressFindActivity,
doFinish = {
val intent = Intent()
setResult(AppCompatActivity.RESULT_CANCELED, intent)
finish()
},
)
}
}
}
}
}
}
}
@SuppressLint("JavascriptInterface", "SetJavaScriptEnabled")
@Composable
fun WebViewForAddress(addressFindActivity: AddressFindActivity, doFinish:() -> Unit) {
val blogspot = "https://billcoreatech.blogspot.com/2026/06/blog-post_480.html"; // "https://billcoreatech.blogspot.com/2022/06/blog-post.html"
var webViewContainer by remember { mutableStateOf<FrameLayout?>(null) }
var mainWebView by remember { mutableStateOf<WebView?>(null) }
var webView by remember { mutableStateOf<WebView?>(null) }
var canGoBack by remember { mutableStateOf(false) }
var isPostcodeRequested by remember { mutableStateOf(false) }
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { context ->
val container = FrameLayout(context)
webViewContainer = container
fun WebView.configureForAddressSearch() {
settings.run {
javaScriptEnabled = true
domStorageEnabled = true
javaScriptCanOpenWindowsAutomatically = true
setSupportMultipleWindows(true)
}
val javascriptInterface = addressFindActivity.MyJavaScriptInterface()
addJavascriptInterface(javascriptInterface, "Android")
addJavascriptInterface(javascriptInterface, "android")
addJavascriptInterface(javascriptInterface, "ReactNativeWebView")
webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView,
request: WebResourceRequest
): Boolean {
return handleAddressCallbackUrl(
url = request.url,
addressFindActivity = addressFindActivity
)
}
override fun onPageFinished(view: WebView, url: String?) {
canGoBack = view.canGoBack()
if (!isPostcodeRequested) {
isPostcodeRequested = true
view.evaluateJavascript("execDaumPostcode();", null)
}
}
}
webChromeClient = object : WebChromeClient() {
override fun onCreateWindow(
view: WebView,
isDialog: Boolean,
isUserGesture: Boolean,
resultMsg: Message
): Boolean {
val popupWebView = WebView(view.context).apply {
configureForAddressSearch()
webChromeClient = object : WebChromeClient() {
override fun onCloseWindow(window: WebView) {
container.removeView(window)
window.destroy()
webView = view
canGoBack = view.canGoBack()
}
}
}
container.addView(
popupWebView,
FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
)
webView = popupWebView
val transport = resultMsg.obj as WebView.WebViewTransport
transport.webView = popupWebView
resultMsg.sendToTarget()
return true
}
}
}
WebView(context).apply {
configureForAddressSearch()
loadUrl(blogspot, emptyMap())
mainWebView = this
webView = this
container.addView(
this,
FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
)
}
container
},
update = {
canGoBack = webView?.canGoBack() == true
},
)
BackHandler(enabled = true) {
val view = webView
if (view != null && canGoBack) {
view.goBack()
} else if (view != null && view !== mainWebView) {
webViewContainer?.removeView(view)
view.destroy()
webView = mainWebView
canGoBack = mainWebView?.canGoBack() == true
} else {
doFinish()
}
}
DisposableEffect(Unit) {
onDispose {
webViewContainer?.let { container ->
for (index in container.childCount - 1 downTo 0) {
(container.getChildAt(index) as? WebView)?.destroy()
}
container.removeAllViews()
}
mainWebView = null
webView = null
webViewContainer = null
}
}
}
private fun handleAddressCallbackUrl(
url: Uri,
addressFindActivity: AddressFindActivity
): Boolean {
if (url.scheme != "multichat416" || url.host != "address") {
return false
}
val data = url.getQueryParameter("data").orEmpty()
addressFindActivity.returnAddress(data)
return true
}
코드 사용 예제는 훗날 추가해 보겠습니다. 개발을 마무리 하고 나서.
오늘의 이야기
#스하리1000명프로젝트,
แพ้เกาหลีเหรอ? แม้ว่าคุณจะพูดภาษาเกาหลีไม่ได้ แต่แอปนี้จะช่วยให้คุณเดินทางได้อย่างง่ายดาย
เพียงพูดภาษาของคุณ ระบบจะแปล ค้นหา และแสดงผลลัพธ์เป็นภาษาของคุณ
เหมาะสำหรับนักเดินทาง! รองรับมากกว่า 10 ภาษา รวมถึงภาษาอังกฤษ ญี่ปุ่น จีน เวียดนาม และอื่นๆ อีกมากมาย
ลองตอนนี้!
https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127
2026/06/28
오늘의 이야기
#스치니1000프로젝트 #재미 #행운기원 #Compose #Firebase
🎯 야 너 토요일마다 로또 확인하냐?
나도 맨날 “혹시나~” 하면서 봤거든 ㅋㅋ
근데 이제는 그냥 안 해
AI한테 맡겼어 🤖✨
그것도 구글 Gemini로다가!
그래서 앱 하나 만들었지
👉 “로또 예상번호 by Gemini” 🎱
AI가 분석해서 번호 딱! 뽑아줌
그냥 보고 참고만 하면 됨
재미로 해도 좋고…
혹시 모르는 거잖아? 😏
https://play.google.com/store/apps/details?id=com.billcorea.gptlotto1127
오늘의 이야기
#스하리1000명프로젝트
오늘 내가 만든앱 하나 알려주고 싶어, 이 앱은 알림수집기 라고 이름을 붙였는 데,
내 폰에 표시 되는 알림을 읽어서 내가 지정한 단어가 들어 있고, 지출기록을 남겨야 하는 알림이
있으면 수집하고, 카카오톡으로 친구에게 전달해 주는 기능을 구현해 줄꺼야. 📲
이번 패치에서는 하루 한번 지정한 시간에 나에게 알림(노티) 하도록 기능을 추가 했어. 🙏
한번 써보고 불편한 거 있으면 말해줘.
앱 바로가기
👉 https://play.google.com/store/apps/details?id=com.nari.notify2kakao
오늘의 이야기
#스하리1000명프로젝트,
Kadang-kadang susah nak bercakap dengan pekerja asing kan?
Saya membuat aplikasi mudah yang membantu! Anda menulis dalam bahasa anda, dan orang lain melihatnya dalam bahasa mereka.
Ia auto-terjemah berdasarkan tetapan.
Sangat berguna untuk sembang mudah. Lihatlah apabila anda mendapat peluang!
https://play.google.com/store/apps/details?id=com.billcoreatech.multichat416
오늘의 이야기
#스하리1000명프로젝트,
Bị lạc ở Hàn Quốc? Ngay cả khi bạn không nói được tiếng Hàn, ứng dụng này vẫn giúp bạn đi lại dễ dàng.
Chỉ cần nói ngôn ngữ của bạn—nó sẽ dịch, tìm kiếm và hiển thị kết quả bằng ngôn ngữ của bạn.
Tuyệt vời cho du khách! Hỗ trợ hơn 10 ngôn ngữ bao gồm tiếng Anh, tiếng Nhật, tiếng Trung, tiếng Việt, v.v.
Hãy thử nó ngay bây giờ!
https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127
2026/06/27
오늘의 이야기
#스치니1000프로젝트 #재미 #행운기원 #Compose #Firebase
🎯 야 너 토요일마다 로또 확인하냐?
나도 맨날 “혹시나~” 하면서 봤거든 ㅋㅋ
근데 이제는 그냥 안 해
AI한테 맡겼어 🤖✨
그것도 구글 Gemini로다가!
그래서 앱 하나 만들었지
👉 “로또 예상번호 by Gemini” 🎱
AI가 분석해서 번호 딱! 뽑아줌
그냥 보고 참고만 하면 됨
재미로 해도 좋고…
혹시 모르는 거잖아? 😏
https://play.google.com/store/apps/details?id=com.billcorea.gptlotto1127
오늘의 이야기
#스치니1000프로젝트 #재미 #행운기원 #Compose #Firebase 🎯 야 너 토요일마다 로또 확인하냐? 나도 맨날 “혹시나~” 하면서 봤거든 ㅋㅋ 근데 이제는 그냥 안 해 AI한테 맡겼어 🤖✨ 그것도 구글 Gemini로다가! ...