Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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