|
@@ -0,0 +1,349 @@
|
|
|
|
|
+# 环境搭建指南(换电脑快速上手)
|
|
|
|
|
+
|
|
|
|
|
+> **目标**:在一台新电脑上,从零把本项目跑起来并打出 Android APK。
|
|
|
|
|
+> **适用**:Windows(当前环境)· macOS / Linux 标注了差异
|
|
|
|
|
+> **最后核对**:2026-11-15,下列版本均为**本机实测版本**
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 〇、先看这个(30 秒)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# 1. 基础环境:Node 22 + JDK 21 + Android SDK
|
|
|
|
|
+# 2. 克隆代码
|
|
|
|
|
+git clone https://git.fmode.cn/ice-static/fmode-app.git
|
|
|
|
|
+cd fmode-app
|
|
|
|
|
+
|
|
|
|
|
+# 3. 装依赖(postinstall 会自动生成 pdf worker)
|
|
|
|
|
+npm install
|
|
|
|
|
+
|
|
|
|
|
+# 4. 跑 Web 端
|
|
|
|
|
+npm start # → http://localhost:4200
|
|
|
|
|
+
|
|
|
|
|
+# 5. 打包 Android
|
|
|
|
|
+node scripts/copy-pdf-worker.mjs
|
|
|
|
|
+npm run build && npx cap sync android
|
|
|
|
|
+cd android && ./gradlew assembleDebug
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**构建成功后**:`android/app/build/outputs/apk/debug/app-debug.apk`
|
|
|
|
|
+
|
|
|
|
|
+> ⚠️ 第 5 步的 `./gradlew` 在本机**会因下载超时而失败**,详见「四、Gradle 坑」。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 一、必需软件(版本必须对)
|
|
|
|
|
+
|
|
|
|
|
+| 软件 | **本机实测版本** | 要求 | 为什么 |
|
|
|
|
|
+|---|---|---|---|
|
|
|
|
|
+| **Node.js** | **v22.22.3** | ≥ 20 | Angular 20 要求;Capacitor 8 要求 Node ≥ 20 |
|
|
|
|
|
+| **npm** | **10.9.8** | 随 Node | 项目用 npm(**不是 pnpm**,根目录的 `pnpm-lock.yaml` 是历史遗留,忽略它) |
|
|
|
|
|
+| **JDK** | **21.0.8 (Microsoft OpenJDK)** | **必须 21** | Capacitor 8 的 AGP 要求 JDK 21;17 会报错 |
|
|
|
|
|
+| **Android SDK** | platform **36** / build-tools **36.x** / NDK 27.1 | compileSdk 36 | `capacitor.config.ts` 里 targetSdk=36 |
|
|
|
|
|
+| **Android Studio** | AI-251(2025.1) | 可选 | 只为可视化调试;纯命令行构建不装也行 |
|
|
|
|
|
+| **adb** | Platform-Tools 36.0.1 | 随 SDK | 装 App / 看日志 / 截图 |
|
|
|
|
|
+
|
|
|
|
|
+### 本机的实际安装位置(换电脑时作参考,无需照搬)
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+JDK E:\coding-environment\jdks\21 (JAVA_HOME)
|
|
|
|
|
+AndroidSDK E:\coding-environment\AndroidSDK (需设为 ANDROID_HOME)
|
|
|
|
|
+adb E:\coding-environment\adb\adb
|
|
|
|
|
+Android Studio E:\coding-environment\Android
|
|
|
|
|
+Gradle 缓存 ~/.gradle/wrapper/dists/gradle-8.14.3-bin
|
|
|
|
|
+Playwright ~/AppData/Local/ms-playwright
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 二、安装步骤
|
|
|
|
|
+
|
|
|
|
|
+### 2.1 Node.js
|
|
|
|
|
+
|
|
|
|
|
+**Windows**:装 [nvm-windows](https://github.com/coreybutler/nvm-windows) 后
|
|
|
|
|
+```bash
|
|
|
|
|
+nvm install 22
|
|
|
|
|
+nvm use 22
|
|
|
|
|
+```
|
|
|
|
|
+或直接下 [Node 22 LTS 安装包](https://nodejs.org/)。
|
|
|
|
|
+
|
|
|
|
|
+**macOS/Linux**:`nvm install 22 && nvm use 22`
|
|
|
|
|
+
|
|
|
|
|
+验证:`node -v` 应输出 `v22.x`
|
|
|
|
|
+
|
|
|
|
|
+### 2.2 JDK 21
|
|
|
|
|
+
|
|
|
|
|
+**Windows**:
|
|
|
|
|
+```bash
|
|
|
|
|
+# 用 winget
|
|
|
|
|
+winget install Microsoft.OpenJDK.21
|
|
|
|
|
+# 或 scoop
|
|
|
|
|
+scoop install temurin21-jdk
|
|
|
|
|
+```
|
|
|
|
|
+装完设置环境变量:
|
|
|
|
|
+```powershell
|
|
|
|
|
+[Environment]::SetEnvironmentVariable('JAVA_HOME','C:\Program Files\Microsoft\jdk-21','User')
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**macOS**:`brew install --cask temurin@21`
|
|
|
|
|
+**Linux**:`sudo apt install openjdk-21-jdk`
|
|
|
|
|
+
|
|
|
|
|
+验证:`java -version` 必须是 **21.x**
|
|
|
|
|
+
|
|
|
|
|
+> 🔴 **JDK 版本是最容易踩的坑**。项目历史上装的是 21,如果新机器是 17,AGP 会直接报
|
|
|
|
|
+> `Unsupported class file major version` 之类。**别用 17,别用 24。**
|
|
|
|
|
+
|
|
|
|
|
+### 2.3 Android SDK
|
|
|
|
|
+
|
|
|
|
|
+**推荐用 Android Studio 的 SDK Manager 装**(最省事):
|
|
|
|
|
+1. 装 [Android Studio](https://developer.android.com/studio)
|
|
|
|
|
+2. SDK Manager → SDK Platforms 勾 **Android 16 (API 36)**
|
|
|
|
|
+3. SDK Tools 勾 **Android SDK Build-Tools 36.x**、**Platform-Tools**、**NDK 27.1**
|
|
|
|
|
+
|
|
|
|
|
+**纯命令行**(不装 Studio):
|
|
|
|
|
+```bash
|
|
|
|
|
+# 下载 commandline-tools,解压到 <SDK_ROOT>/cmdline-tools/latest
|
|
|
|
|
+sdkmanager "platforms;android-36" "build-tools;36.0.0" "platform-tools" "ndk;27.1.12297006"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**设置环境变量**(本项目**必须**,否则 Gradle 找不到 SDK):
|
|
|
|
|
+```bash
|
|
|
|
|
+export ANDROID_HOME="<你的SDK路径>" # Windows: E:/coding-environment/AndroidSDK
|
|
|
|
|
+export ANDROID_SDK_ROOT="$ANDROID_HOME"
|
|
|
|
|
+```
|
|
|
|
|
+Windows 持久化:
|
|
|
|
|
+```powershell
|
|
|
|
|
+[Environment]::SetEnvironmentVariable('ANDROID_HOME','E:\coding-environment\AndroidSDK','User')
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 🔴 **本机的 `ANDROID_HOME` 目前是空的**(每次构建我都是临时 `export`)。
|
|
|
|
|
+> 换电脑时建议**直接写进系统环境变量**,省得每次手动设。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 三、项目依赖
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+npm install
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+`postinstall` 会自动跑 `scripts/copy-pdf-worker.mjs`,生成 `public/pdf.worker.js`。
|
|
|
|
|
+
|
|
|
|
|
+### 关键运行时依赖(不用单独装,`npm install` 全搞定)
|
|
|
|
|
+
|
|
|
|
|
+| 包 | 版本 | 用途 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| `@angular/*` | ^20.3.0 | 框架 |
|
|
|
|
|
+| `@capacitor/core` / `android` / `cli` | ^8.6.2 | 打包 |
|
|
|
|
|
+| `@capacitor/app` | ^8.1.2 | 深链监听、回前台事件 |
|
|
|
|
|
+| `@capacitor/local-notifications` | ^8.3.1 | 权限查询(**发通知已改用自建插件**) |
|
|
|
|
|
+| `@capacitor/status-bar` | ^8.0.4 | 状态栏安全区 |
|
|
|
|
|
+| `@capacitor/share` | ^8.0.3 | 向外分享(已装未启用) |
|
|
|
|
|
+| `pdfjs-dist` | **4.10.38(锁死)** | PDF 预览,**不可随便升级** |
|
|
|
|
|
+| `@silurus/ooxml` | ^0.66.3 | Word/Excel 预览 |
|
|
|
|
|
+| `matrix-js-sdk` | ^42.4.0 | 消息收发(懒加载) |
|
|
|
|
|
+
|
|
|
|
|
+### Playwright(真机/CDP 调试用)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+npm install # playwright 在 devDependencies 里
|
|
|
|
|
+npx playwright install msedge # 或用系统已装的 Edge
|
|
|
|
|
+```
|
|
|
|
|
+> 本机用的是 **系统 Edge**(`chromium.launch({ channel: 'msedge' })`),
|
|
|
|
|
+> 因为 `playwright install chromium` 没装浏览器时连不上。新机器要么装 Edge(Windows 自带),
|
|
|
|
|
+> 要么 `npx playwright install chromium`。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 四、Gradle 坑(本机实测,**换电脑必看**)
|
|
|
|
|
+
|
|
|
|
|
+### 症状
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+java.net.SocketTimeoutException: Connect timed out
|
|
|
|
|
+ at org.gradle.wrapper.Install.forceFetch
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+`./gradlew` 会去 `services.gradle.org` 下载 Gradle 发行包,**国内经常超时**。
|
|
|
|
|
+
|
|
|
|
|
+### 两种解法
|
|
|
|
|
+
|
|
|
|
|
+**解法 A(本机采用):改用本地已缓存的 gradle**
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# 先看本地有什么版本
|
|
|
|
|
+ls ~/.gradle/wrapper/dists/
|
|
|
|
|
+
|
|
|
|
|
+# 直接用解压好的可执行文件(跳过 wrapper 下载)
|
|
|
|
|
+~/.gradle/wrapper/dists/gradle-8.14.3-bin/<hash>/gradle-8.14.3/bin/gradle assembleDebug
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**解法 B(更通用):配国内镜像**
|
|
|
|
|
+
|
|
|
|
|
+编辑 `android/gradle/wrapper/gradle-wrapper.properties`,把
|
|
|
|
|
+`distributionUrl` 换成:
|
|
|
|
|
+```properties
|
|
|
|
|
+distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.14.3-bin.zip
|
|
|
|
|
+```
|
|
|
|
|
+(或用阿里云镜像 `https://mirrors.aliyun.com/macports/distfiles/gradle/`)
|
|
|
|
|
+
|
|
|
|
|
+> 🔴 `gradle-wrapper.properties` 里原来是 `-all` 包(100+MB),
|
|
|
|
|
+> 本机已改成 `-bin`(约 60MB),下载量小一半。
|
|
|
|
|
+
|
|
|
|
|
+### 另一个坑:Maven 依赖下载慢
|
|
|
|
|
+
|
|
|
|
|
+首次构建要下几十个 AndroidX 依赖。可以在 `android/build.gradle` 和
|
|
|
|
|
+`android/settings.gradle` 的 `repositories` 里加阿里云镜像:
|
|
|
|
|
+
|
|
|
|
|
+```groovy
|
|
|
|
|
+maven { url 'https://maven.aliyun.com/repository/google' }
|
|
|
|
|
+maven { url 'https://maven.aliyun.com/repository/public' }
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 五、跑起来
|
|
|
|
|
+
|
|
|
|
|
+### 5.1 Web 端(开发调试最快)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+npm start # ng serve → http://localhost:4200
|
|
|
|
|
+# 或指定端
|
|
|
|
|
+open http://localhost:4200/mobile/messages
|
|
|
|
|
+open http://localhost:4200/desktop/chat
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**免登录开发**:项目根有 `.claude/dev-login.json`(**不入库**),
|
|
|
|
|
+`npm run dev:logged-in` 会自动注入登录态。
|
|
|
|
|
+
|
|
|
|
|
+### 5.2 Android App
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# 一次性完整流程
|
|
|
|
|
+export ANDROID_HOME="E:/coding-environment/AndroidSDK"
|
|
|
|
|
+node scripts/copy-pdf-worker.mjs
|
|
|
|
|
+npm run build && npx cap sync android
|
|
|
|
|
+cd android && ~/.gradle/wrapper/dists/gradle-8.14.3-bin/*/gradle-8.14.3/bin/gradle assembleDebug
|
|
|
|
|
+
|
|
|
|
|
+# 装到手机(先开 USB 调试)
|
|
|
|
|
+adb install -r app/build/outputs/apk/debug/app-debug.apk
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+也可以用 npm 脚本:`npm run cap:sync` / `npm run cap:open` / `npm run cap:apk`。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 六、真机调试手法(**这些是手搓的,没有现成技能**)
|
|
|
|
|
+
|
|
|
|
|
+> 🔴 **重要说明**:手机端测试**没有用任何 MCP 服务或技能**。
|
|
|
|
|
+> `mobile-mcp` 配置了但一直连接超时,全程是手工拼 `adb` 命令 + 临时写 Playwright 脚本。
|
|
|
|
|
+
|
|
|
|
|
+### 6.1 基础 adb
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+adb devices -l # 设备列表
|
|
|
|
|
+adb shell screencap -p /sdcard/s.png # 截图
|
|
|
|
|
+adb pull /sdcard/s.png ./shot.png # 拉回本地
|
|
|
|
|
+adb shell input tap 640 1200 # 点击(坐标是**物理像素**)
|
|
|
|
|
+adb shell input text "hello" # 输入(**只支持 ASCII**,中文会崩)
|
|
|
|
|
+adb shell input keyevent 4 # 返回键
|
|
|
|
|
+adb shell input keyevent 3 # Home
|
|
|
|
|
+adb logcat -d | grep -i fmode # 看日志
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 🔴 **坐标换算**:截图在终端里显示时会缩放。Read 工具会提示
|
|
|
|
|
+> 「multiply coordinates by 1.39」,意思是**显示坐标 × 1.39 = 物理坐标**。
|
|
|
|
|
+> 直接按看到的坐标点会点偏。
|
|
|
|
|
+
|
|
|
|
|
+### 6.2 精确定位元素(比目测坐标靠谱)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+adb shell uiautomator dump /sdcard/ui.xml
|
|
|
|
|
+adb shell cat /sdcard/ui.xml | tr '>' '\n' | grep '通知'
|
|
|
|
|
+# 输出里找 bounds="[46,426][1234,703]" → 中心点 (640, 565)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**点击通知栏通知必须用这个**,目测坐标会点空(踩过)。
|
|
|
|
|
+
|
|
|
|
|
+### 6.3 连进 WebView 读内部状态(最有用的手法)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# 1. 拿到 App 的 PID
|
|
|
|
|
+PID=$(adb shell ps -A | grep cn.fmode.app | awk '{print $2}' | head -1)
|
|
|
|
|
+
|
|
|
|
|
+# 2. 把 WebView 调试端口转发到本机
|
|
|
|
|
+adb forward tcp:9400 localabstract:webview_devtools_remote_$PID
|
|
|
|
|
+
|
|
|
|
|
+# 3. 用 Playwright 连上去(脚本自己写)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+脚本模板(存成任意 `.mjs`,用 `node xxx.mjs` 跑):
|
|
|
|
|
+
|
|
|
|
|
+```js
|
|
|
|
|
+import { chromium } from 'playwright';
|
|
|
|
|
+const b = await chromium.connectOverCDP('http://127.0.0.1:9400');
|
|
|
|
|
+const p = b.contexts()[0].pages()[0];
|
|
|
|
|
+
|
|
|
|
|
+// 读 DOM / 执行任意 JS
|
|
|
|
|
+const v = await p.evaluate(() => {
|
|
|
|
|
+ return getComputedStyle(document.documentElement).getPropertyValue('--mob-safe-top');
|
|
|
|
|
+});
|
|
|
|
|
+console.log(v);
|
|
|
|
|
+
|
|
|
|
|
+await b.close();
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**能干什么**:
|
|
|
|
|
+- 读 CSS 变量实际值(排查安全区问题就靠这个)
|
|
|
|
|
+- 查 DOM 结构、元素数量
|
|
|
|
|
+- 直接调 Capacitor 插件:`window.Capacitor.Plugins.LocalNotifications.checkPermissions()`
|
|
|
|
|
+- **触发文件选择器**:`p.waitForEvent('filechooser')` + `chooser.setFiles(路径)`
|
|
|
|
|
+- 走 Angular 的路由/服务状态
|
|
|
|
|
+
|
|
|
|
|
+> 🔴 **注意**:连 App 的 WebView 用 `waitUntil: 'domcontentloaded'`,
|
|
|
|
|
+> **不要用 `networkidle`** —— Matrix 长轮询永远不会 idle,会一直等到超时。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 七、环境变量清单
|
|
|
|
|
+
|
|
|
|
|
+| 变量 | 值 | 必需 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| `JAVA_HOME` | JDK 21 目录 | ✅ |
|
|
|
|
|
+| `ANDROID_HOME` | Android SDK 目录 | ✅(构建 Android) |
|
|
|
|
|
+| `ANDROID_SDK_ROOT` | 同 ANDROID_HOME | 建议 |
|
|
|
|
|
+| `PATH` | 含 `%JAVA_HOME%\bin`、`%ANDROID_HOME%\platform-tools` | ✅ |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 八、常见问题
|
|
|
|
|
+
|
|
|
|
|
+| 现象 | 原因 | 解法 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| `gradlew` 超时 | Gradle 发行包下载慢 | 见「四、Gradle 坑」 |
|
|
|
|
|
+| `ANDROID_HOME not set` | 环境变量没配 | 见 2.3 |
|
|
|
|
|
+| `Unsupported class file major version` | JDK 版本不对 | 换 JDK 21 |
|
|
|
|
|
+| **PDF 一直转圈** | `public/pdf.worker.js` 是旧版 | `node scripts/copy-pdf-worker.mjs`(有断言会告诉你) |
|
|
|
|
|
+| `npm install` ECONNRESET | 网络抖动 | `npm i --fetch-retries=5` |
|
|
|
|
|
+| `playwright` 找不到浏览器 | 没装浏览器 | `npx playwright install chromium` 或用系统 Edge |
|
|
|
|
|
+| App 里字体/样式不对 | 没跑 `cap sync` | `npm run build && npx cap sync android` |
|
|
|
|
|
+| 真机白屏 | 见 `docs/00-tracking/` 对应事故文档 | — |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 九、新电脑接手检查清单
|
|
|
|
|
+
|
|
|
|
|
+跑完下面这些全部通过,说明环境 OK:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+node -v # v22.x
|
|
|
|
|
+java -version # 21.x
|
|
|
|
|
+echo $ANDROID_HOME # 非空,且目录存在
|
|
|
|
|
+npm install # 无报错,且自动生成了 public/pdf.worker.js
|
|
|
|
|
+node scripts/copy-pdf-worker.mjs # 输出「已校验」,字节数一致
|
|
|
|
|
+npm run build # Output location: dist/fmode-app-v2
|
|
|
|
|
+npx tsc --noEmit -p tsconfig.app.json # 无输出(无错误)
|
|
|
|
|
+adb devices # 能看到设备(真机调试才需要)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**然后**:读 `docs/00-tracking/当前进度-给AI接手.md` 了解进度再动手。
|