app安裝到 iOS 模擬器

一.應(yīng)用場(chǎng)景

先來談?wù)勈鞘裁辞闆r下,會(huì)有在模擬器上安裝app的需求。

在一個(gè)大公司里,對(duì)源碼的管理有嚴(yán)格的制度,非開發(fā)人員是沒有權(quán)限接觸到源碼的。對(duì)蘋果的開發(fā)證書管理也非常嚴(yán)格,甚至連開發(fā)人員也沒有發(fā)布證書,證書只在持續(xù)集成環(huán)境或者Appstore產(chǎn)線里面,或者只在最后打包上架的人手上。

那么現(xiàn)在就有這樣的需求,開發(fā)人員搭建好UI以后,要把開發(fā)完成的Alapha版給到UI設(shè)計(jì)師那邊去評(píng)審,看看是否完全達(dá)到要求,達(dá)不到要求就需要打回來重做。

一般做法就是直接拿手機(jī)去安裝一遍了。直接真機(jī)看效果。不過要是設(shè)計(jì)師和開發(fā)不在同一個(gè)地方的公司,一個(gè)在北京一個(gè)在上海,這種就沒法安裝了。源碼又無法導(dǎo)出給設(shè)計(jì)師,讓他運(yùn)行一下Xcode跑一下模擬器。打release的ipa通過掃碼安裝,如果公司大了,UDID全部都用完了,也沒法安裝。這個(gè)時(shí)候就比較麻煩了。(一般也沒人遇到這么蛋疼的事情吧)

那么現(xiàn)在就有給模擬器安裝app的需求了,那開發(fā)人員如何能把開發(fā)版的app給打包出來給其他模擬器安裝呢?

二.解決辦法

解決思路,想要?jiǎng)e人的模擬器運(yùn)行起我們開發(fā)的app,最簡(jiǎn)單的辦法就是把我們DerivedData的數(shù)據(jù)直接拷貝到別人模擬器上面,就可以了。當(dāng)然還要考慮到設(shè)計(jì)師也許并不會(huì)一些命令行命令,我們的操作越傻瓜越好。

1.拷貝本地的DerivedData里面的debug包

Mac的拷貝命令有cp和ditto,建議用ditto進(jìn)行拷貝工作。

Usage: ditto [] src [ ... src ] dst are any of:

? ? -h? ? ? ? ? ? ? ? ? ? ? ? print full usage

? ? -v? ? ? ? ? ? ? ? ? ? ? ? print a line of status for each source copied

? ? -V? ? ? ? ? ? ? ? ? ? ? ? print a line of status for every file copied

? ? -X? ? ? ? ? ? ? ? ? ? ? ? do not descend into directories with a different device ID

? ? -c? ? ? ? ? ? ? ? ? ? ? ? create an archive at dst (by default CPIO format)

? ? -x? ? ? ? ? ? ? ? ? ? ? ? src(s) are archives

? ? -z? ? ? ? ? ? ? ? ? ? ? ? gzip compress CPIO archive

? ? -j? ? ? ? ? ? ? ? ? ? ? ? bzip2 compress CPIO archive

? ? -k? ? ? ? ? ? ? ? ? ? ? ? archives are PKZip

? ? --keepParent? ? ? ? ? ? ? parent directory name src is embedded in dst_archive

? ? --arch archVal? ? ? ? ? ? fat files will be thinned to archVal

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? multiple -arch options can be specified

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? archVal should be one of "ppc", "i386", etc

? ? --bom bomFile? ? ? ? ? ? ? only objects present in bomFile are copied

? ? --norsrc? ? ? ? ? ? ? ? ? don't preserve resource data

? ? --noextattr? ? ? ? ? ? ? ? don't preserve extended attributes

? ? --noqtn? ? ? ? ? ? ? ? ? ? don't preserve quarantine information

? ? --noacl? ? ? ? ? ? ? ? ? ? don't preserve ACLs

? ? --sequesterRsrc? ? ? ? ? ? copy resources via polite directory (PKZip only)

? ? --nocache? ? ? ? ? ? ? ? ? don't use filesystem cache for reads/writes

? ? --hfsCompression? ? ? ? ? compress files at destination if appropriate

? ? --nopreserveHFSCompression don't preserve HFS+ compression when copying files

? ? --zlibCompressionLevel num use compression level 'num' when creating a PKZip archive

? ? --password? ? ? ? ? ? ? ? request password for reading from encrypted PKZip archive

Ditto比cp命令更好的地方在于:

它在復(fù)制過程中不僅能保留源文件或者文件夾的屬性與權(quán)限,還能保留源文件的資源分支結(jié)構(gòu)和文件夾的源結(jié)構(gòu)。

此命令能確保文件或者文件夾被如實(shí)復(fù)制。

如果目標(biāo)文件或者文件夾不存在,ditto將直接復(fù)制過去或創(chuàng)建新的文件和文件夾,相反,對(duì)于已經(jīng)存在的文件,命令將與目標(biāo)文件(夾)合并。

ditto還能提供完整符號(hào)鏈接。

那么我們就拷貝出本地的debug包

ditto -ck --sequesterRsrc --keepParent `ls -1 -d -t ~/Library/Developer/Xcode/DerivedData/*/Build/Products/*-iphonesimulator/*.app | head -n 1` /Users/YDZ/Desktop/app.zip

有幾點(diǎn)需要說明的:

上面命令最后一個(gè)路徑(/Users/YDZ/Desktop/app.zip),這個(gè)是自定義的,我這里舉的例子是直接放在桌面。除了這里改一下路徑,前面的都不需要改,包括 * 也都不用改。

再來說一下命令里面的 * 的問題。當(dāng)我們打開自己本地的~/Library/Developer/Xcode/DerivedData/ ,這個(gè)路徑下,會(huì)發(fā)現(xiàn)里面裝的都是在我們本地模擬器上運(yùn)行過的app程序。前面是app的Bundle Identifier,橫線后面是一堆字符串。上面的ditto里面帶 * 的那個(gè)路徑是為了動(dòng)態(tài)匹配一個(gè)地址的,* 在這里也是一個(gè)通配符。后面的head說明了匹配的規(guī)則。head其實(shí)是找出最近一次我們運(yùn)行模擬器的app的路徑。

為了保證我們打包是正確的,建議先運(yùn)行一下我們要打包的app,一般我們Scheme里面的Run都是debug product(如果這里有更改,那就改成對(duì)應(yīng)debug的Scheme),確保是我們要給設(shè)計(jì)師審核的app,之后再運(yùn)行這個(gè)ditto命令。

2.把debug包拷貝到另一個(gè)模擬器中

我們運(yùn)行完上面的ditto命令會(huì)產(chǎn)生一個(gè)zip文件,解壓出來,會(huì)得到一個(gè)app文件,這個(gè)就是debug包了。debug包就是我們要給設(shè)計(jì)師的app包了。

如何能讓設(shè)計(jì)師傻瓜式的安裝這個(gè)app呢?

這里介紹一個(gè)命令行工具,ios-sim命令行工具。

ios-sim 是一個(gè)可以在命令控制iOS模擬器的工具。利用這個(gè)命令,我們可以啟動(dòng)一個(gè)模擬器,安裝app,啟動(dòng)app,查詢iOS SDK。它可以使我們像自動(dòng)化測(cè)試一樣不用打開Xcode。

不過 ios-sim 只支持Xcode 6 以后的版本。

安裝ios-sim

? ? $ npm install ios-sim -g

說明文檔:

Usage: ios-sim[--args ...]? ? Commands:? ? ? showsdks? ? ? ? ? ? ? ? ? ? ? ? List the available iOS SDK versions? ? ? showdevicetypes? ? ? ? ? ? ? ? List the available device types? ? ? launchLaunch the application at the specified path on the iOS Simulator? ? ? start? ? ? ? ? ? ? ? ? ? ? ? ? Launch iOS Simulator without an app? ? ? installInstall the application at the specified path on the iOS Simulator without launching the app? ? Options:? ? ? --version? ? ? ? ? ? ? ? ? ? ? Print the version of ios-sim? ? ? --help? ? ? ? ? ? ? ? ? ? ? ? ? Show this help text? ? ? --exit? ? ? ? ? ? ? ? ? ? ? ? ? Exit after startup? ? ? --logThe path where log of the app running in the Simulator will be redirected to? ? ? --devicetypeidThe id of the device type that should be simulated (Xcode6+). Use 'showdevicetypes' to list devices.? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? e.g "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone6, 8.0"? ? Removed in version 4.x:? ? ? --stdoutThe path where stdout of the simulator will be redirected to (defaults to stdout of ios-sim)? ? ? --stderrThe path where stderr of the simulator will be redirected to (defaults to stderr of ios-sim)? ? ? --sdkThe iOS SDK version to run the application on (defaults to the latest)? ? ? --familyThe device type that should be simulated (defaults to `iphone')? ? ? --retina? ? ? ? ? ? ? ? ? ? ? ? Start a retina device? ? ? --tall? ? ? ? ? ? ? ? ? ? ? ? ? In combination with --retina flag, start the tall version of the retina device (e.g. iPhone 5 (4-inch))? ? ? --64bit? ? ? ? ? ? ? ? ? ? ? ? In combination with --retina flag and the --tall flag, start the 64bit version of the tall retina device (e.g. iPhone 5S (4-inch 64bit))? ? Unimplemented in this version:? ? ? --verbose? ? ? ? ? ? ? ? ? ? ? Set the output level to verbose? ? ? --timeoutThe timeout time to wait for a response from the Simulator. Default value: 30 seconds? ? ? --args <...>? ? ? ? ? ? ? ? ? ? All following arguments will be passed on to the application? ? ? --env? A plist file containing environment key-value pairs that should be set

? ? ? --setenv NAME=VALUE? ? ? ? ? ? Set an environment variable

用法不難

ios-sim launch /Users/YDZ/Desktop/app.app --devicetypeid iPhone-6s

其中,/Users/YDZ/Desktop/app.app這個(gè)是設(shè)計(jì)師收到app之后的路徑。--devicetypeid參數(shù)后面是給定一個(gè)模擬器的版本。

只需要把上面的命令發(fā)給設(shè)計(jì)師,無腦粘貼到命令行,裝好app的模擬器就會(huì)自動(dòng)啟動(dòng),打開app了。

三.額外的嘗試

好奇的同學(xué)肯定不會(huì)滿足只給模擬器安裝debug包吧,既然可以不用代碼就可以給模擬器安裝app,那我們能安裝release包么?我好奇的嘗試了一下。

先從Appstore上面下載最新的微信,把ipa后綴改成zip,解壓,把Payload文件夾里面的“WeChat”取出來,然后運(yùn)行ios-sim命令。

結(jié)果微信確實(shí)是安裝到了模擬器了。不過一點(diǎn)擊app,看見了月亮界面就退出了。控制臺(tái)打印了一堆信息。

An error was encountered processing the command (domain=FBSOpenApplicationErrorDomain, code=1):The operation couldn’t be completed. (FBSOpenApplicationErrorDomain error 1.)Aug 18 16:29:17 YDZdeMacBook-Pro nsurlsessiond[19213]: Task 1 for client{contents = "com.apple.mobileassetd"} completed with error - code: -999Aug 18 16:29:17 YDZdeMacBook-Pro com.apple.CoreSimulator.SimDevice.D6BD3967-9BC4-4A8D-9AD0-23176B22B12A.launchd_sim[19096] (UIKitApplication:com.tencent.xin[0xdf6d][19774]): Program specified by service does not contain one of the requested architectures:Aug 18 16:29:17 YDZdeMacBook-Pro SpringBoard[19181]: Unable to get pid for 'UIKitApplication:com.tencent.xin[0xdf6d]': No such process (err 3)Aug 18 16:29:17 YDZdeMacBook-Pro SpringBoard[19181]: Bootstrapping failed forAug 18 16:29:17 YDZdeMacBook-Pro SpringBoard[19181]: Unable to delete job with label UIKitApplication:com.tencent.xin[0xdf6d]. Error: Operation now in progressAug 18 16:29:17 YDZdeMacBook-Pro SpringBoard[19181]: Application 'UIKitApplication:com.tencent.xin[0xdf6d]' exited for an unknown reason.Aug 18 16:29:17 YDZdeMacBook-Pro com.apple.CoreSimulator.SimDevice.D6BD3967-9BC4-4A8D-9AD0-23176B22B12A.launchd_sim[19096] (UIKitApplication:com.tencent.xin[0xdf6d][19774]): Trampoline was terminated before jumping to service: Killed: 9Aug 18 16:29:18 YDZdeMacBook-Pro fileproviderd[19169]: (Note ) FileProvider: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/FileProvider.framework/Support/fileproviderd starting.Aug 18 16:29:20 YDZdeMacBook-Pro pkd[19238]: assigning plug-in com.apple.ServerDocuments.ServerFileProvider(1.0) to plugin sandboxAug 18 16:29:20 YDZdeMacBook-Pro pkd[19238]: enabling pid=19169 for plug-in com.apple.ServerDocuments.ServerFileProvider(1.0) D12B6280-6DF1-434C-9BAA-BD9B0D0FB756 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/Applications/ServerDocuments.app/PlugIns/ServerFileProvider.appexAug 18 16:29:22 YDZdeMacBook-Pro SpringBoard[19181]: Weekly asset update check did fire (force=NO)Aug 18 16:29:22 YDZdeMacBook-Pro SpringBoard[19181]: Beginning check for asset updates (force: 0Aug 18 16:29:22 YDZdeMacBook-Pro SpringBoard[19181]: Did not complete check for asset updates (force: 0, isVoiceOverRunning: 0Aug 18 16:29:23 YDZdeMacBook-Pro mstreamd[19171]: (Note ) mstreamd: mstreamd starting up.Aug 18 16:29:23 YDZdeMacBook-Pro DTServiceHub[19191]: DTServiceHub(19191) [error]: 'mach_msg_send' failed: (ipc/send) invalid destination port (268435459)Aug 18 16:29:25 YDZdeMacBook-Pro itunesstored[19744]: iTunes Store environment is: MR22Aug 18 16:29:25 YDZdeMacBook-Pro itunesstored[19744]: Normal message received by listener connection. Ignoring.Aug 18 16:29:25 --- last message repeated 1 time ---Aug 18 16:29:25 YDZdeMacBook-Pro mstreamd[19171]: (Note ) PS: The subscription plugin class does not support push notification refreshing.Aug 18 16:29:25 YDZdeMacBook-Pro itunesstored[19744]: libMobileGestalt MGIOKitSupport.c:387: value for udid-version property of IODeviceTree:/product is invalid ((null))Aug 18 16:29:25 YDZdeMacBook-Pro itunesstored[19744]: Normal message received by listener connection. Ignoring.Aug 18 16:29:25 YDZdeMacBook-Pro itunesstored[19744]: libMobileGestalt MGBasebandSupport.c:60: _CTServerConnectionCopyMobileEquipmentInfo: CommCenter error: 1:45 (Operation not supported)Aug 18 16:29:25 YDZdeMacBook-Pro itunesstored[19744]: libMobileGestalt MGBasebandSupport.c:189: No CT mobile equipment info dictionary while fetching kCTMobileEquipmentInfoIMEIAug 18 16:29:26 YDZdeMacBook-Pro mstreamd[19171]: (Note ) PS: Media stream daemon starting...Aug 18 16:29:27 YDZdeMacBook-Pro itunesstored[19744]: UpdateAssetsOperation: Error downloading manifest from URL https://apps.itunes.com/files/ios-music-app/: Error Domain=SSErrorDomain Code=109 "無法連接到 iTunes Store" UserInfo={NSLocalizedDescription=無法連接到 iTunes Store, SSErrorHTTPStatusCodeKey=503}Aug 18 16:29:31 YDZdeMacBook-Pro healthd[19174]: (Error) MC: MobileContainerManager gave us a path we weren't expecting; file a radar against them? ? ? ? ? Expected: /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles? ? ? ? ? Actual: /Users/YDZ/Library/Developer/CoreSimulator/Devices/D6BD3967-9BC4-4A8D-9AD0-23176B22B12A/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles? ? ? ? ? Overriding MCM with the one true pathAug 18 16:29:31 YDZdeMacBook-Pro healthd[19174]: PairedSync, Debugging at level 0 for console and level 0 for log filesAug 18 16:29:31 YDZdeMacBook-Pro healthd[19174]: Error: Could not create service from plist at path: file:///Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PairedSyncServices/com.apple.pairedsync.healthd.plist. Returning nil PSYSyncCoordinator for service name com.apple.pairedsync.healthd.? Please check that your plist exists and is in the correct format.Aug 18 16:29:31 YDZdeMacBook-Pro healthd[19174]: Error: failed to load bundle "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Health/Plugins/CompanionHealth.bundle": Error Domain=NSCocoaErrorDomain Code=4 "未能載入軟件包“CompanionHealth.bundle”,因?yàn)槲茨苷业狡淇蓤?zhí)行文件的位置。" UserInfo={NSLocalizedFailureReason=未能找到該軟件包可執(zhí)行文件的位置。, NSLocalizedRecoverySuggestion=請(qǐng)嘗試重新安裝軟件包。, NSBundlePath=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Health/Plugins/CompanionHealth.bundle, NSLocalizedDescription=未能載入軟件包“CompanionHealth.bundle”,因?yàn)槲茨苷业狡淇蓤?zhí)行文件的位置。}Aug 18 16:29:33 YDZdeMacBook-Pro wcd[19180]: libMobileGestalt MobileGestalt.c:2584: Failed to get battery levelAug 18 16:29:34 --- last message repeated 1 time ---Aug 18 16:29:34 YDZdeMacBook-Pro assertiond[19185]: assertion failed: 15G31 13E230: assertiond + 15801 [3C808658-78EC-3950-A264-79A64E0E463B]: 0x1Aug 18 16:29:34 --- last message repeated 1 time ---Aug 18 16:29:34 YDZdeMacBook-Pro SpringBoard[19181]: [MPUSystemMediaControls] Updating supported commands for now playing application.Aug 18 16:29:34 YDZdeMacBook-Pro assertiond[19185]: assertion failed: 15G31 13E230: assertiond + 15801 [3C808658-78EC-3950-A264-79A64E0E463B]: 0x1Aug 18 16:29:34 --- last message repeated 1 time ---Aug 18 16:29:34 YDZdeMacBook-Pro fileproviderd[19169]: plugin com.apple.ServerDocuments.ServerFileProvider invalidatedAug 18 16:29:34 YDZdeMacBook-Pro ServerFileProvider[19775]: host connectionconnection from pid 19169 invalidatedAug 18 16:30:08 YDZdeMacBook-Pro mstreamd[19171]: (Note ) PS: Media stream daemon stopping.Aug 18 16:30:09 YDZdeMacBook-Pro mstreamd[19171]: (Note ) AS:: Shared Streams daemon has shut down.

Aug 18 16:30:09 YDZdeMacBook-Pro mstreamd[19171]: (Warn ) mstreamd: mstreamd shutting down.

Aug 18 16:30:09 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: Switching to keyboard: zh-Hans

Aug 18 16:30:09 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.

Aug 18 16:30:09 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: Switching to keyboard: zh-Hans

Aug 18 16:30:09 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.

Aug 18 16:30:10 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: Switching to keyboard: zh-Hans

Aug 18 16:30:10 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.

Aug 18 16:30:10 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: Switching to keyboard: zh-Hans

Aug 18 16:30:10 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.

Aug 18 16:30:16 YDZdeMacBook-Pro sharingd[19183]: 16:30:16.190 : Failed to send SDURLSessionProxy startup message, error Error Domain=com.apple.identityservices.error Code=23 "Timed out" UserInfo={NSLocalizedDescription=Timed out, NSUnderlyingError=0x7ff088e005a0 {Error Domain=com.apple.ids.idssenderrordomain Code=12 "(null)"}}

Aug 18 16:30:38 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: Switching to keyboard: zh-Hans

Aug 18 16:30:38 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.

Aug 18 16:30:38 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: Switching to keyboard: zh-Hans

Aug 18 16:30:38 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: KEYMAP: Failed to determine iOS keyboard layout for language zh-Hans.

Aug 18 16:30:41 YDZdeMacBook-Pro CoreSimulatorBridge[19190]: Switching to keyboard: zh-Hans

仔細(xì)看了一下log,根本原因還是因?yàn)?/p>

com.apple.CoreSimulator.SimDevice.D6BD3967-9BC4-4A8D-9AD0-23176B22B12A.launchd_sim[19096] (UIKitApplication:com.tencent.xin[0xdf6d][19774]): Program specified by service does not contain one of the requested architectures:

Unable to get pid for 'UIKitApplication:com.tencent.xin[0xdf6d]': No such process (err 3)

因?yàn)閞elease包里面architectures打包的時(shí)候不包含模擬器的architectures。debug包里面就有。所以release就沒法安裝到模擬器了。

由于筆者逆向方面的東西沒有研究,所以也無法繼續(xù)下去了。不知道逆向技術(shù)能不能把release包破殼之后能不能轉(zhuǎn)成debug包呢?如果能轉(zhuǎn)成debug包,通過ios-sim命令應(yīng)該也是可以直接安裝到模擬器的。

至此,ios-sim給模擬器安裝app就嘗試到此了。因?yàn)橹荒芙o模擬器安裝debug包,所以在題目上額外給安裝加了雙引號(hào),并不是所有的app文件都可以安裝到模擬器。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容