2026/03/29

오늘의 이야기



#스치니1000프로젝트 #재미 #행운기원 #Compose #Firebase

🎯 야 너 토요일마다 로또 확인하냐?
나도 맨날 "혹시나~" 하면서 봤거든 ㅋㅋ

근데 이제는 그냥 안 해
AI한테 맡겼어 🤖✨

그것도 구글 Gemini로다가!

그래서 앱 하나 만들었지
👉 "로또 예상번호 by Gemini" 🎱

AI가 분석해서 번호 딱! 뽑아줌
그냥 보고 참고만 하면 됨

재미로 해도 좋고…
혹시 모르는 거잖아? 😏


https://play.google.com/store/apps/details?id=com.billcorea.gptlotto1127




오늘의 이야기

Android Studio Koala | 2023.3.2 Canary 2
Build #AI-233.14475.28.2332.11606850, built on March 21, 2024
Runtime version: 17.0.10+0--11572160 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 11.0
GC: G1 Young Generation, G1 Old Generation
Memory: 5120M
Cores: 8
Registry:
  ide.instant.shutdown=false
  ide.experimental.ui=true
Non-Bundled Plugins:
  wu.seal.tool.jsontokotlin (3.7.4)
  idea.plugin.protoeditor (233.13135.65)
  lermitage.intellij.battery.status (2.3.1)
  com.developerphil.adbidea (1.6.15)


 


새로운 버전이 release 되었습니다. 


 


koala release



 


Build a Generative AI app using the Gemini API template 

Gemini API 템플릿을 사용하여 Generative AI 앱 구축


 


You can now use Android Studio to build an app that implements Generative AI using the Google AI SDK. The Gemini API template in Android Studio lets you incorporate AI-powered features, such as those that rely on text generation and image recognition, in your app to delight your users.


 


이제 Android Studio를 사용하여 Google AI SDK를 사용하여 Generative AI를 구현하는 앱을 빌드할 수 있습니다. Android Studio의 Gemini API 템플릿을 사용하면 텍스트 생성 및 이미지 인식에 의존하는 기능과 같은 AI 기반 기능을 앱에 통합하여 사용자를 즐겁게 할 수 있습니다.


 


https://developer.android.com/studio/preview/gemini-template?hl=en



 


Android 스튜디오에서 첫 번째 생성형 AI 앱 빌드하기  |  Android Studio  |  Android Developers


Android 스튜디오의 새 템플릿을 사용하여 생성형 AI 앱을 실행하세요.


developer.android.com




 


Launch Android Studio in Safe Mode

안전 모드에서 Android Studio 실행


 


Android Studio offers the ability to launch Android Studio in Safe Mode. This mode can be useful if you run into a situation where certain features don't work or the entire IDE fails to launch. Using Safe Mode temporarily returns the IDE to a set of default configurations that might allow it to launch, so that you can troubleshoot from there to identify the issue and restore functionality.


 


Android Studio는 안전 모드에서 Android Studio를 실행하는 기능을 제공합니다. 이 모드는 특정 기능이 작동하지 않거나 전체 IDE가 실행되지 않는 상황에 처했을 때 유용할 수 있습니다. 안전 모드를 사용하면 IDE가 실행을 허용할 수 있는 일련의 기본 구성으로 일시적으로 돌아가므로 거기서부터 문제를 해결하여 문제를 식별하고 기능을 복원할 수 있습니다.


 


https://developer.android.com/studio/preview/features?hl=en#safe-mode



 


Android 스튜디오 미리보기의 새로운 기능  |  Android Studio  |  Android Developers


Android 스튜디오 미리보기의 새로운 기능을 확인하세요.


developer.android.com




이상으로 새로운 릴리즈에 대한 이야기를 번역해 보았습니다.


 


 


 


 


 





오늘의 이야기


#스하리1000명프로젝트

스치니들!
내가 만든 이 앱은, 내 폰에 오는 알림 중에서 중요한 키워드가 있는 경우
등록해둔 친구에게 자동으로 전달해주는 앱이야 📲

예를 들어, 카드 결제 알림을 와이프나 자녀에게 보내주거나
이번 달 지출을 달력처럼 확인할 수도 있어!

앱을 함께 쓰려면 친구도 설치 & 로그인해줘야 해.
그래야 친구 목록에서 서로 선택할 수 있으니까~
서로 써보고 불편한 점 있으면 알려줘 🙏

👉 https://play.google.com/store/apps/details?id=com.nari.notify2kakao





오늘의 이야기

 앱을 만들고 playstore에 등록을 하고, firebase에 등록을 해야 하다 보면 singing report을 통해서 SHA-1 SHA-256 값들을 구해야 하는 경우가 생기게 됩니다. 


 


안정화된 버전의 android studio 의 경우는 다를 수 도 있겠으나,  Canary 버전을 사용하고 있는 지금은  기본 Setting으로는 그것을 보여 주지 않도록 하고 있는 것으로 보입니다. 


 


--- Android Studio 버전 정보 ---


Android Studio Jellyfish | 2023.3.1 Canary 13
Build #AI-233.14475.28.2331.11543046, built on March 7, 2024
Runtime version: 17.0.10+0--11446219 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 11.0
GC: G1 Young Generation, G1 Old Generation
Memory: 5120M
Cores: 8
Registry:
  ide.instant.shutdown=false
  ide.experimental.ui=true
Non-Bundled Plugins:
  wu.seal.tool.jsontokotlin (3.7.4)
  lermitage.intellij.battery.status (2.3.1)
  com.developerphil.adbidea (1.6.13)


 


 화면 오른쪽 상단에 있는 코끼리 버튼을 클릭 하여 gradle 창을 열어 보면 이렇게 보여서 혹시 당황스럽더라도...


 




 


 


다음과 같이 해 보세요... 먼저 설정 (Setting)을 들어가 봅니다.    아래 그림 처럼  되는  Gradle에 체크되지 않은 옵션 2개가 보입니다. 그걸 2개다 일단 체크합니다.




 


 


다음은 File 메뉴에서 Sync Project with Gradle Files을 선택하여 Gradle을 다시 실행합니다. 


 




 


 


시간이 좀 흐른 다음... 다시 Gradle 창을 들어가 보면  아래 그림처럼 android 탭이 생기고 그 안에 signing report 가 보입니다.  이제 그걸 더블 클릭하고 실행하게 되면  singing report 가 출력 되는 것을 볼 수 있습니다. 


 




 


 


이제 그 안에서 SHA-1 값을 찾아 사용해 볼 수 있습니다.  다만 그것은 debug 모드에서 사용할 수 있는 내용이고요. release key에 해당하는 값을 구하는 방법은  다음 그림과 같이 터미널 창에서 입력해 실행해 보세요.


 




 


마지막에 있는 파일 이름은 release 할 때 사용하는 key 파일 이름입니다. 


 


이상으로 오늘 이야기를 마무리하겠습니다.   이렇게 정리를 두는 것도... 다 나중에 다시 보기 위해서.... 오늘도 파이팅입니다.





오늘의 이야기

https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127&pli=1



 


옵데강 (제주맛집 리스트 모아보기) - Google Play 앱


인터넷에 널린(?) 제주 맛집 정보를 모아 봅니다.


play.google.com




 


조금은 허접한(?) 앱 이기는 합니다만... 그래도 나름 재미있는 프로젝트 이기는 합니다.   이 앱을 구동하기 위해서는 


1. python 을 이용한 앱 스크래핑을 해야 합니다. 


2. firebase RealtimeDatabase에 저장을 해야 합니다.


3. android 앱이 realtime database 의 정보를 수신해 보여주는 기능을 구현해야 합니다.


4. 덤으로 제주버스정보을 API 호출을 통해 수신하고 관리합니다.


5. 앱에서는 구글 지도를 이용해 해당 정보를 표시해 줄 수 있어야 합니다.


 


이걸 하기 위해서는 24시간 구동이 가능한 서버 구성이 필요하기도 합니다. python을 24시간 구동하는 방법으로는 Google Cloud Function을 이용할 수 도 있겠지만, 시간 단위로 트리거를 해야 하는 등등 절차가 필요합니다.  그래서 현재는 raspberry pi 4를 이용해서 집에서 구동해 보고 있습니다.


 


그럼 오늘의 이야기는  python으로 주소 정보를 수집하는 것에 대한 이야기를 적어 보겠습니다.


 


 


import urllib
import requests
from bs4 import BeautifulSoup

searchKey = '제주맛집'
for idx in range(1, 100):
print(idx)
url = "https://search.daum.net/search?w=fusion&nil_search=btn&DA=STC&q={0}&p={1}&col=blog".format(
urllib.parse.quote_plus(searchKey), idx)
response = requests.get(url, verify=True)
# print(response.text)
bs = BeautifulSoup(response.text, 'html.parser')
# print(bs)
# print('---------------------------------------------------------------------------------------------')
for item in bs.find_all('c-menu-share'):
print(item['data-link'])

 


다음 포털의 검색을 위해서 '제주맛집'이라는 검색을 입력해 보면 위 URL을 통해서 검색된 정보를 노출하고 있는 것을 알 수 있었습니다.   html을 파싱 하기 위해서 BeautifulSoup을 이용해 보았습니다. 


 


이제 결과를 통해서 제주맛집으로 검색되는 블로그의 URL 임을 확인해 볼 수 있었습니다.


 


실행 결과



 


다음은 저 URL을 읽어서 해당 페이지의 html을 읽어 보도록 하겠습니다.


 


def parseText(baseUrl):
try:
response = requests.get(baseUrl, verify=True)
bs = BeautifulSoup(response.text, 'html.parser')
text1 = ''
if 'blog.naver' in baseUrl:
iframexx = bs.find_all('iframe')
for iframe in iframexx:
res = requests.get('https://blog.naver.com/' + iframe.attrs['src'])
bs = BeautifulSoup(res.text, 'html.parser')
text1 = re.sub('(<([^>]+)>)', '', bs.get_text())
else:
text1 = re.sub('(<([^>]+)>)', '', bs.get_text())

 


 


html 에서 text 만 html tag 을 다 제거한 경우의 결과값



 


이렇게 해서 블로그 페이지에서 text 만 추출하는 작업을 해 보았습니다.   


 


이제 오늘 해 보고 싶었던 이야기... 저 글에서 추출해 보고 싶은 정보인  블로그 안에서 찾을 수 있는 맛집 정보를 GEMINI AI을 활용해서 추출하는 프롬프트를 작성해 보겠습니다. 


 


def getGeminiResponse(text):
# Or use `os.getenv('GOOGLE_API_KEY')` to fetch an environment variable.
GOOGLE_API_KEY = 'AIz....................TQ3A'
genai.configure(api_key=GOOGLE_API_KEY)
prompt = '''
From now on, you will be analyzing sentences and finding addresses in South Korea within them.
You will also be tasked with finding out the name of the store located at that address.
Are you familiar with the address format in Korea?
The address will be written separately into street number address and road name address.
Although it is not possible to know which address is contained in the following sentence,
you will be able to find it well.
And find a phone number or cell phone number where you can be contacted.

The response format is
"상호: Company name or Business name, 주소: Korean address, 전화: Phone Number or Telephone Number"

The answer must always be in Korean.
Now, find the address and business name and phone number or telephone number in the next sentence and let me know.
{0}
'''.format(text)

model = genai.GenerativeModel(model_name='gemini-pro',
generation_config = generation_config,
safety_settings = safety_settings)
response = model.generate_content(prompt)
return response.text

 


나름 한글로 정리한 요건을 영문으로 번역해 프롬프트를 만들어 보았습니다. 아직 한글로 요청하면 이해도가 떨어지기 때문이기 때문입니다.   아직 까지는 비용 발생 없이 잘 활용하고 있습니다. 


 


이 코드들을 잘 활용한 결과를 만들어야 할 텐데... 걱정입니다.   현재 운영 중이 앱은 xml layout으로 구현되어 앱을 수정해야 할 필요성을 느끼고 있어서(?) 수정 작업을 해 볼 예정입니다. 


 


다음 이야기는 정리가 되면 다시 적어 보겠습니다.


 


 





오늘의 이야기


#스하리1000명프로젝트,
Soms is het moeilijk om met buitenlandse werknemers te praten, toch?
Ik heb een eenvoudige app gemaakt die helpt! Jij schrijft in jouw taal, en anderen zien het in hun taal.
Het vertaalt automatisch op basis van instellingen.
Superhandig voor makkelijke chats. Neem eens een kijkje als je de kans krijgt!
https://play.google.com/store/apps/details?id=com.billcoreatech.multichat416




오늘의 이야기

오늘은 android build 방법은 gradle plugin의 새 버전 일 때 만나는 오류 메시지 하나에 대한  이야기를 적어 봅니다. 


 


이전까지 정상적으로 잘 빌드 되었던 프로젝트 이기는 하나... 어느 순간에 이런 오류가 발생됩니다. ㅠㅠ ;;


 


Manifest merger failed : Attribute property#android.adservices.AD_SERVICES_CONFIG@resource value=(@xml/ga_ad_services_config) from [cohttp://m.google.android.gms:play-services-measurement-api:21.5.1] AndroidManifest.xml:32:13-58
is also present at [cohttp://m.google.android.gms:play-services-ads-lite:22.6.0] AndroidManifest.xml:92:13-59 value=(@xml/gma_ad_services_config).
Suggestion: add 'tools:replace="android:resource"' to <property> element at AndroidManifest.xml to override.


 


build 오류가 나왔습니다.



 


구글링을 통해서 검색을 해 보면 나오는 문제 해소 하는 방법을 참고 하여 수정해 봅니다. 수정할 부분은  manifest.xml 에 


property을 추가하면 된다는 이야기를 찾을 수 있었습니다. 그래서 다음과 같이 manifest을 수정했습니다. 


 


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_opdigang_v1"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_opdigang_v1_round"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_config"
android:theme="@style/Theme.OpdGang1127">

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/API_KEY" />

<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="@string/APP_ID"/>

<activity
android:name=".MapsActivity"
android:exported="false"
android:label="@string/title_activity_maps" />
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustNothing">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<property
android:name="android.adservices.AD_SERVICES_CONFIG"
android:resource="@xml/gma_ad_services_config"
tools:replace="android:resource" />

</application>

</manifest>

 


이제 다시 빌드를 시도해 봅니다. 


 


새로 빌드한 결과



 


이상 입니다.  깔끔하죠???





오늘의 이야기

private lateinit var audioManager: AudioManager

...

    audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
    val targetVolume = 0
    audioManager.setStreamVolume(AudioManager.STREAM_ALARM, targetVolume, AudioManager.FLAG_PLAY_SOUND)
    audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, targetVolume, AudioManager.FLAG_PLAY_SOUND)
    audioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, targetVolume, AudioManager.FLAG_PLAY_SOUND)
    audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, targetVolume, AudioManager.FLAG_PLAY_SOUND)
    audioManager.setStreamVolume(AudioManager.STREAM_RING, targetVolume, AudioManager.FLAG_PLAY_SOUND)
    audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, targetVolume, AudioManager.FLAG_PLAY_SOUND)

 
오늘은 오디오 매니저를 이용해 기기의 볼륨을 한 번에 꺼 보도록 하겠습니다. 
 

볼륨이 다 줄어 들었어요


 
그런데... 통화 볼륨은 왜??? 
 
그건 아직 잘 모르겠네요. ㅋㅋㅋ  다음에 또 알게 되면 적어 보겠습니다.
 





오늘의 이야기


#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




오늘의 이야기

Raspberry Pi에 Python을 설치해 보고 있습니다. 
 
https://github.com/tvdsluijs/sh-python-installer

GitHub - tvdsluijs/sh-python-installer: General easy to use Raspberry Pi & Ubuntu Python installer

General easy to use Raspberry Pi & Ubuntu Python installer - tvdsluijs/sh-python-installer

github.com

 
그러던 와중에 한줄 코멘드를 이용해서 설치할 수 있는 방법을 찾게 되어 기록해 둘까 합니다.  이걸 하는 이유는 다음에  또 포스팅해 볼까 합니다. 
 

 wget -qO - https://raw.githubusercontent.com/tvdsluijs/sh-python-installer/main/python.sh | sudo bash -s [python_version]

 
위 코멘트에서 python_version 에 들어갈 버전 코드는 다음 링크에서 찾아서 적어 주시면 됩니다. 
 
https://www.python.org/ftp/python/

Index of /ftp/python/

www.python.org

 
사용하고 싶은 버전을 선택 해서 실행해 주시면 됩니다.   raspberry pi 4를 사용하고 있기는 하지만 CPU 성능 등이 있기 때문에 설치 시간은 오래 걸리네요.  아무튼 설치가 진행되면 어떻게 되는지는 설치가 완료되면 다시 적어 보겠습니다.
 

설치중


 
 

설치 완료


 





오늘의 이야기

# Gemini API Key 

import google.generativeai as genai

GOOGLE_API_KEY='AIza*********************************PU'
genai.configure(api_key=GOOGLE_API_KEY)

# for m in genai.list_models():
# if 'generateContent' in m.supported_generation_methods:
# print(m.name)

model = genai.GenerativeModel('gemini-pro')
prompt = '''
You are a competent translator. Please convert the following English words. The next word is {0}.
The country codes that need to be converted are 'ar', bn', 'cn','de','es','fr','hi','in','it','ja','ko','ms',' nl','pt','ru','th','tr','vi','zh'
Please indicate how to print in the format 'Country Code: Converted Word'.
'''.format('Written By')
response = model.generate_content(prompt)
print(response.text)

 


안드로이드 앱을 구현하는 동안 다국어 버전을 만들기 위해서는 번역을 해야 하는 경우가 발생하게 됩니다.  그래서 이번에는 GEMINI API을 활용해서 간단한 번역기(?)를 만들어 보려고 합니다. 


 


번역 예시



 


GEMINI API 관련된 여러글에서 강조했던 것처럼 prompt을 어떻게 작성하는 가에 따라서 달라질 수 있습니다.  예시 코드의 prompt는 간략하게 만들어 본 것이기는 합니다. 또한 AI의 단점은 간혹 거짓말(?)을 할 수 있기도 합니다. 이런 부분만을 유의해서 잘 활용해 보면 좋을 것 같습니다. 


 


예전에 했던 Translate API 을 활용했던 것보다 훨씬 단순하게 번역을 해 볼 수 있었습니다.  이제 다국어 버전의 앱을 조금은 더 쉽게 만들어 보도록 하겠습니다.


 





오늘의 이야기

#스치니1000프로젝트 #재미 #행운기원 #Compose #Firebase 🎯 야 너 토요일마다 로또 확인하냐? 나도 맨날 "혹시나~" 하면서 봤거든 ㅋㅋ 근데 이제는 그냥 안 해 AI한테 맡겼어 🤖✨ 그것도 구글 Gemini로다...