구글 ai studio 코드로 만든 웹앱을 안드로이드 패키징하기
1. tailwindcss 설치
npm install -D tailwindcss postcss autoprefixer
2. 프로덕션 빌드 및 테스트
# 개발 모드
npm run dev
# 프로덕션 빌드
npm run build
# 빌드 결과 미리보기
npm run preview
- 빌드 시 에러 발생 대응 내역 (또는 사전 확인 점검)
[vite:terser] terser not found
Terser를 설치해야 함.
npm install -D terser
혹은 아래 파일 수정해서 terser 대신 esbuild 사용을 권함.
vite.config.ts
build: {
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'ui-vendor': ['lucide-react'],
}
}
},
sourcemap: false,
minify: 'esbuild', // terser 대신 esbuild
terser 와 esbuild 비교 (압축률 속도 비교)
| esbuild | 95% | ⚡⚡⚡ 초고속 | ✅ |
| terser | 100% | 🐌 느림 | ⚠️ |
3. 성능 최적화 체크리스트
1) pwa 설정 / 전체화면 웹앱을 위한 플러그인
설치 및 초기화
npm install -D vite-plugin-pwa
vite.config.ts 코드 (pwa 부분 추가 최종본)
import path from 'path';
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, '.', '');
return {
server: {
port: 3000,
host: '0.0.0.0',
},
define: {
'process.env.API_KEY': JSON.stringify(env.VITE_GEMINI_API_KEY),
'process.env.GEMINI_API_KEY': JSON.stringify(env.VITE_GEMINI_API_KEY)
},
plugins: [
react(),
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: 'Age of Hundred',
short_name: '백살까지',
description: '100세까지 남은 시간을 추적하는 앱',
theme_color: '#000000',
background_color: '#000000',
display: 'standalone',
icons: [
{
src: 'icon-192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'icon-512.png',
sizes: '512x512',
type: 'image/png'
}
]
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365 // 1년
}
}
}
]
}
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, '.'),
}
},
build: {
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'ui-vendor': ['lucide-react'],
}
}
},
sourcemap: false,
minify: 'esbuild',
}
};
});
2) tailwindcss 설정 / CSS를 위한 라이브러리
tailwind v3 설치 및 초기화
npm install -D tailwindcss@3 postcss autoprefixer
npx tailwindcss init -p
tailwind.config.js 코드
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./index.tsx",
"./App.tsx",
"./components/**/*.{ts,tsx}",
"./types.ts",
"./translations.ts",
"./audioEngine.ts",
"./googleDriveService.ts",
],
theme: {
extend: {
fontFamily: {
'sans': ['Noto Sans KR', 'sans-serif'],
'serif': ['Maru Buri', 'serif'],
'condensed': ['Oswald', 'sans-serif'],
'lexend': ['Lexend', 'sans-serif'],
},
animation: {
'pulse': 'pulse var(--pulse-duration, 2s) cubic-bezier(0.4, 0, 0.6, 1) infinite',
},
},
},
plugins: [],
}
3) 기타 파일 추가
postcss.config.js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
body {
@apply font-sans bg-black text-white overflow-hidden m-0;
letter-spacing: -0.02em;
}
}
@layer components {
.font-serif {
font-family: 'Maru Buri', serif;
}
.font-condensed {
font-family: 'Oswald', sans-serif;
text-transform: uppercase;
}
.font-lexend {
font-family: 'Lexend', sans-serif;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
}
@layer utilities {
/* Custom scrollbar */
::-webkit-scrollbar {
width: 4px;
}
::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.05);
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 10px;
}
}
.gitignore 업데이트
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Environment variables
.env
.env.local
.env.production
.env.*.local
# Android
android/
ios/
package.json 업데이트
{
"name": "age-of-hundred",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
"react": "^19.2.3",
"react-dom": "^19.2.3",
"lucide-react": "^0.562.0",
"@google/genai": "^1.34.0"
},
"devDependencies": {
"@types/node": "^22.14.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@vitejs/plugin-react": "^5.0.0",
"typescript": "~5.8.2",
"vite": "^6.2.0",
"tailwindcss": "^3.4.0",
"postcss": "^8.4.0",
"autoprefixer": "^10.4.0",
"terser": "^5.36.0"
}
}
4. Capacitor로 안드로이드 앱 변환
1) capacitor 설치
npm install @capacitor/core @capacitor/cli
npm install @capacitor/android
2) 초기화
npx cap init "Age of Hundred" "com.plizm.ageofhundred" --web-dir=dist
3) 빌드
npm run build
4) 안드로드 추가
npx cap add android
5) 동기화
npx cap sync
5. 안드로이드에서 오픈
1) device Mangager /
- 우측에 하나 있으면 ,play 버튼

Sync tool 관련 다운로드가 실행된다.
- 우측에는 에뮬레이터가 실행됨

완료되면 상단 play 버튼이 활성화 된다.

짜란 이렇게 우측 에뮬레이터에 앱 화면이 뜬다.

기능 테스트 성공.

2. 폰 연결 및 테스트
1) 설정 / 개발자옵션 / USB 디버깅 옵션 활성화 ( 폰 - PC 연결)

상단에서 기기를 선택하고, Play 버튼 클릭

실제로 화면에서는 가로폭 숫자가 커지면 짤리는 문제
위아래 폭도 조금 문제가 있고,
글자 폰트도 좀 더 커진 것 같다. 우측 화면줄이는 아이콘도 없애야겠고,
중앙 숫자에는 clamp()가 적용되어있는데, 이것이 안드로이드에서 작동안하는 것 같음.
Tailwind 반응형 클래스 사용으로 바꿔줌.
하지만 역시나 적용이 안됨.
ai studio에서 최종적으로 안드로이드 패키징 시에 문제가 없도록 아래 프롬프트를 실행
'안드로이드 디바이스에서 빌드 후 발생할 수 있는 문제점을 미리 체크해두자.'

AI 답변
안드로이드 패키징(PWA 또는 WebView) 시 발생할 수 있는 주요 기술적 호스트 이슈들을 점검하고, 이를 해결하기 위한 최종 보완 작업을 수행하겠습니다.
(i) 업데이트 및 보완 사항
- 시스템 폰트 스케일링 완전 방어:
- index.html에 -webkit-text-size-adjust: none을 추가하여 안드로이드 설정의 "글자 크기" 옵션이 레이아웃을 무너뜨리지 않도록 강제합니다.
- 모바일 터치 최적화:
- touch-action: none과 manipulation을 적절히 배치하여 더블 탭 확대 기능을 끄고, 스와이프(단위 변경) 감도를 안정화합니다.
- 뷰포트 및 세이프 에어리어(Safe Area) 강화:
- viewport-fit=cover 설정을 유지하며, 안드로이드 상단 노치와 하단 내비게이션 바 영역(env(safe-area-inset-*))이 모든 인터페이스 요소에 정확히 반영되도록 레이아웃 클래스를 점검합니다.
- 오디오 컨텍스트 활성화 로직:
- 안드로이드 크롬 기반 환경에서 오디오는 반드시 사용자 상호작용 후 시작되어야 합니다. SplashScreen에서 Enter 클릭 시 AudioContext를 미리 재개(resume)하는 코드를 보강합니다.
(ii) 동작 및 시각적 변화
- 텍스트 안정성: 시스템 폰트가 크더라도 타이머 숫자가 화면 밖으로 삐져나가지 않고 정해진 비율을 유지합니다.
- 부드러운 스크롤/스와이프: 스와이프 시 발생하는 모바일 특유의 바운스 효과나 확대/축소 간섭이 사라져 네이티브 앱 같은 조작감을 제공합니다.
- 풀스크린 최적화: 하단 바와 노치 영역에 텍스트가 겹치지 않도록 세이프 마진이 엄격하게 적용됩니다.
이렇게 다시 ai studio로 돌아가 최종적인 수정을 마쳤다.
그리고 다시 새로 다운로드 하고,
다시 아래 과정을 반복하여 빌드 테스트에 성공!
안드로이드 빌드 테스트 요약
새로운 폴더를 불러온다는 전제하에 (모든 것은 cmd 모드에서 실행할 것)
파일은 제 프로젝트에 한하여 참고했던 전체 ai답변 내용임. by claude
주요 내용은 아래의 과정임.
1. tailwind 3.0 을 설치한다. 초기화한다.
npm install -D tailwindcss@3 postcss autoprefixer
npx tailwindcss init -p
2. 로컬 웹브라우저에서 확인한다.
npm run dev
3. 안드로이드 패키지 빌드한다.
1) pwa 플러그인 설치 (전체화면을 위해 사용한 플러그인)
npm install -D vite-plugin-pwa
2) capacitor 설치 및 초기화, 빌드, 안드로이드 추가, 동기화 (안드로이드 변환을 위한 장치)
# Capacitor 설치
npm install @capacitor/core @capacitor/cli
npm install @capacitor/android
# 초기화
npx cap init "Age of Hundred" "com.plizm.ageofhundred" --web-dir=dist
# 빌드
npm run build
# Android 추가
npx cap add android
# 동기화
npx cap sync
# Android Studio 열기
npx cap open android
폰 USB 연결 테스트 완료
'AI.' 카테고리의 다른 글
| 구글 ai studio 코드 다운로드 후, 로컬 브라우저에 띄우기 (0) | 2025.12.26 |
|---|---|
| 업비트 거래 자동화 AI 만들기 4편 (4) | 2024.10.29 |
| 업비트 거래 자동화 AI 만들기 3편 (5) | 2024.10.29 |
| 업비트 거래 자동화 AI 만들기 2편 (7) | 2024.10.28 |
| 업비트 거래 자동화 AI 만들기 1편 (5) | 2024.10.27 |