給iOS 模擬器“安裝”app文件

前言

剛剛接觸iOS的時候,我就一直很好奇,模擬器上面能不能直接安裝app呢?如果可以,我們就直接在模擬器上面聊QQ和微信了。直到昨天和朋友們聊到了這個話題,沒有想到還真的可以給模擬器“安裝”app!

一.應(yīng)用場景

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

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

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

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

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

二.解決辦法

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

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

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


Usage: ditto [ <options> ] src [ ... src ] dst

    <options> 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命令更好的地方在于:

  1. 它在復(fù)制過程中不僅能保留源文件或者文件夾的屬性與權(quán)限,還能保留源文件的資源分支結(jié)構(gòu)和文件夾的源結(jié)構(gòu)。
  2. 此命令能確保文件或者文件夾被如實(shí)復(fù)制。
  3. 如果目標(biāo)文件或者文件夾不存在,ditto將直接復(fù)制過去或創(chuàng)建新的文件和文件夾,相反,對于已經(jīng)存在的文件,命令將與目標(biāo)文件(夾)合并。
  4. ditto還能提供完整符號鏈接。

那么我們就拷貝出本地的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)需要說明的:

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

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

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

2.把debug包拷貝到另一個模擬器中

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

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

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

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

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

安裝ios-sim

    $ npm install ios-sim -g

說明文檔:


    Usage: ios-sim <command> <options> [--args ...]
        
    Commands:
      showsdks                        List the available iOS SDK versions
      showdevicetypes                 List the available device types
      launch <application path>       Launch the application at the specified path on the iOS Simulator
      start                           Launch iOS Simulator without an app
      install <application path>      Install 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
      --log <log file path>           The path where log of the app running in the Simulator will be redirected to
      --devicetypeid <device type>    The 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:
      --stdout <stdout file path>     The path where stdout of the simulator will be redirected to (defaults to stdout of ios-sim)
      --stderr <stderr file path>     The path where stderr of the simulator will be redirected to (defaults to stderr of ios-sim)
      --sdk <sdkversion>              The iOS SDK version to run the application on (defaults to the latest)
      --family <device family>        The 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
      --timeout <seconds>             The 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 <environment file path>   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這個是設(shè)計師收到app之后的路徑。--devicetypeid參數(shù)后面是給定一個模擬器的版本。

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

三.額外的嘗試

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

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

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

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 <CFString 0x7fa810c047d0 [0x1073daa40]>{contents = "com.apple.mobileassetd"} completed with error - code: -999
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]): 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 for <FBApplicationProcess: 0x7fa83cd91840; com.tencent.xin; pid: -1>
Aug 18 16:29:17 YDZdeMacBook-Pro SpringBoard[19181]: Unable to delete job with label UIKitApplication:com.tencent.xin[0xdf6d]. Error: Operation now in progress
Aug 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: 9
Aug 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 sandbox
Aug 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.appex
Aug 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: 0
Aug 18 16:29:22 YDZdeMacBook-Pro SpringBoard[19181]: Did not complete check for asset updates (force: 0, isVoiceOverRunning: 0
Aug 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: MR22
Aug 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 kCTMobileEquipmentInfoIMEI
Aug 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 path
Aug 18 16:29:31 YDZdeMacBook-Pro healthd[19174]: PairedSync, Debugging at level 0 for console and level 0 for log files
Aug 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=請嘗試重新安裝軟件包。, 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 level
Aug 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]: 0x1
Aug 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]: 0x1
Aug 18 16:29:34 --- last message repeated 1 time ---
Aug 18 16:29:34 YDZdeMacBook-Pro fileproviderd[19169]: plugin com.apple.ServerDocuments.ServerFileProvider invalidated
Aug 18 16:29:34 YDZdeMacBook-Pro ServerFileProvider[19775]: host connection <NSXPCConnection: 0x7f880160bc30> connection from pid 19169 invalidated
Aug 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: <MSIOSAlbumSharingDaemon: 0x7fd139c0a020>: 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打包的時候不包含模擬器的architectures。debug包里面就有。所以release就沒法安裝到模擬器了。

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

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

請大家多多指教。

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

相關(guān)閱讀更多精彩內(nèi)容

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