Files
ios-location-track/scripts/build.ps1
T

183 lines
7.7 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# iOS 虚拟定位轨迹工具 —— Windows 构建脚本
#
# 产出:
# dist\iOSLocationTrack\iOSLocationTrack.exe 绿色版(直接双击运行)
# dist\installer\iOSLocationTrack-1.1.1_win-setup.exe 安装包(需要 Inno Setup 6)
#
# 用法(在项目根目录):
# .\scripts\build.ps1 # 打包 exe + 安装包(若装了 Inno Setup)
# .\scripts\build.ps1 -NoInstaller # 只打包 exe
# .\scripts\build.ps1 -SkipTests # 跳过测试
#
# 前置:
# 1. 已运行过 .\scripts\run.ps1(或手动建好 .venv 并装好依赖)
# 2. 图标:resources\AppIcon.ico(缺失时自动用 tools\make_ico.py 生成)
# 3. 开发者镜像:resources\ddi\personalized\Image.dmg(缺失时自动下载)
# 4. Inno Setup 6(可选):winget install -e --id JRSoftware.InnoSetup
[CmdletBinding()]
param(
[switch]$NoInstaller,
[switch]$SkipTests,
[switch]$SkipIcon,
[switch]$SkipDdi
)
$ErrorActionPreference = 'Stop'
function Write-Bold { param($m) Write-Host "`n=== $m ===" -ForegroundColor White }
function Write-Ok { param($m) Write-Host " [OK] $m" -ForegroundColor Green }
function Write-Warn { param($m) Write-Host " [!!] $m" -ForegroundColor Yellow }
function Write-Fail { param($m) Write-Host " [XX] $m" -ForegroundColor Red }
$Root = Split-Path -Parent $PSScriptRoot
Set-Location $Root
$VenvPy = Join-Path $Root '.venv\Scripts\python.exe'
if (-not (Test-Path $VenvPy)) {
Write-Fail "找不到 $VenvPy。请先运行 .\scripts\run.ps1 创建环境。"
exit 1
}
# ---------- 0. 构建依赖 ----------
Write-Bold "0. 构建依赖"
& $VenvPy -c "import PyInstaller, PIL" 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Warn "缺少 PyInstaller / Pillow,正在安装…"
$idx = if ($env:IOSLOC_PIP_INDEX) { $env:IOSLOC_PIP_INDEX } else { 'https://mirrors.aliyun.com/pypi/simple/' }
& $VenvPy -m pip install --disable-pip-version-check -i $idx pyinstaller pillow
if ($LASTEXITCODE -ne 0) { Write-Fail "构建依赖安装失败"; exit 1 }
}
Write-Ok "PyInstaller / Pillow 就绪"
# ---------- 0.5 脚本编码自检(.ps1 必须 UTF-8 with BOM)----------
# Windows PowerShell 5.1 只有看到 BOM 才按 UTF-8 解析 .ps1;否则按系统 ANSI 代码页读,
# 结果是中文全部乱码并**直接语法报错**(The string is missing the terminator),脚本根本跑不起来。
# 不少编辑器/工具保存时会静默丢掉 BOM,所以这里自动补回,避免"改个注释就构建不了"。
$bomFixed = @()
foreach ($script in Get-ChildItem (Join-Path $PSScriptRoot '*.ps1')) {
$bytes = [System.IO.File]::ReadAllBytes($script.FullName)
$hasBom = $bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF
if (-not $hasBom) {
$text = [System.IO.File]::ReadAllText($script.FullName, [System.Text.UTF8Encoding]::new($false))
[System.IO.File]::WriteAllText($script.FullName, $text, [System.Text.UTF8Encoding]::new($true))
$bomFixed += $script.Name
}
}
if ($bomFixed.Count -gt 0) {
Write-Warn "已为下列脚本补回 UTF-8 BOM:$($bomFixed -join '、')(下次编辑请保留 BOM)"
} else {
Write-Ok ".ps1 编码正常(UTF-8 with BOM)"
}
# ---------- 1. 图标 ----------
if (-not $SkipIcon) {
Write-Bold "1. Windows 图标(.ico)"
if ((Test-Path 'resources\AppIcon.ico') -and
((Get-Item 'resources\AppIcon.ico').LastWriteTime -gt (Get-Item 'resources\AppIcon.iconset').LastWriteTime)) {
Write-Ok "resources\AppIcon.ico 已是最新"
} else {
& $VenvPy tools\make_ico.py
if ($LASTEXITCODE -ne 0) { Write-Fail "图标生成失败"; exit 1 }
}
}
# ---------- 2. 开发者镜像 ----------
if (-not $SkipDdi) {
Write-Bold "2. 开发者镜像素材"
$imageDmg = 'resources\ddi\personalized\Image.dmg'
if (Test-Path $imageDmg) {
$mb = [math]::Round((Get-Item $imageDmg).Length / 1MB, 2)
Write-Ok "$imageDmg 已存在($mb MB)"
} else {
Write-Warn "$imageDmg 缺失(仓库中不入库),正在下载…"
& $VenvPy tools\fetch_ddi.py --personalized-only
if (-not (Test-Path $imageDmg)) {
Write-Fail "镜像下载失败。iOS 17+ 挂载会退化为在线获取,打包产物不完整。"
Write-Fail "可稍后重试:$VenvPy tools\fetch_ddi.py --personalized-only"
exit 1
}
}
}
# ---------- 3. 测试 ----------
if (-not $SkipTests) {
Write-Bold "3. 测试(无需设备)"
$failed = 0
foreach ($t in @('tests\selftest.py', 'tests\drift_sim.py', 'tests\offline_tiles.py')) {
Write-Host " --- $t"
& $VenvPy $t 2>&1 | Select-Object -Last 3
if ($LASTEXITCODE -ne 0) { $failed++; Write-Fail "$t 失败" }
}
if ($failed -gt 0) { Write-Fail "$failed 个测试套件失败,已中止打包"; exit 1 }
Write-Ok "全部测试通过"
}
# ---------- 4. PyInstaller ----------
Write-Bold "4. 打包 exe(onedir + requireAdministrator 清单)"
if (Test-Path 'dist\iOSLocationTrack') { Remove-Item 'dist\iOSLocationTrack' -Recurse -Force }
& $VenvPy -m PyInstaller --clean --noconfirm Location.spec
if ($LASTEXITCODE -ne 0) { Write-Fail "PyInstaller 打包失败"; exit 1 }
$exe = 'dist\iOSLocationTrack\iOSLocationTrack.exe'
if (-not (Test-Path $exe)) { Write-Fail "未生成 $exe"; exit 1 }
$sizeMb = [math]::Round(((Get-ChildItem 'dist\iOSLocationTrack' -Recurse -File |
Measure-Object Length -Sum).Sum / 1MB), 1)
Write-Ok "$exe(整包 $sizeMb MB)"
# ---------- 5. 校验清单里的 requireAdministrator ----------
Write-Bold "5. 校验 exe 是否请求管理员权限"
$manifestOk = $false
try {
# manifest 嵌在 exe 资源里;用 findstr 直接找 UTF-8 明文即可
$bytes = [System.IO.File]::ReadAllBytes((Resolve-Path $exe))
$text = [System.Text.Encoding]::UTF8.GetString($bytes)
if ($text -match 'requireAdministrator') {
$manifestOk = $true
Write-Ok "清单包含 requireAdministrator(启动时会弹 UAC)"
}
} catch { }
if (-not $manifestOk) {
Write-Warn "未能在 exe 中确认 requireAdministrator —— 请手动确认 Location.spec 的 uac_admin=True"
}
# ---------- 6. Inno Setup ----------
if ($NoInstaller) {
Write-Bold "6. 跳过安装包(-NoInstaller)"
} else {
Write-Bold "6. 制作安装包(Inno Setup)"
$iscc = $null
foreach ($candidate in @(
"${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe",
"$env:ProgramFiles\Inno Setup 6\ISCC.exe",
"$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe",
"$env:LOCALAPPDATA\Inno Setup 6\ISCC.exe"
)) {
if ($candidate -and (Test-Path $candidate)) { $iscc = $candidate; break }
}
if (-not $iscc) {
$cmd = Get-Command ISCC.exe -ErrorAction SilentlyContinue
if ($cmd) { $iscc = $cmd.Source }
}
if (-not $iscc) {
Write-Warn "未找到 Inno Setup 6,跳过安装包。"
Write-Warn "安装:winget install -e --id JRSoftware.InnoSetup"
Write-Warn "然后重跑:.\scripts\build.ps1 -SkipTests -SkipIcon -SkipDdi"
} else {
Write-Host " 使用 $iscc"
& $iscc 'installer\iosloc.iss'
if ($LASTEXITCODE -ne 0) { Write-Fail "Inno Setup 编译失败"; exit 1 }
Get-ChildItem 'dist\installer\*.exe' | ForEach-Object {
Write-Ok "$($_.FullName)($([math]::Round($_.Length/1MB,1)) MB)"
}
}
}
Write-Bold "完成"
Write-Host " 绿色版:dist\iOSLocationTrack\iOSLocationTrack.exe"
if (Test-Path 'dist\installer') {
Get-ChildItem 'dist\installer\*.exe' -ErrorAction SilentlyContinue | ForEach-Object {
Write-Host " 安装包:$($_.FullName)"
}
}
Write-Host "`n 提示:exe 启动时会请求管理员权限(用于首次自动安装 Apple Mobile Device Support)。"