給 iOS 模擬器 「安裝」app 文件

前言

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

一.應用場景

先來談談是什麼狀況下,會有在模擬器上安裝app的需求。git

在一個大公司裏,對源碼的管理有嚴格的制度,非開發人員是沒有權限接觸到源碼的。對蘋果的開發證書管理也很是嚴格,甚至連開發人員也沒有發佈證書,證書只在持續集成環境或者Appstore產線裏面,或者只在最後打包上架的人手上。github

那麼如今就有這樣的需求,開發人員搭建好UI之後,要把開發完成的Alapha版給到UI設計師那邊去評審,看看是否徹底達到要求,達不到要求就須要打回來重作。npm

通常作法就是直接拿手機去安裝一遍了。直接真機看效果。不過要是設計師和開發不在同一個地方的公司,一個在北京一個在上海,這種就無法安裝了。源碼又沒法導出給設計師,讓他運行一下Xcode跑一下模擬器。打release的ipa經過掃碼安裝,若是公司大了,UDID所有都用完了,也無法安裝。這個時候就比較麻煩了。(通常也沒人遇到這麼蛋疼的事情吧)微信

那麼如今就有給模擬器安裝app的需求了,那開發人員如何能把開發版的app給打包出來給其餘模擬器安裝呢?session

二.解決辦法

解決思路,想要別人的模擬器運行起咱們開發的app,最簡單的辦法就是把咱們DerivedData的數據直接拷貝到別人模擬器上面,就能夠了。固然還要考慮到設計師也許並不會一些命令行命令,咱們的操做越傻瓜越好。app

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

Mac的拷貝命令有cp和ditto,建議用ditto進行拷貝工做。dom

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

  1. 它在複製過程當中不只能保留源文件或者文件夾的屬性與權限,還能保留源文件的資源分支結構和文件夾的源結構。
  2. 此命令能確保文件或者文件夾被如實複製。
  3. 若是目標文件或者文件夾不存在,ditto將直接複製過去或建立新的文件和文件夾,相反,對於已經存在的文件,命令將與目標文件(夾)合併。
  4. ditto還能提供完整符號連接。

那麼咱們就拷貝出本地的debug包ide

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

有幾點須要說明的:

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

  2. 再來講一下命令裏面的 * 的問題。當咱們打開本身本地的~/Library/Developer/Xcode/DerivedData/ ,這個路徑下,會發現裏面裝的都是在咱們本地模擬器上運行過的app程序。前面是app的Bundle Identifier,橫線後面是一堆字符串。上面的ditto裏面帶 * 的那個路徑是爲了動態匹配一個地址的,* 在這裏也是一個通配符。後面的head說明了匹配的規則。head實際上是找出最近一次咱們運行模擬器的app的路徑。

爲了保證咱們打包是正確的,建議先運行一下咱們要打包的app,通常咱們Scheme裏面的Run都是debug product(若是這裏有更改,那就改爲對應debug的Scheme),確保是咱們要給設計師審覈的app,以後再運行這個ditto命令。

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

咱們運行完上面的ditto命令會產生一個zip文件,解壓出來,會獲得一個app文件,這個就是debug包了。debug包就是咱們要給設計師的app包了。

如何能讓設計師傻瓜式的安裝這個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  
  
  
  

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

只須要把上面的命令發給設計師,無腦粘貼到命令行,裝好app的模擬器就會自動啓動,打開app了。

三.額外的嘗試

好奇的同窗確定不會知足只給模擬器安裝debug包吧,既然能夠不用代碼就能夠給模擬器安裝app,那咱們能安裝release包麼?我好奇的嘗試了一下。

先從Appstore上面下載最新的微信,把ipa後綴改爲zip,解壓,把Payload文件夾裏面的「WeChat」取出來,而後運行ios-sim命令。

結果微信確實是安裝到了模擬器了。不過一點擊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 
  
  
  

 
  
  {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 
 
  
    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」,由於未能找到其可執行文件的位置。" UserInfo={NSLocalizedFailureReason=未能找到該軟件包可執行文件的位置。, NSLocalizedRecoverySuggestion=請嘗試從新安裝軟件包。, NSBundlePath=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Health/Plugins/CompanionHealth.bundle, NSLocalizedDescription=未能載入軟件包「CompanionHealth.bundle」,由於未能找到其可執行文件的位置。} 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 
   
     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: 
    
      : 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 
     
    
   

 複製代碼

仔細看了一下log,根本緣由仍是由於

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)複製代碼

由於release包裏面architectures打包的時候不包含模擬器的architectures。debug包裏面就有。因此release就無法安裝到模擬器了。

因爲筆者逆向方面的東西沒有研究,因此也沒法繼續下去了。不知道逆向技術能不能把release包破殼以後能不能轉成debug包呢?若是能轉成debug包,經過ios-sim命令應該也是能夠直接安裝到模擬器的。

至此,ios-sim給模擬器安裝app就嘗試到此了。由於只能給模擬器安裝debug包,因此在題目上額外給安裝加了雙引號,並非全部的app文件均可以安裝到模擬器。

請你們多多指教。

相關文章
相關標籤/搜索