Last active
April 27, 2021 16:10
-
-
Save hjeffrey/e0ec83b375e2860b21820c5d558fa687 to your computer and use it in GitHub Desktop.
Install ipa to Simulator of Xcode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- | |
-- 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