Skip to content

Commit 6fcaea7

Browse files
committed
refactor(android): remove tracked binaries and bootstrap wrapper at runtime
1 parent ad2f491 commit 6fcaea7

39 files changed

Lines changed: 2398 additions & 22 deletions

.env.android.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Android APP build env for frontend (Vite)
2+
# 必填:手机 APP 请求后端 API 的完整地址(建议 HTTPS)
3+
VITE_API_BASE_URL=https://your-backend-domain.com/api
4+
5+
# 可选:仅当你在原生容器内运行并希望和 VITE_API_BASE_URL 区分时使用
6+
# VITE_API_BASE_URL_MOBILE=https://your-backend-domain.com/api
7+
8+
# ⚠️ 不要在前端填写 SUPABASE_SERVICE_ROLE_KEY
9+
# Service Role Key 只能放在后端环境变量中

README.md

Lines changed: 122 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,133 @@
22
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
33
</div>
44

5-
# Run and deploy your AI Studio app
5+
# Couple Connection
66

7-
This contains everything you need to run your app locally.
7+
本仓库包含:
8+
- 前端(Vite + React)
9+
- 后端(Node + Express)
10+
- Supabase(数据库 + Storage)
11+
- Android 打包能力(Capacitor)
812

9-
View your app in AI Studio: https://ai.studio/apps/temp/1
13+
## 本地开发
1014

11-
## AI Code Review
15+
**Prerequisites:** Node.js
1216

13-
This repository has GPT-powered automated code review enabled. See [setup instructions](.github/GPT_CODE_REVIEW_SETUP.md) ([English](.github/GPT_CODE_REVIEW_SETUP_EN.md)) for configuration details.
17+
1. 安装依赖:
18+
```bash
19+
npm install
20+
```
21+
2. 启动前端:
22+
```bash
23+
npm run dev
24+
```
25+
3. 启动后端:
26+
```bash
27+
npm run dev:backend
28+
```
29+
30+
## Supabase 配置(重要)
31+
32+
后端需要以下环境变量(放在后端运行环境,不要暴露到前端):
33+
34+
- `SUPABASE_URL`
35+
- `SUPABASE_SERVICE_ROLE_KEY`
36+
37+
> ⚠️ `SUPABASE_SERVICE_ROLE_KEY` 是高权限密钥,绝对不能写进前端 `.env` 或 APK。
38+
39+
## 打包 Android APK(手机安装)
40+
41+
> 说明:仓库已按“**不支持二进制文件**”要求移除图标/启动图 PNG 与 `gradle-wrapper.jar`
42+
> - 图标与启动图改为 XML 资源;
43+
> - `gradle-wrapper.jar` 在执行 Android 打包命令时通过 `scripts/bootstrap-gradle-wrapper.sh` 自动下载。
44+
45+
### 1) 先修复 Android SDK 环境
46+
47+
```bash
48+
npm run android:sdk:setup
49+
```
50+
51+
### 2) 配置移动端 API 地址
52+
53+
复制并填写:
54+
55+
```bash
56+
cp .env.android.example .env
57+
```
58+
59+
至少配置:
60+
61+
```bash
62+
VITE_API_BASE_URL=https://你的后端域名/api
63+
```
64+
65+
### 3) 同步并生成 Android 工程
66+
67+
```bash
68+
npm run build:mobile
69+
```
70+
71+
### 4) 构建 Debug APK
72+
73+
```bash
74+
npm run android:apk
75+
```
1476

15-
## Run Locally
77+
APK 默认输出目录:
1678

17-
**Prerequisites:** Node.js
79+
```text
80+
android/app/build/outputs/apk/official/debug/app-official-universal-debug.apk
81+
```
1882

83+
### 5) 安装到手机(小米/华为等)
1984

20-
1. Install dependencies:
21-
`npm install`
22-
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
23-
3. Run the app:
24-
`npm run dev`
85+
```bash
86+
adb install -r android/app/build/outputs/apk/official/debug/app-official-universal-debug.apk
87+
```
88+
89+
> 若是首次安装,需在手机上允许“安装未知应用”。
90+
91+
## Release 签名与渠道包
92+
93+
```bash
94+
npm run android:keystore:create -- android/app/release-keystore.jks coupleconnection <storePassword> <keyPassword> 3650 "CN=YourApp, OU=Mobile, O=YourOrg, L=Shenzhen, ST=Guangdong, C=CN" JKS # 生成 release keystore 和 keystore.properties
95+
npm run android:apk:release # 输出 official 渠道 release APK
96+
npm run android:bundle:release # 输出 official 渠道 release AAB
97+
```
98+
99+
## 多渠道 / 多 ABI
100+
101+
已配置:
102+
- 渠道:`official` / `xiaomi` / `huawei`
103+
- ABI:`armeabi-v7a` / `arm64-v8a` / `x86_64`(含 universalApk)
104+
105+
## 常用移动端命令
106+
107+
```bash
108+
npm run android:sync # 仅同步 Web 资源和插件
109+
npm run android:open # 用 Android Studio 打开原生工程
110+
npm run android:apk # 构建 debug APK
111+
npm run android:apk:release # 构建 official 渠道 release APK
112+
```
113+
114+
115+
## 上架前最后一步(版本号/图标/启动图/包名渠道)
116+
117+
请直接按该文档操作:
118+
119+
- [docs/ANDROID_RELEASE_GUIDE.md](docs/ANDROID_RELEASE_GUIDE.md)
120+
121+
文档已把以下内容整合为一套流程:
122+
- versionCode / versionName
123+
- 应用图标与启动图替换
124+
- 小米/华为/官方包名渠道策略
125+
126+
## 真机兼容清单(小米/华为)
127+
128+
请查看完整文档:
129+
130+
- [docs/ANDROID_RELEASE_GUIDE.md](docs/ANDROID_RELEASE_GUIDE.md)
131+
132+
## AI Code Review
133+
134+
This repository has GPT-powered automated code review enabled. See [setup instructions](.github/GPT_CODE_REVIEW_SETUP.md) ([English](.github/GPT_CODE_REVIEW_SETUP_EN.md)) for configuration details.

android/.gitignore

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
2+
3+
# Built application files
4+
*.apk
5+
*.aar
6+
*.ap_
7+
*.aab
8+
9+
# Files for the ART/Dalvik VM
10+
*.dex
11+
12+
# Java class files
13+
*.class
14+
15+
# Generated files
16+
bin/
17+
gen/
18+
out/
19+
# Uncomment the following line in case you need and you don't have the release build type files in your app
20+
# release/
21+
22+
# Gradle files
23+
.gradle/
24+
build/
25+
26+
# Local configuration file (sdk path, etc)
27+
local.properties
28+
29+
# Proguard folder generated by Eclipse
30+
proguard/
31+
32+
# Log Files
33+
*.log
34+
35+
# Android Studio Navigation editor temp files
36+
.navigation/
37+
38+
# Android Studio captures folder
39+
captures/
40+
41+
# IntelliJ
42+
*.iml
43+
.idea/workspace.xml
44+
.idea/tasks.xml
45+
.idea/gradle.xml
46+
.idea/assetWizardSettings.xml
47+
.idea/dictionaries
48+
.idea/libraries
49+
# Android Studio 3 in .gitignore file.
50+
.idea/caches
51+
.idea/modules.xml
52+
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
53+
.idea/navEditor.xml
54+
55+
# Keystore files
56+
# Uncomment the following lines if you do not want to check your keystore files in.
57+
#*.jks
58+
#*.keystore
59+
60+
# External native build folder generated in Android Studio 2.2 and later
61+
.externalNativeBuild
62+
.cxx/
63+
64+
# Google Services (e.g. APIs or Firebase)
65+
# google-services.json
66+
67+
# Freeline
68+
freeline.py
69+
freeline/
70+
freeline_project_description.json
71+
72+
# fastlane
73+
fastlane/report.xml
74+
fastlane/Preview.html
75+
fastlane/screenshots
76+
fastlane/test_output
77+
fastlane/readme.md
78+
79+
# Version control
80+
vcs.xml
81+
82+
# lint
83+
lint/intermediates/
84+
lint/generated/
85+
lint/outputs/
86+
lint/tmp/
87+
# lint/reports/
88+
89+
# Android Profiling
90+
*.hprof
91+
92+
# Cordova plugins for Capacitor
93+
capacitor-cordova-android-plugins
94+
95+
# Copied web assets
96+
app/src/main/assets/public
97+
98+
# Generated Config files
99+
app/src/main/assets/capacitor.config.json
100+
app/src/main/assets/capacitor.plugins.json
101+
app/src/main/res/xml/config.xml
102+
103+
# Release signing secrets
104+
keystore.properties
105+
app/*.jks
106+
app/*.keystore
107+
108+
# Downloaded at runtime to keep repository text-only
109+
gradle/wrapper/gradle-wrapper.jar

android/app/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/build/*
2+
!/build/.npmkeep

android/app/build.gradle

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
apply plugin: 'com.android.application'
2+
3+
import java.util.Properties
4+
5+
final Properties keystoreProperties = new Properties()
6+
final File keystorePropertiesFile = rootProject.file('keystore.properties')
7+
if (keystorePropertiesFile.exists()) {
8+
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
9+
}
10+
11+
final int appVersionCode = (project.findProperty('APP_VERSION_CODE') ?: '1') as Integer
12+
final String appVersionName = String.valueOf(project.findProperty('APP_VERSION_NAME') ?: '1.0.0')
13+
final String appIdBase = String.valueOf(project.findProperty('APP_ID_BASE') ?: 'com.gifts.coupleconnection')
14+
final String appIdXiaomi = String.valueOf(project.findProperty('APP_ID_XIAOMI') ?: appIdBase + '.mi')
15+
final String appIdHuawei = String.valueOf(project.findProperty('APP_ID_HUAWEI') ?: appIdBase + '.hw')
16+
17+
android {
18+
namespace "com.gifts.coupleconnection"
19+
compileSdk rootProject.ext.compileSdkVersion
20+
21+
defaultConfig {
22+
applicationId appIdBase
23+
minSdkVersion rootProject.ext.minSdkVersion
24+
targetSdkVersion rootProject.ext.targetSdkVersion
25+
versionCode appVersionCode
26+
versionName appVersionName
27+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
28+
29+
ndk {
30+
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
31+
}
32+
33+
aaptOptions {
34+
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
35+
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
36+
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
37+
}
38+
}
39+
40+
signingConfigs {
41+
release {
42+
if (keystorePropertiesFile.exists()) {
43+
keyAlias keystoreProperties['keyAlias']
44+
keyPassword keystoreProperties['keyPassword']
45+
storeFile file(keystoreProperties['storeFile'])
46+
storePassword keystoreProperties['storePassword']
47+
}
48+
}
49+
}
50+
51+
buildTypes {
52+
debug {
53+
debuggable true
54+
}
55+
release {
56+
minifyEnabled false
57+
shrinkResources false
58+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
59+
if (keystorePropertiesFile.exists()) {
60+
signingConfig signingConfigs.release
61+
}
62+
}
63+
}
64+
65+
flavorDimensions += ["channel"]
66+
productFlavors {
67+
official {
68+
dimension "channel"
69+
applicationId appIdBase
70+
resValue 'string', 'app_name', 'Couple Connection'
71+
manifestPlaceholders = [channelName: 'official']
72+
}
73+
xiaomi {
74+
dimension "channel"
75+
applicationId appIdXiaomi
76+
resValue 'string', 'app_name', 'Couple Connection 小米版'
77+
versionNameSuffix '-xm'
78+
manifestPlaceholders = [channelName: 'xiaomi']
79+
}
80+
huawei {
81+
dimension "channel"
82+
applicationId appIdHuawei
83+
resValue 'string', 'app_name', 'Couple Connection 华为版'
84+
versionNameSuffix '-hw'
85+
manifestPlaceholders = [channelName: 'huawei']
86+
}
87+
}
88+
89+
splits {
90+
abi {
91+
enable true
92+
reset()
93+
include 'armeabi-v7a', 'arm64-v8a', 'x86_64'
94+
universalApk true
95+
}
96+
}
97+
98+
}
99+
100+
repositories {
101+
flatDir {
102+
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
103+
}
104+
}
105+
106+
dependencies {
107+
implementation fileTree(include: ['*.jar'], dir: 'libs')
108+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
109+
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
110+
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
111+
implementation project(':capacitor-android')
112+
testImplementation "junit:junit:$junitVersion"
113+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
114+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
115+
implementation project(':capacitor-cordova-android-plugins')
116+
}
117+
118+
apply from: 'capacitor.build.gradle'
119+
120+
try {
121+
def servicesJSON = file('google-services.json')
122+
if (servicesJSON.text) {
123+
apply plugin: 'com.google.gms.google-services'
124+
}
125+
} catch (Exception e) {
126+
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
127+
}

0 commit comments

Comments
 (0)