Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.android.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Android APP build env for frontend (Vite)
# 必填:手机 APP 请求后端 API 的完整地址(建议 HTTPS)
VITE_API_BASE_URL=https://your-backend-domain.com/api

# 可选:仅当你在原生容器内运行并希望和 VITE_API_BASE_URL 区分时使用
# VITE_API_BASE_URL_MOBILE=https://your-backend-domain.com/api

# ⚠️ 不要在前端填写 SUPABASE_SERVICE_ROLE_KEY
# Service Role Key 只能放在后端环境变量中
134 changes: 122 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,133 @@
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
</div>

# Run and deploy your AI Studio app
# Couple Connection

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

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

## AI Code Review
**Prerequisites:** Node.js

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.
1. 安装依赖:
```bash
npm install
```
2. 启动前端:
```bash
npm run dev
```
3. 启动后端:
```bash
npm run dev:backend
```

## Supabase 配置(重要)

后端需要以下环境变量(放在后端运行环境,不要暴露到前端):

- `SUPABASE_URL`
- `SUPABASE_SERVICE_ROLE_KEY`

> ⚠️ `SUPABASE_SERVICE_ROLE_KEY` 是高权限密钥,绝对不能写进前端 `.env` 或 APK。

## 打包 Android APK(手机安装)

> 说明:仓库已按“**不支持二进制文件**”要求移除图标/启动图 PNG 与 `gradle-wrapper.jar`。
> - 图标与启动图改为 XML 资源;
> - `gradle-wrapper.jar` 在执行 Android 打包命令时通过 `scripts/bootstrap-gradle-wrapper.sh` 自动下载。

### 1) 先修复 Android SDK 环境

```bash
npm run android:sdk:setup
```

### 2) 配置移动端 API 地址

复制并填写:

```bash
cp .env.android.example .env
```

至少配置:

```bash
VITE_API_BASE_URL=https://你的后端域名/api
```

### 3) 同步并生成 Android 工程

```bash
npm run build:mobile
```

### 4) 构建 Debug APK

```bash
npm run android:apk
```

## Run Locally
APK 默认输出目录:

**Prerequisites:** Node.js
```text
android/app/build/outputs/apk/official/debug/app-official-universal-debug.apk
```

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

1. Install dependencies:
`npm install`
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
3. Run the app:
`npm run dev`
```bash
adb install -r android/app/build/outputs/apk/official/debug/app-official-universal-debug.apk
```

> 若是首次安装,需在手机上允许“安装未知应用”。

## Release 签名与渠道包

```bash
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
npm run android:apk:release # 输出 official 渠道 release APK
npm run android:bundle:release # 输出 official 渠道 release AAB
```

## 多渠道 / 多 ABI

已配置:
- 渠道:`official` / `xiaomi` / `huawei`
- ABI:`armeabi-v7a` / `arm64-v8a` / `x86_64`(含 universalApk)

## 常用移动端命令

```bash
npm run android:sync # 仅同步 Web 资源和插件
npm run android:open # 用 Android Studio 打开原生工程
npm run android:apk # 构建 debug APK
npm run android:apk:release # 构建 official 渠道 release APK
```


## 上架前最后一步(版本号/图标/启动图/包名渠道)

请直接按该文档操作:

- [docs/ANDROID_RELEASE_GUIDE.md](docs/ANDROID_RELEASE_GUIDE.md)

文档已把以下内容整合为一套流程:
- versionCode / versionName
- 应用图标与启动图替换
- 小米/华为/官方包名渠道策略

## 真机兼容清单(小米/华为)

请查看完整文档:

- [docs/ANDROID_RELEASE_GUIDE.md](docs/ANDROID_RELEASE_GUIDE.md)

## AI Code Review

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.
109 changes: 109 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore

# Built application files
*.apk
*.aar
*.ap_
*.aab

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/
# Uncomment the following line in case you need and you don't have the release build type files in your app
# release/

# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
# Android Studio 3 in .gitignore file.
.idea/caches
.idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
.idea/navEditor.xml

# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.
#*.jks
#*.keystore

# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
.cxx/

# Google Services (e.g. APIs or Firebase)
# google-services.json

# Freeline
freeline.py
freeline/
freeline_project_description.json

# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md

# Version control
vcs.xml

# lint
lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/

# Android Profiling
*.hprof

# Cordova plugins for Capacitor
capacitor-cordova-android-plugins

# Copied web assets
app/src/main/assets/public

# Generated Config files
app/src/main/assets/capacitor.config.json
app/src/main/assets/capacitor.plugins.json
app/src/main/res/xml/config.xml

# Release signing secrets
keystore.properties
app/*.jks
app/*.keystore

# Downloaded at runtime to keep repository text-only
gradle/wrapper/gradle-wrapper.jar
2 changes: 2 additions & 0 deletions android/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/build/*
!/build/.npmkeep
127 changes: 127 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
apply plugin: 'com.android.application'

import java.util.Properties

final Properties keystoreProperties = new Properties()
final File keystorePropertiesFile = rootProject.file('keystore.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

final int appVersionCode = (project.findProperty('APP_VERSION_CODE') ?: '1') as Integer
final String appVersionName = String.valueOf(project.findProperty('APP_VERSION_NAME') ?: '1.0.0')
final String appIdBase = String.valueOf(project.findProperty('APP_ID_BASE') ?: 'com.gifts.coupleconnection')
final String appIdXiaomi = String.valueOf(project.findProperty('APP_ID_XIAOMI') ?: appIdBase + '.mi')
final String appIdHuawei = String.valueOf(project.findProperty('APP_ID_HUAWEI') ?: appIdBase + '.hw')

android {
namespace "com.gifts.coupleconnection"
compileSdk rootProject.ext.compileSdkVersion

defaultConfig {
applicationId appIdBase
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode appVersionCode
versionName appVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
}

aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}

signingConfigs {
release {
if (keystorePropertiesFile.exists()) {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
}

buildTypes {
debug {
debuggable true
}
release {
minifyEnabled false
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
if (keystorePropertiesFile.exists()) {
signingConfig signingConfigs.release
}
}
}

flavorDimensions += ["channel"]
productFlavors {
official {
dimension "channel"
applicationId appIdBase
resValue 'string', 'app_name', 'Couple Connection'
manifestPlaceholders = [channelName: 'official']
}
xiaomi {
dimension "channel"
applicationId appIdXiaomi
resValue 'string', 'app_name', 'Couple Connection 小米版'
versionNameSuffix '-xm'
manifestPlaceholders = [channelName: 'xiaomi']
}
huawei {
dimension "channel"
applicationId appIdHuawei
resValue 'string', 'app_name', 'Couple Connection 华为版'
versionNameSuffix '-hw'
manifestPlaceholders = [channelName: 'huawei']
}
}

splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86_64'
universalApk true
}
}

}

repositories {
flatDir {
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
}
}

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
implementation project(':capacitor-android')
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
implementation project(':capacitor-cordova-android-plugins')
}

apply from: 'capacitor.build.gradle'

try {
def servicesJSON = file('google-services.json')
if (servicesJSON.text) {
apply plugin: 'com.google.gms.google-services'
}
} catch (Exception e) {
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
}
Loading