Skip to content

Instantly share code, notes, and snippets.

@hjeffrey
Last active April 27, 2021 16:10
Show Gist options
  • Save hjeffrey/e0ec83b375e2860b21820c5d558fa687 to your computer and use it in GitHub Desktop.
Save hjeffrey/e0ec83b375e2860b21820c5d558fa687 to your computer and use it in GitHub Desktop.
Install ipa to Simulator of Xcode
--
-- Project: Install IPA to Simulator
-- Author: Jeffrey Jia
-- Date: 2017 年 9 月 26 日
--
on open fileList
repeat with theFilePath in fileList
set fileInfo to info for file theFilePath
if name of fileInfo ends with ".ipa" then
--display alert "0. Drop File"
installIAP(theFilePath)
else
display alert "错误" message "文件类型错误,请选择 ipa 文件"
end if
end repeat
return
end open
-- 启动
set chooseIPAPath to (choose file of type {"ipa"} with prompt "选择 IPA 安装包" default location (path to «class desk» from user domain))
if chooseIPAPath is equal to false then
return
else
installIAP(chooseIPAPath)
end if
on installIAP(theIPAPath)
-- display alert "1. Will install"
set folderName to ".Simulator"
set SimulatorPath to makeTempFolder(folderName)
try
-- display alert "2. Maked Temp Folder"
set appRecord to getAppPathRecord(theIPAPath, SimulatorPath)
-- display alert "3. Getted App Path"
set mainAppList to appList of appRecord
if (count of mainAppList) is greater than 0 then
set watchAppList to watchAppList of appRecord
set uuidRecord to getSimulatorUUIDRecord(SimulatorPath, (count of watchAppList) is greater than 0)
-- display alert "4. Choosed device"
if uuidRecord is not equal to false then
simInstallApp(mainAppList, appUUID of uuidRecord)
-- display alert "5. Installed main app"
set watchUUID to watchUUID of uuidRecord
if (watchUUID is not equal to "") then
simInstallApp(watchAppList, watchUUID)
-- display alert "6. Installed apple watch app"
end if
else
cleanTempFolder(SimulatorPath)
return
end if
end if
end try
cleanTempFolder(SimulatorPath)
-- display alert "7. Cleaning Temp Folder"
set chooseButton to display dialog "是否需要启动模拟器?" buttons {"否", "是"} with title "安装完成" with icon note default button "是"
if (button returned of chooseButton is equal to "是") then
openSimulator()
--display alert "8. Open simulator"
else
--display alert "9. Will shutdown device"
shutdownSimulator(appUUID of uuidRecord)
if (watchUUID is not equal to "") then
shutdownSimulator(watchUUID)
end if
--display alert "10. Did shutdown device"
--display alert "安装完成"
end if
return
end installIAP
-- 创建缓存文件夹
on makeTempFolder(folderName)
do shell script "mkdir ~/Desktop/" & folderName
return (path to desktop folder as string) & folderName & ":" as alias
end makeTempFolder
-- 清理缓存文件夹
on cleanTempFolder(tempFolder)
do shell script "rm -rf " & POSIX path of tempFolder
end cleanTempFolder
-- 获取 ipa 文件中需要安装的 App 目录地址
on getAppPathRecord(theFilePath, unzipPath)
set appPath to POSIX path of theFilePath
do shell script "ditto -xk --sequesterRsrc --rsrc " & appPath & " " & (POSIX path of unzipPath)
set payloadPath to ((unzipPath as string) & "Payload:") as alias
set appList to list folder payloadPath without invisibles
repeat with theFile in appList
if (theFile contains ".app") then
set appPath to (payloadPath as string) & theFile
end if
end repeat
set appPathList to getAppListAtPath(appPath)
set watchPath to (appPath as string) & ":Watch:" as alias
set watchAppList to list folder watchPath without invisibles
repeat with theFile in watchAppList
if (theFile contains ".app") then
set watchAppPath to (watchPath as string) & theFile
end if
end repeat
set watchAppPathList to getAppListAtPath(watchAppPath)
return {appList:appPathList, watchAppList:watchAppPathList}
end getAppPathRecord
-- 从 app 的根目录排查,返回所有需要安装的目录列表
on getAppListAtPath(appRootPath)
set appPathList to {appRootPath}
set pluginListPath to (appRootPath as string) & ":PlugIns:" as alias
set appexList to list folder pluginListPath without invisibles
repeat with theFile in appexList
--if (theFile contains ".appex") then
set thePluginPath to (pluginListPath as string) & theFile
set end of appPathList to thePluginPath
--end if
end repeat
return appPathList
end getAppListAtPath
-- 从设备信息提取设备的 UUID
on getUUIDFromDevice(deviceInfo)
return do shell script "echo '" & deviceInfo & "' | sed 's/.\\{8\\}-.\\{4\\}-.\\{4\\}-.\\{4\\}-.\\{12\\}/{&}/' | sed 's/.*({//' | sed 's/}).*//'"
end getUUIDFromDevice
on getSDKVersion(sdkVersion)
return do shell script "echo '" & sdkVersion & "' | sed 's/--/\"/g'"
end getSDKVersion
on getDeviceMsg(deviceInfo)
return do shell script "echo '" & deviceInfo & "' | sed 's/(Shutdown)/ /' | sed 's/(Booted)/ /'"
end getDeviceMsg
-- 选择主设备 UUID 和 Apple watch 的 UUID
on getSimulatorUUIDRecord(targetPath, isNeedWatch)
do shell script "xcrun simctl list > " & (POSIX path of targetPath) & "device.txt"
set deviceFile to (targetPath as string) & "device.txt" as alias
set contentList to read deviceFile using delimiter "
"
set deviceList to {}
set watchDeviceList to {}
repeat with theDevice in contentList
if (theDevice begins with "-- ") then
if theDevice contains "Unavailable" then
else if (theDevice contains "watchOS") then
set end of watchDeviceList to "以下是 " & getSDKVersion(theDevice) & " 的设备列表(请勿选择此项!)"
else
set end of deviceList to "以下是 " & getSDKVersion(theDevice) & " 的设备列表(请勿选择此项!)"
end if
else if (theDevice begins with " iPhone") or (theDevice begins with " iPad") or (theDevice begins with " Apple TV") then
if theDevice contains "unavailable" then
-- do nothing
else
set end of deviceList to getDeviceMsg(theDevice as string)
end if
else if (theDevice begins with " Apple Watch") then
set end of watchDeviceList to getDeviceMsg(theDevice as string)
end if
end repeat
set needChooseDevice to true
set chooseDevice to ""
repeat while needChooseDevice
set chooseResut to choose from list deviceList with title "安装到 iPhone, iPad 或者 Apple TV" with prompt "选择模拟器,注意区分 iOS 版本和设备类型"
if chooseResut is equal to false then
set needChooseDevice to false
return false
else
set chooseDevice to chooseResut as string
if (chooseDevice begins with "-- ") then
display alert "请勿选择提示信息项!"
else
set needChooseDevice to false
end if
end if
end repeat
set deviceUUID to getUUIDFromDevice(chooseDevice)
set watchDeviceUUID to ""
if isNeedWatch then
set needChooseDevice to true
set chooseDevice to ""
repeat while needChooseDevice
set chooseResut to choose from list watchDeviceList with title "安装到 Apple Watch" with prompt "选择模拟器,注意区分 iOS 版本和设备类型。选择“取消”则不安装 Watch App"
if chooseResut is equal to false then
set needChooseDevice to false
else
set chooseDevice to chooseResut as string
if (chooseDevice begins with "-- ") then
display alert "请勿选择提示信息项!"
else
set needChooseDevice to false
end if
end if
end repeat
end if
if (chooseDevice is equal to "") then
--
else
set watchDeviceUUID to getUUIDFromDevice(chooseDevice)
end if
return {appUUID:deviceUUID, watchUUID:watchDeviceUUID}
end getSimulatorUUIDRecord
-- 指定设备安装指定的 app
on simInstallApp(appPathList, deviceUUID)
try
do shell script "xcrun simctl boot '" & deviceUUID & "'"
on error errorMsg number errorNum
if errorNum is equal to 164 then
-- booted
else
display dialog ("Error number " & errorNum as string) & ": " & errorMsg
end if
end try
set cmdInstallApp to "xcrun simctl install '" & deviceUUID & "' "
repeat with appPath in appPathList
set cmdInstallApp to (cmdInstallApp & (POSIX path of appPath) & " ")
end repeat
-- display alert cmdInstallApp
do shell script cmdInstallApp
end simInstallApp
-- 启动模拟器
on openSimulator()
try
set XcodePath to do shell script "xcode-select -p"
do shell script "open " & XcodePath & "/Applications/Simulator.app"
on error
set XcodePath to (choose file of type {"app"} with prompt "选择 Xcode" default location (path to «class desk» from user domain))
try
do shell script "open " & (POSIX path of XcodePath) & "Contents/Developer/Applications/Simulator.app"
on error errorMsg number errorNum
if errorMsg contains "does not exist" then
display alert "未找到模拟器,程序退出"
end if
end try
end try
end openSimulator
on shutdownSimulator(deviceUUID)
do shell script "xcrun simctl shutdown '" & deviceUUID & "'"
end shutdownSimulator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment