update: 同步 emu* 脚本至 einz 最新版
- emuResolveIos.js:裸跑时 Booted 优先、否则取系统版本最高的 iPhone; EMU 环境变量最高优先;短名表扩至 ip17 系列;修复 rootDir 指向错误 导致项目 config 永远读不到的问题 - emuBootIos.sh:Xcode 27+ 不再随附 Simulator.app,检测后跳过并提示 DeviceHub 来源:~/einz/scripts/(拷贝后 einz 侧持续演进,此处为落后快照) Co-Authored-By: AtomCode (glm5.3-flash) <[email protected]>
This commit is contained in:
+12
-2
@@ -9,7 +9,7 @@
|
||||
# npm run app-ios-boot -- FF429526-A7EE-… # 直接给 UDID
|
||||
# [email protected] npm run app-ios-boot # 用环境变量改默认
|
||||
#
|
||||
# 短名表见 emuResolveIos.js 的 builtinAlias(ip16 / ip16plus / ip16pro / ip16pm),
|
||||
# 短名表见 scripts/emuResolveIos.js 的 builtinAlias(ip16 / ip16plus / ip16pro / ip16pm),
|
||||
# 也可以在 package.json 的 config 里加("ipad": "iPad Pro 13-inch (M4)")。
|
||||
#
|
||||
# 跑 App 永远打「当前已启动的那台」(纯 booted 语义):
|
||||
@@ -27,5 +27,15 @@ if xcrun simctl boot "${udid}" 2>/dev/null; then
|
||||
else
|
||||
echo "(已在运行,跳过 boot)"
|
||||
fi
|
||||
open "$(xcode-select -p)/Applications/Simulator.app"
|
||||
# Xcode 27 起不再随附 Simulator.app(simctl 独立工作);模拟器 GUI 改由
|
||||
# DeviceHub(Xcode.app/Contents/Applications/DeviceHub.app)承担——有就开它,
|
||||
# 没有就跳过(flutter run 也会自己唤起模拟器窗口)。
|
||||
SIM_APP="$(xcode-select -p)/Applications/Simulator.app"
|
||||
if [ -d "$SIM_APP" ]; then
|
||||
open "$SIM_APP"
|
||||
else
|
||||
echo "(本机 Xcode 无 Simulator.app(Xcode 27+ 已移除),跳过开 GUI)"
|
||||
echo " 看模拟器界面:open -b com.apple.dt.Devices # DeviceHub"
|
||||
echo " 或直接 flutter run,会自动把模拟器窗口带到前台"
|
||||
fi
|
||||
xcrun simctl list devices booted
|
||||
|
||||
+78
-10
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
// 把「短名@系统版本」解析成本机真实存在的模拟器 UDID(供 emuBootIos.sh 调用)。
|
||||
//
|
||||
// node emuResolveIos.js [email protected] # 短名(见下面别名表)
|
||||
// node emuResolveIos.js "iPhone [email protected]" # 写机型全名也行
|
||||
// node emuResolveIos.js "iPhone 16" # 不给版本 → 取系统版本最高的那台
|
||||
// node emuResolveIos.js FF429526-… # 本来就是 UDID → 原样返回
|
||||
// node scripts/emuResolveIos.js [email protected] # 短名(见下面别名表)
|
||||
// node scripts/emuResolveIos.js "iPhone [email protected]" # 写机型全名也行
|
||||
// node scripts/emuResolveIos.js "iPhone 16" # 不给版本 → 取系统版本最高的那台
|
||||
// node scripts/emuResolveIos.js FF429526-… # 本来就是 UDID → 原样返回
|
||||
//
|
||||
// 为什么不用 UDID:UDID 是每台 Mac 各自生成的,换台机器就失效。
|
||||
// 机型名 + 系统版本是 Xcode 自带的,任何机器上都能查到,所以跨机器可移植。
|
||||
@@ -16,10 +16,35 @@ const { execSync } = require('child_process')
|
||||
const path = require('path')
|
||||
|
||||
const builtinAlias = {
|
||||
ipxr: 'iPhone XR',
|
||||
ipxs: 'iPhone Xs',
|
||||
ip11: 'iPhone 11',
|
||||
ip11pro: 'iPhone 11 Pro',
|
||||
ip11pm: 'iPhone 11 Pro Max',
|
||||
ip12: 'iPhone 12',
|
||||
ip12mini: 'iPhone 12 mini',
|
||||
ip12pro: 'iPhone 12 Pro',
|
||||
ip12pm: 'iPhone 12 Pro Max',
|
||||
ip13: 'iPhone 13',
|
||||
ip13mini: 'iPhone 13 mini',
|
||||
ip13pro: 'iPhone 13 Pro',
|
||||
ip13pm: 'iPhone 13 Pro Max',
|
||||
ip14: 'iPhone 14',
|
||||
ip14plus: 'iPhone 14 Plus',
|
||||
ip14pro: 'iPhone 14 Pro',
|
||||
ip14pm: 'iPhone 14 Pro Max',
|
||||
ip15: 'iPhone 15',
|
||||
ip15plus: 'iPhone 15 Plus',
|
||||
ip15pro: 'iPhone 15 Pro',
|
||||
ip15pm: 'iPhone 15 Pro Max',
|
||||
ip16: 'iPhone 16',
|
||||
ip16plus: 'iPhone 16 Plus',
|
||||
ip16pro: 'iPhone 16 Pro',
|
||||
ip16pm: 'iPhone 16 Pro Max',
|
||||
ip17: 'iPhone 17',
|
||||
ip17pro: 'iPhone 17 Pro',
|
||||
ip17pm: 'iPhone 17 Pro Max',
|
||||
ip17air: 'iPhone Air'
|
||||
}
|
||||
|
||||
const rootDir = path.resolve(__dirname, '..')
|
||||
@@ -30,9 +55,13 @@ try {
|
||||
pkgConfig = {}
|
||||
}
|
||||
|
||||
const input = (process.argv[2] || '').trim() || String(pkgConfig.defaultIosEmu || '[email protected]').trim()
|
||||
const input =
|
||||
(process.argv[2] || '').trim() ||
|
||||
String(process.env.EMU || pkgConfig.defaultIosEmu || '').trim()
|
||||
|
||||
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(input)) {
|
||||
if (
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(input)
|
||||
) {
|
||||
console.log(input)
|
||||
process.exit(0)
|
||||
}
|
||||
@@ -48,13 +77,48 @@ const version =
|
||||
.replace(/^iOS\s*/i, '')
|
||||
const deviceName = pkgConfig[left] || builtinAlias[left.toLowerCase()] || left
|
||||
|
||||
const json = JSON.parse(execSync('xcrun simctl list devices available -j').toString())
|
||||
const runtimeKeyFor = (want) => `iOS-${want.replace(/\./g, '-')}`
|
||||
const versionOf = (runtimeKey) => {
|
||||
const json = JSON.parse(
|
||||
execSync('xcrun simctl list devices available -j').toString()
|
||||
)
|
||||
|
||||
// 辅助函数放在**所有使用之前**:下面 `if (!input)` 分支在模块顶层就跑
|
||||
// sort,比较器立刻调用 versionOf——const 声明若在使用之后会触发 TDZ
|
||||
// (ReferenceError: Cannot access 'versionOf' before initialization,
|
||||
// 2026-10-12 老板实测)。
|
||||
const runtimeKeyFor = want => `iOS-${want.replace(/\./g, '-')}`
|
||||
const versionOf = runtimeKey => {
|
||||
const matched = runtimeKey.match(/iOS-(\d+)(?:-(\d+))?/)
|
||||
return matched ? [Number(matched[1]), Number(matched[2] || 0)] : [0, 0]
|
||||
}
|
||||
|
||||
// 空规格(裸 npm run app-ios-boot):有 Booted 直接用它;否则挑可用的
|
||||
// iPhone 里系统版本最高的那台——任何机器上都能裸跑,不再钉死某机型。
|
||||
if (!input) {
|
||||
const all = []
|
||||
for (const [runtimeKey, devices] of Object.entries(json.devices)) {
|
||||
if (!/iOS-/.test(runtimeKey)) continue
|
||||
for (const d of devices) all.push({ ...d, runtimeKey })
|
||||
}
|
||||
const booted = all.find(d => d.state === 'Booted')
|
||||
if (booted) {
|
||||
console.log(booted.udid)
|
||||
process.exit(0)
|
||||
}
|
||||
const iPhones = all.filter(d => /iPhone/i.test(d.name))
|
||||
if (iPhones.length === 0) {
|
||||
console.error('❌ 本机没有可用的 iPhone 模拟器')
|
||||
console.error(' 看有哪些:xcrun simctl list devices available')
|
||||
process.exit(1)
|
||||
}
|
||||
iPhones.sort((a, b) => {
|
||||
const [aMajor, aMinor] = versionOf(a.runtimeKey)
|
||||
const [bMajor, bMinor] = versionOf(b.runtimeKey)
|
||||
return bMajor - aMajor || bMinor - aMinor
|
||||
})
|
||||
console.log(iPhones[0].udid)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const matched = []
|
||||
for (const [runtimeKey, devices] of Object.entries(json.devices)) {
|
||||
if (!/iOS-/.test(runtimeKey)) {
|
||||
@@ -71,7 +135,11 @@ for (const [runtimeKey, devices] of Object.entries(json.devices)) {
|
||||
}
|
||||
|
||||
if (matched.length === 0) {
|
||||
console.error(`❌ 本机没有匹配的模拟器:${input}(机型「${deviceName}」${version ? ` + iOS ${version}` : ''})`)
|
||||
console.error(
|
||||
`❌ 本机没有匹配的模拟器:${input}(机型「${deviceName}」${
|
||||
version ? ` + iOS ${version}` : ''
|
||||
})`
|
||||
)
|
||||
console.error(' 看有哪些:xcrun simctl list devices available')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user