--- 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` 是正常运行时数据