95 lines
4.4 KiB
Markdown
95 lines
4.4 KiB
Markdown
---
|
||
name: pywebview_macos_packaging
|
||
description: 当打包 PyWebview macOS App、调试 "The string did not match" 错误、修改 _packaging/ 目录时,应该索引本记忆
|
||
---
|
||
|
||
# PyWebview macOS 打包项目记忆
|
||
|
||
## 目标
|
||
将 Vue 3 + Python Flask 项目打包为 macOS 桌面 App(PyWebview),不使用 Electron/Tauri 或原生 macOS 对话框。
|
||
|
||
## 核心文件
|
||
| 文件 | 作用 |
|
||
|------|------|
|
||
| `_packaging/app.py` | PyWebview 主入口:检测 `.env` → 直接启动 / setup页面 |
|
||
| `_packaging/setup.html` | 首次设置页面(4步:工作区→模型→管理员→确认),classic暖奶油主题 |
|
||
| `_packaging/app.spec` | PyInstaller 打包配置 |
|
||
| `_packaging/dist/AI-Agent-System.app` | 打包产物 |
|
||
| `_packaging/AI-Agent-System-v8.dmg` | 最后一个可用DMG(527MB) |
|
||
|
||
## 关键修复历史
|
||
|
||
### 1. DMG 禁止标志
|
||
- **原因**:DMG 内同时存在 `AI-Agent-System/`(onedir目录)和 `AI-Agent-System.app`
|
||
- **修复**:DMG 只放 `.app` + `Applications` 符号链接
|
||
- **hdiutil 创建需完全访问权限**:当前受限制,需切换到完全访问权限模式
|
||
|
||
### 2. OpenSSL 符号冲突
|
||
- **原因**:`_ssl.cpython-311-darwin.so` 加载 psycopg2 自带的旧版 `libcrypto.3.dylib`
|
||
- **修复**:用 Homebrew OpenSSL 3.6.2 的 dylib 替换 bundle 中 `__dot__dylibs` 目录
|
||
|
||
### 3. `.env` 加载路径
|
||
- **修复**:`config/__init__.py` 的 `_load_dotenv()` 改为 frozen 时读 `~/.astrion/astrion/host/.env`
|
||
|
||
### 4. engineio Invalid async_mode
|
||
- **原因**:PyInstaller frozen 环境缺少 `engineio.async_drivers.threading`
|
||
- **修复**:`app.spec` hiddenimports 添加 `'engineio.async_drivers.threading'`
|
||
|
||
### 5. PyWebview 6.x private_mode 🚨 **关键问题**
|
||
- **现象**:Playwright 浏览器中正常(0 errors),PyWebview App 中所有 API 返回 HTML 导致 "The string did not match the expected pattern"
|
||
- **根因**:`webview.start()` 默认 `private_mode=True`,WKWebView 隐私模式下 cookie 不工作,session 丢失
|
||
- **修复**:`webview.start(private_mode=False)`
|
||
|
||
### 6. App Transport Security
|
||
- **修复**:`app.spec` Info.plist 添加 `NSAppTransportSecurity: { NSAllowsLocalNetworking: True }`
|
||
|
||
### 7. 环境变量污染
|
||
- **问题**:旧环境变量 `AGENTS_HOST_HOME=~/.agents/host-clone` 导致数据目录错误(现已被 `ASTRION_DATA_ROOT` 替代)
|
||
- **注意**:`~/.astrion/astrion-clone` 是本对话副本数据,不要动
|
||
- **修复**:`_start_flask` 导入前清除 `ASTRION_DATA_ROOT`/`DATA_DIR`/`LOGS_DIR` 等旧环境变量污染
|
||
|
||
### 8. JSON 错误处理器
|
||
- **修复**:`_start_flask` 中注册全局 error handler,确保任何异常都返回 JSON 而非 HTML
|
||
|
||
## 当前状态(2026-06-12)
|
||
|
||
### ✅ 已确认正常
|
||
- Flask 后端在浏览器中完全正常(curl/Playwright 测试 0 errors)
|
||
- 登录、对话列表、数据加载均正常
|
||
- API 返回纯 JSON
|
||
|
||
### ❌ 仍存在问题
|
||
- **PyWebview App 中仍然无数据**,前端报 "The string did not match the expected pattern"
|
||
- 已排除:backend 崩溃、engineio 错误、private_mode、ATS、环境变量污染
|
||
- **问题定位**:在 PyWebview 的 WKWebView 内部,fetch API 请求被某种机制拦截/修改,导致返回非 JSON 响应
|
||
|
||
### 🔍 下一步排查方向
|
||
1. 在 PyWebview 中启用远程调试(`webview.start(debug=True)`)查看 WKWebView console
|
||
2. 检查 PyWebview 6.x 的 `request_sent`/`response_received` 事件是否拦截了请求
|
||
3. 检查 WKWebView 对 `127.0.0.1` 的 same-origin 策略是否有特殊处理
|
||
4. 尝试用 `localhost` 替代 `127.0.0.1`
|
||
5. 考虑降级 PyWebview 到 5.x 或尝试其他打包方案(Tauri/Electron)
|
||
|
||
## 打包命令
|
||
```bash
|
||
# Python 必须是 Homebrew Python 3.11(Xcode Python 3.9 会 SIGKILL)
|
||
cd _packaging
|
||
pyinstaller --noconfirm --distpath ./dist --workpath ./build app.spec
|
||
|
||
# 安装到 /Applications
|
||
cp -R dist/AI-Agent-System.app /Applications/
|
||
codesign --force --deep -s - /Applications/AI-Agent-System.app
|
||
xattr -cr /Applications/AI-Agent-System.app
|
||
|
||
# 创建 DMG(需完全访问权限)
|
||
hdiutil create -srcfolder dist/AI-Agent-System.app -volname "AI_Agent_System" -ov -format UDZO AI-Agent-System.dmg
|
||
```
|
||
|
||
## 用户要求
|
||
- 禁止原生 macOS/浏览器组件
|
||
- setup 页面需与项目设计风格统一
|
||
- 只读一个 `.env`(数据存储目录 ~/.astrion/astrion/host/.env)
|
||
- 等待时间不要设置太长
|
||
- `~/.astrion/astrion-clone` 是本对话副本数据,不要乱动
|
||
- `~/.astrion/astrion/host` 是正常运行时数据
|