jim800121chen c54f16fca0 Initial commit: visionA monorepo with local-tool subproject
local-tool/: visionA-local desktop app
- M1: Wails shell + Go server + Next.js UI + Mock mode (macOS dmg ready)
- M2: i18n (zh-TW/en) + Settings 4-tab refactor
- M3: Embedded Python 3.12 runtime (python-build-standalone) + KneronPLUS wheels
- M4: Windows Inno Setup script (build on Windows runner)
- M5: Linux AppImage script + udev rule (build on Linux runner)
- M6: ffmpeg (GPL, pending legal review) + yt-dlp bundled
- Lifecycle: watchServer health check, fatal native dialog,
            Wails IPC raise endpoint, stale process cleanup

.autoflow/: full PRD / Design Spec / Architecture / Testing docs
            (4 rounds tri-party discussion + cross review)
.github/workflows/: macOS / Windows / Linux build CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:10:38 +08:00

9.7 KiB
Raw Permalink Blame History

Packaging — visionA-local

macOS .dmg、Windows Inno Setup .exe、Linux AppImage 的具體打包流程。 無任何程式碼簽章(使用者決策 Q2 = C


1. 總覽:三平台產出物

平台 格式 簽章 大小(預估)
macOS 14/15 x86_64 visiona-local-v{ver}-macos-x64.dmg 內含 .app ad-hoccodesign -s - ~195MB
Windows 10/11 x64 visiona-local-v{ver}-windows-x64.exeInno Setup installer ~205MB
Ubuntu 22.04/24.04 x64 visiona-local-v{ver}-linux-x64.AppImage ~210MB

2. macOS.app + .dmg

2.1 建置流程

# 1. 準備 payload
make payload-macos    # 把 python + wheels + ffmpeg + models 塞到 visiona-local/payload/

# 2. Wails 編譯
cd visiona-local && wails build -platform darwin/amd64 -clean

# 3. ad-hoc sign
codesign --force --deep --sign - build/bin/visiona-local.app

# 4. 驗證簽章
codesign -dv --verbose=4 build/bin/visiona-local.app

# 5. 打包成 dmg
dmgbuild -s dmg-config.py "visionA-local" dist/visiona-local-v${VERSION}-macos-x64.dmg  # 顯示標題沿用產品名 visionA-local

2.2 wails.json 關鍵設定

{
  "name": "visiona-local",
  "outputfilename": "visiona-local",
  "frontend:install": "echo skip",
  "frontend:build": "echo skip",
  "info": {
    "companyName": "Innovedus",
    "productName": "visionA-local",
    "productVersion": "1.0.0",
    "copyright": "© 2026 Innovedus",
    "comments": "Kneron KL520/KL720 本地開發工具"
  },
  "nsisType": "multiple",
  "appid": "com.innovedus.visiona-local"
}

2.3 Info.plist 關鍵項

  • CFBundleIdentifier = com.innovedus.visiona-local
  • CFBundleExecutable = visiona-localbinary 全小寫;CFBundleName / CFBundleDisplayName 仍為 visionA-local 作為顯示名)
  • NSHighResolutionCapable = true
  • LSMinimumSystemVersion = 14.0
  • NSCameraUsageDescription = visionA-local 需要存取攝影機以執行 AI 推論展示
  • NSAppleEventsUsageDescription = visionA-local 需要使用 AppleScript 開啟瀏覽器
  • 不需要 NSAppTransportSecurity 因為只用 localhost

2.4 dmgbuild 設定檔(dmg-config.py

# dmg-config.py
format = 'UDBZ'  # bzip2 壓縮,壓縮率好
size = '400M'
files = ['build/bin/visiona-local.app']
symlinks = {'Applications': '/Applications'}
badge_icon = 'build/icon.icns'
icon_locations = {
    'visiona-local.app': (150, 200),
    'Applications': (450, 200),
}
window_rect = ((200, 200), (600, 400))
background = 'build/dmg-background.png'

2.5 首次啟動Gatekeeper workaround

因為沒有 notarization使用者第一次打開 .app 會跳警告:

"visionA-local" can't be opened because it is from an unidentified developer.

解法(必須寫進 README 與首次啟動說明頁):

  1. 在 Finder 中對 visiona-local.app 按右鍵 → 開啟
  2. 在警告對話框按「開啟」
  3. 之後可以正常雙擊開啟

或命令列:xattr -d com.apple.quarantine /Applications/visiona-local.app

3. WindowsInno Setup .exe

3.1 為何選 Inno Setup 而不是 NSIS / MSI

  • UI 現代化Inno Setup 6 的預設樣式比 NSIS 好看
  • 腳本簡單Pascal-like DSL比 NSIS 的 MakeNSIS 好維護
  • 安裝 driver 方便:內建 DriverInstall 流程支援 pnputil
  • 不用 MSIMSI 需要 WiX 工具鏈與 signing 才順我們不簽章Inno Setup 更簡單

3.2 建置流程

# 1. 準備 payload
make payload-windows

# 2. Wails 編譯
cd visiona-local && wails build -platform windows/amd64 -clean

# 3. 執行 Inno Setup Compiler
iscc visiona-local-installer.iss

# 產物dist/visiona-local-v{ver}-windows-x64.exe

3.3 visiona-local-installer.iss 骨架

[Setup]
AppId={{A7F3E891-4B2C-4D5E-9F1A-8B3C2D1E0F9A}
AppName=visionA-local
AppVersion=1.0.0
AppPublisher=Innovedus
AppPublisherURL=https://innovedus.com
DefaultDirName={autopf}\visiona-local
DefaultGroupName=visiona-local
OutputDir=..\dist
OutputBaseFilename=visiona-local-v1.0.0-windows-x64
SetupIconFile=assets\icon.ico
Compression=lzma2/ultra64
SolidCompression=yes
WizardStyle=modern
PrivilegesRequired=admin
ArchitecturesInstallIn64BitMode=x64
MinVersion=10.0.17763

[Files]
Source: "visiona-local\build\bin\visiona-local.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "visiona-local\payload\*"; DestDir: "{app}\payload"; Flags: ignoreversion recursesubdirs

[Icons]
Name: "{group}\visionA-local"; Filename: "{app}\visiona-local.exe"
Name: "{autodesktop}\visionA-local"; Filename: "{app}\visiona-local.exe"; Tasks: desktopicon

[Tasks]
Name: "desktopicon"; Description: "建立桌面捷徑"; GroupDescription: "附加選項:"

[Run]
; 安裝 WinUSB driver
Filename: "{sys}\pnputil.exe"; \
  Parameters: "/add-driver ""{app}\payload\drivers\kneron_winusb.inf"" /install"; \
  StatusMsg: "正在安裝 Kneron USB driver..."; \
  Flags: runhidden waituntilterminated

; 啟動 app
Filename: "{app}\visiona-local.exe"; \
  Description: "啟動 visionA-local"; \
  Flags: postinstall nowait skipifsilent

[UninstallDelete]
Type: filesandordirs; Name: "{localappdata}\visiona-local"

3.4 SmartScreen 警告處理

沒有 Authenticode 簽章Windows SmartScreen 會擋:

Windows protected your PC — Microsoft Defender SmartScreen prevented an unrecognized app from starting.

解法(寫進安裝說明):

  1. 點「更多資訊」
  2. 點「仍要執行」

使用者第一次下載後會遇到這個警告,執行過一次之後 Windows 會記住。這是可接受的摩擦成本(使用者決策)。

4. LinuxAppImage

4.1 為何選 AppImage 而不是 .deb / snap / flatpak

  • 單檔可攜:一個 .AppImage 檔案,雙擊即跑,不需安裝
  • 跨發行版:只要 glibc >= 2.28Ubuntu 18.04+)就能跑
  • 不需 sudo(正常情境下)
  • 符合「像一般 app」的體驗

.deb 需要 apt install + sudosnap / flatpak 需要發到 store 或有 runtime 依賴,不適合內部工具分發。

4.2 建置流程

# 1. 準備 payload
make payload-linux

# 2. Wails 編譯
cd visiona-local && wails build -platform linux/amd64 -clean

# 3. 建立 AppDir
rm -rf AppDir && mkdir -p AppDir/usr/bin AppDir/usr/lib
cp build/bin/visiona-local AppDir/usr/bin/
cp -r payload AppDir/usr/bin/payload

# 4. 複製 libusb 到 AppDir避免依賴系統 libusb
cp /usr/lib/x86_64-linux-gnu/libusb-1.0.so.0 AppDir/usr/lib/

# 5. 寫入 .desktop 與 AppRun
cat > AppDir/visiona-local.desktop <<EOF
[Desktop Entry]
Type=Application
Name=visionA-local
Exec=visiona-local
Icon=visiona-local
Categories=Development;
EOF

cat > AppDir/AppRun <<'EOF'
#!/bin/bash
HERE="$(dirname "$(readlink -f "$0")")"
export LD_LIBRARY_PATH="$HERE/usr/lib:${LD_LIBRARY_PATH}"
exec "$HERE/usr/bin/visiona-local" "$@"
EOF
chmod +x AppDir/AppRun

cp assets/icon.png AppDir/visiona-local.png

# 6. 用 appimagetool 打包
ARCH=x86_64 appimagetool AppDir dist/visiona-local-v${VERSION}-linux-x64.AppImage

4.3 首次執行需要的權限

因為要寫入 /etc/udev/rules.d/99-kneron.rules 讓非 root 使用者存取 USB

首次執行時跳 pkexec 提權對話框GNOME 預設可用),執行:

pkexec cp ~/.local/share/visiona-local/scripts/99-kneron.rules /etc/udev/rules.d/
pkexec udevadm control --reload-rules
pkexec udevadm trigger

使用者拒絕或系統沒有 pkexec例如 minimal server 安裝):顯示錯誤訊息提示手動執行 sudo ./install-udev.sh,內附的 script 由我們提供。

4.4 AppImage 的已知限制

  • 沒有 .desktop integration:使用者要自己放到 ~/Applications/ 或用 appimaged
  • 第一次解壓慢AppImage 是 squashfs第一次啟動會把內容 mount 到 /tmp/.mount_*/

5. 圖示與品牌資產

5.1 檔案清單

平台 檔案 尺寸
macOS visiona-local.icns 512×512 @1x + @2x
Windows visiona-local.ico 16, 32, 48, 64, 128, 256
Linux visiona-local.png 256×256

Tray 圖示已移除(第三輪使用者決策 Q-A=A3砍 tray

5.2 來源

使用者決策 Q14先沿用 edge-ai-platform 既有視覺(字母 E,品牌換名但圖示暫時不動。

edge-ai-platform/installer/frontend/src-tauri/icons/ 直接複製(server/tray/assets/ 不再使用)。

6. 首次啟動警告匯總(使用者要看到的文件)

必須在以下位置寫清楚:

  1. README.mdGitHub / Gitea 發布頁)
  2. 下載頁Gitea Release 描述)
  3. 首次啟動歡迎頁(如果有的話,可跳過)

內容模板:

## 首次啟動提示

visionA-local 是內部工具,**沒有 Apple / Microsoft 的程式碼簽章**。
首次執行時作業系統可能會顯示警告,這是正常的。

### macOS
在 Finder 中找到 `visiona-local.app`**按右鍵 → 開啟**,在彈出對話框中選「開啟」。
之後可以正常雙擊開啟。

### Windows
執行安裝檔時若看到 "Windows 已保護您的電腦" 警告:
點「更多資訊」→「仍要執行」。

### Linux
AppImage 預設沒有執行權限:

chmod +x visiona-local-v1.0.0-linux-x64.AppImage ./visiona-local-v1.0.0-linux-x64.AppImage

7. 發布流程

步驟 負責 工具
1. Tag release 開發者 git tag v1.0.0 && git push --tags
2. CI build macOS GitHub Actions / local make installer-macos
3. CI build Windows GitHub Actions / local make installer-windows
4. CI build Linux GitHub Actions / Docker make installer-linux
5. 上傳到 Gitea Release 開發者 gh release create 或手動
6. 更新 latest.json(如果未來做 auto-update - 目前不做

不建置 universal / multi-arch,只有 x64。