抖音品質建設 - iOS 安裝包大小優化實踐篇

2021-02-07 字節跳動技術團隊

客戶端開發的同學都知道「安裝包大小」是 App 重要的基礎體驗指標之一。今天將為大家介紹抖音在優化安裝包大小方向做的一些探索和嘗試。

閱讀這篇文章將會花費 8 分鐘時間,閱讀完成之後你將對安裝包優化有一個整體的認知,文章內容包括:

AppStore 對安裝包的限制沿革以及 App 花費精力優化 iOS 安裝包將獲得什麼收益;如何在線下準確把控安裝包大小對 AppStore 上影響;Part 1. 包大小劣化到底帶來什麼影響

要說 iOS 平臺上安裝包大小對 App 的影響,首先需要了解到的是 Apple 對安裝包大小的限制。一般 App 都通過 AppStore 渠道進行發布,少部分的 App 比如內部工具等通過企業證書進行籤發。通過 App Store 渠道發布的 App 可以享受 AppStore 提供的安裝包優化支持。

AppStore 對包大小提供的優化支持

對於在 AppStore 發布的包,蘋果也為 App 提供了很多優化方式,而這些是通過企業證書籤發的包無法做到的。

當 App 構建完安裝包之後上傳到 AppStore Connect 後, AppStore Connect 會根據設備、系統來創建其變體(variant)以適配不同的設備,用戶從 App Store 中下載到的安裝包時候,只下載自己設備用到變體。

變體之間的差異取決於設備的處理器架構(arm64, armv7)、屏幕解析度(2x, 3x)、iOS 系統版本。

當然這也導致很難用線下構建的安裝包來量化最終對下載大小的影響。

AppStore & AppStore Connect 對安裝包大小的限制App Store OTA 下載大小限制

蘋果公司為了避免用戶超出運營商套餐流量,限制了用戶通過流量從 AppStore 下載 App 的最大大小, 簡稱 OTA 下載大小限制。其歷史沿革:

2017 年 9 月,限制從 100MB 提升到了 150MB;2019 年 5 月下旬,蘋果把 OTA 下載限制放寬到 200MB;iOS 13 發布之後 iOS13 及以上用戶可以使用流量下載超出 200MB 的 App, 但需要用戶「設置」選擇策略,默認為「超過 200MB 請求許可」,而 iOS13 以下用戶仍然無法下載。Apple __TEXT 段大小限制

除了上邊的限制之外 Apple 對可執行文件__TEXT 段的限制則更為嚴苛,如果超出這個限制 APP 將無法通過 AppStore 審核。這個限制簡而言之,如果要支持 iOS8 的設備, App 單架構主二進位 __TEXT 段上限為 60MB(以 1000KB 為 1M,而不是 1024),放棄對 iOS8 的支持二進位大小限制則變為安裝包內最大二進位所有架構的總和不超過 500MB。

安裝包大小增長的影響

AppStore 下載大小如果在 OTA 下載限制內增長,對用戶新增、留存等指標影響不大。而一旦超過 OTA 下載限制,則對整體指標產生明顯影響。之前統計的劣化數據指標:當限制在 150MB 並且無法下載的時候,對用戶的新增有 10%的影響。由於 iOS13 限制的寬鬆化,所以在 iOS13 之後設備上這個數據將低於 10%。此數據僅供參考並不能一概而論,對於不同類型的 App 首次安裝的場景會呈現差異,比如生活服務、出行類 App 對應蜂窩下載場景會多於影音類、遊戲類 App。

其次對仍然需要支持 iOS8 以下的 App, 超出 __TEXT 段大小的限制將會很大程度上影響審核以及發版進度。當然可以通過一些手段進行救急,比如拆分動態庫的方式繞過。但是這些手段可能導致安裝包整體變得更大。

除了 Apple 的限制外,包大小的劣化一定程度上意味著更加慢的啟動速度;更多的的代碼邏輯;更低研發效率;過於複雜的代碼還會帶來對代碼修改的風險將對穩定性產生負面影響;讓性能等基礎體驗變差,所以包大小不是一個孤立的指標,它從側面的反映出 App 的健康狀態。

Part 2. 安裝包的構成以及如何分析安裝包安裝包的構成

當通過 Archieve 打包的安裝包並 unzip 解壓之後,通常可以看到如下的安裝包結構:

而主要影響下載和安裝大小的內容都集中在 .app 中。而解壓後的佔用 .app 大部分的大小的文件如下:

主二進位(和.app 同名的 MachO 文件);Frameworks(App 自身引入的動態庫);Plugins (App Extension 本質依然是動態的可執行文件);安裝包分析

通過分析安裝包,了解安裝包中可執行文件佔用大小、資源佔用大小,了解安裝包的現狀。明確從哪裡入手可以獲得 ROI 最高的優化手段。而在做包大小分析過程中比較難的是,怎麼樣通過線下的安裝包衡量對下載大小的影響。

但由於上傳到 AppStore Connect 到之後,Apple 對安裝包做了一些調整,線下安裝包的變化無法對應到真正的下載大小變化的變更。而這部分調整包括:

App Slicing 對於不同架構的裁剪,可執行文件只剩下單架構;Asset.car 中圖片只留下設備需要的特定尺寸和壓縮算法的變體;二進位部分__TEXT 段的通過 FirePlay 進行加密導致 __TEXT 段的壓縮比為 1( iOS 13+ 以上設備下載變體中蘋果移除了這個加密 );

所以線下評估的時候,通過刪除 Asset.car 中圖片帶來 10MB 的包大小的減小,但對最後的下載大小影響可能遠遠小於 10MB 。而當增加的 2MB 的代碼 ,最後的下載大小實打實地增長了 2MB。

可執行文件分析

安裝包中的可執行文件,佔了安裝包中很大一部分空間,而這部分不光和代碼有關還和編譯、連結過程中添加的參數,編譯的機器環境、Xcode 版本等等都有關係。而常常通過 LinkMap 來對可執行文件進行分析。

LinkMap 中包含了可執行文件的架構信息,段表,連結了的所有文件,以及文件中各符號佔用的大小。其實通過分析 LinkMap 就基本得到了可執行文件中包含了哪些東西。這部分數據也有助於針對性的進行一些優化。

Part 3. 常見的包大小優化手段可執行文件部分的優化

重命名部分段繞過 __TEXT 段 FirePlay 加密:

雖然 Apple 在 iOS13 + 去掉了對可執行文件的 __TEXT 段加密,但對於 iOS 低版本的設備而言超出 OTA 的下載限制比高版本影響還要大。所以可以將可執行文件中一部分段從 __TEXT 段中移動到其他段來繞過加密帶來提高壓縮比。而且在啟動時候 Page Load 解密 __TEXT 段也是比較大的性能損耗,能同時優化啟動時間。目前比較穩定的可以移動的段包括:

__TEXT,__cstring
__TEXT,__const
__TEXT,__gcc_except_tab
__TEXT,__objc_methname
__TEXT,__objc_classname
__TEXT,__objc_methtype

可在OTHER_LDFLAGS中添加如下參數進行移動:

$(inherited) -Wl,-
rename_section,__TEXT,__cstring,__RODATA,__cstring -Wl,-
rename_section,__TEXT,__const,__RODATA,__const -Wl,-
rename_section,__TEXT,__gcc_except_tab,__RODATA,__gcc_except_tab -Wl,-
rename_section,__TEXT,__objc_methname,__RODATA,__objc_methname -Wl,-
rename_section,__TEXT,__objc_classname,__RODATA,__objc_classname -Wl,-
rename_section,__TEXT,__objc_methtype,__RODATA,__objc_methtype -w

符號表的裁剪: 對於 App 的主二進位而言,對外是不需要暴露符號信息的。而對外暴露的符號名稱對 App 整體安全來講也存在一些風險。通常通過設置 STRIP_STYLE= all 來裁剪所有符號。但通過:

objdump -exports-trie /path/to/MyApp.app/MyApp

還能獲取到可執行文件中的符號,這部分可以通過設置 EXPORTED_SYMBOLS_FILE 為一個空文件解決 EXPORTED_SYMBOLS_FILE=/path/to/emptyfile.txt 。

對於自己構建的動態庫。只需要保留未定義的符號以及全局的符號其他的都可以去除。通常設置STRIP_STYLE=non-global。

多個可執行文件中存在多份的相同代碼: 有時候在寫代碼的時候為了實現一個簡單的功能就引入了一個很大的庫。而這個庫是採用靜態連結的方式被連結到可執行文件中時。如果不同的可執行文件都用了這個庫那麼這個庫將存在多份。

舉個例子:對於 iOS 場景下, Extension 是一個獨立的可執行文件,在 Extension 想發送一個網絡請求的時候,習慣性的是直接依賴了業務層的網絡框架。而這個依賴會導致業務層網絡框架在多個二進位中存在。

死代碼裁剪: 在構建完成之後如果是 C、C++ 等靜態的語言的代碼、一些常量定義,如果發現沒有被使用到將會被標記為 Dead code。開啟 DEAD_CODE_STRIP = YES 這些 Dead code 將不會被打包到安裝包中。在 LinkMap 這些符號也會被標記為 <<dead>>。

編譯期優化參數: GCC_OPTIMIZATION_LEVEL 定義了 clang 用什麼優化等級進行編譯優化。根據不同的 Configuration, Xcode 默認的 Debug 使用 -O0, Release 使用 -Os。

在 Xcode 11 之後 Xcode 提供了一種更加激進的編譯優化參數 -Oz,它通過識別單個編譯單元中跨函數的相同代碼序列來減少代碼大小。這些序列在單個編譯器生成的函數中被封裝(Outlined)。每個原始代碼序列都被替換為調用該 Outlined 函數。會減小相同代碼存在多份問題,但是也會使得的函數調用存在更深的調用棧,會影響性能。對性能略有影響具體參考下圖。抖音開啟了 Oz 之後對二進位有 6M 左右的優化。

需要注意的是在 ARC 場景 objc_retainAutoreleaseReturnValue 被外聯之後會導致一個本來不需要被放入 autoreleasepool 中的對象被放入了 autoreleasepool。這將導致一些有問題的寫法出現更壞的結果比如出現延遲釋放導致 BAD_ACCESS 或者被 @autoreleasepool 包裹的對象延時釋放導致的內存暴漲,所以在開啟的時候需要進行測試。

具體的信息左側為開啟了 Oz ,右側為 Os:

可見,下面的代碼移動到了一個外聯函數中:

mov        x29, x29
bl         imp___stubs__objc_retainAutoreleasedReturnValue

變成了一句對外聯函數的調用:

bl         _OUTLINED_FUNCTION_0

而 mov x29, x29 本質沒有任何實際意義,其作用是在 objc 對 autorelease 對象優化中作為一個標誌。在編譯器發現對返回的 autorelease 對象進行 objc_retainAutoreleaseReturnValue 時就會插入的標記。

而一般創建一個對象並返回的時候代碼是:

return objc_autoreleaseReturnValue(ret);

當 objc_autoreleaseReturnValue 檢查返回地址處有此標誌 ,如果存在意味著返回的對象會被立馬 retain ,所以沒必要放到 autoreleasepool 中。僅僅在 Thread Local Storage 中設置一個標記,直接對返回的對象引用記數 +1 就可以了。objc_retainAutoreleasedReturnValue 看到這個標誌也無需額外 retain,兩者配合從而優化掉了一次 autorelease 和 retain 操作,但這是優化細節,語義上仍然應該把它當作一個 autorelease 對象。而開啟了 Oz 之後標記被移動到另外一個外聯函數內部,導致這個優化失效對象被放到了 autoreleasepool 中出現延時釋放,從而引發一些內存問題。

連結期優化參數: LLVM 提供連結期編譯優化,通過設置工程中的 Link-Time Optimization 進行控制。

提供以下幾個選項:

No 不開啟連結期優化;

Monolithic 生成單個 LTO 文件,每次連結重新生成,無緩存高內存消耗,參數 LLVM_LTO=YES;

Incremental 生成多個 LTO 文件,增量生成,低內存消耗,參數 LLVM_LTO=YES_THIN;

本地調試和對時間敏感的構建流程不建議開啟 LTO。會增加很多的構建時間。

這裡需要注意的是 LTO 雖然是連結期優化,但是仍然需要編譯期參與,加入了 LTO 的編譯出來的 .a 本質是 LLVM 的 BitCode,如果使用未開啟 LTO 構建出來的的 .a 直接是機器碼了。直接連結是無法完成 LTO 優化的。

開啟 LTO 之後跨編譯單元的重複代碼會被連結器單獨生成以 .lto.o 為後綴的目標文件進行連結。尤其是對於 Objc Runtime 需要的一些結構 比如方法籤名的 literal string, protocol 的結構等有比較大的優化。同時開啟 Oz 和 LTO 可以讓外聯函數都只存在一份能夠最大限度的優化安裝包體積。

如果你的項目中大量的使用了 Protocol 建議還是開啟這個選項。抖音全部開啟 Oz & LTO 得到的收益是減小二進位大小 18MB。

資源文件部分的優化:

無用資源的移除: 通過掃描代碼中的字符串的常量和資源名稱。可以求差集可以得到未使用到的資源並對資源進行處理。

資源的動態化: 可以將一些低頻場景下的資源放到雲端,在進入 app 安裝之後再去雲端按需獲取。

ODR 的資源獲取方案: Apple 提供了按需資源(On-Demand Resource)的方式來幫助減小安裝包首次下載的大小, 當有一些由於審核原因必須要內置在安裝包中,但又可以走下發的情況可以嘗試以下這種解決方案。當然 ODR 中的資源也需要符合 App Store 的審核標準,否則也會存在拒審風險。

資源壓縮: 當我們一定要在安裝包內置某個資源的話,應該在可接受的範疇之內,儘可能的小。比如我們安裝包中內置的視頻、音頻資源可以採用降低清晰度、碼率等等方式進行壓縮。iOS 原生的多語言方案比較消耗空間,可以考慮自研更加緊湊的方案。

Asset.car 中圖片的優化: Assets.car 編譯過程中有時會選擇一些圖片,拼湊成一張大圖(ZZZZPackedAsset)來提高圖片的加載效率。被放進這張大圖的小圖會變為通過偏移量的引用。

建議使用頻率高且小的圖片放到 Asset.car 中,Asset.car 能保證其加載和渲染的速度最優。而大的圖片比如背景圖之類的,長寬尺寸就有上千個像素,而這种放到 Asset.car 中會大大的增加安裝包的大小。建議實踐中比如頁面背景圖,或者其他 png 格式超過 100KB 大小的圖片都使用 WebP 的方式引入。相較於 PNG 格式,WebP 具有更加優秀的圖像數據壓縮算法,能帶來更小的圖片體積,而且擁有肉眼識別無差異的圖像質量。

當我們在構建過程中,Xcode 會通過自己的壓縮算法重新對圖片進行處理。這也是為什麼我們通過對圖片無損壓縮來優化包大小沒有效果的原因。對於放入 Asset.car 中的圖片如果圖片沒有半透明效果,使用 70% 的有損壓縮是一個不錯的方式,既能保證圖片清晰度的同時獲得更小的大小。如果對於有半透明效果的圖片,採用 70% 的有損壓縮會導致半透明的地方出現噪點,所以壓縮過後的圖片最好找設計師同學再確認一次。

我們通過對 Asset.car 進行了逆向研究,同一張圖片,在不同設備、iOS 系統上 Xcode 採用了不同的壓縮算法這也導致了下載時候不同的設備針對圖片出現大小的區別。

截止目前 Xcode 會使用的壓縮算法有 lzfse、palette_img、deepmap2、deepmap_lzfse 、zip。

以 iPhoneX 為例子:

iOS 11.x 版本:對應的壓縮算法為 lzfse、zip;

iOS 12.0.x - iOS 12.4.x: 對應的壓縮算法為 deepmap_lzfse、palette_img;

iOS 13.x: 對應的壓縮算法為deepmap2;按照壓縮比來講 lzfse < palette_img ~= deepmap_lzfse < deepmap2。

在 BuildSetting 中如果設置了 ASSETCATALOG_COMPILER_OPTIMIZATION=space 那麼低版本的使用 lzfse 壓縮算法的圖片會變成 zip 的算法可減少 iOS11.x 及以下的 iOS 設備圖片的佔用大小。其他 iOS 版本的壓縮算法不受這個配置的影響。

無用代碼的清理:

一般的無用代碼篩查方式可以分為動態和靜態兩種方式。靜態的方式主要是通過代碼掃描、參與編譯構建過程或者分析最終產物來確認哪些代碼沒有被用到。而動態的方式主要是靠插樁或者運行時信息來獲取哪些代碼沒有執行。由於 Objc 強大的動態特性,我們在樣本量足夠大的場景使用動態方式會比靜態方式準確率高很多。

靜態篩查篩查方案:

比較簡單的方式是:基於 otool dump 最終產物中的 __objc_class_list & __objc_class_refs 做差集找到未使用的 Objc 類。

如果代碼採用 C 、C++ 等靜態語言編寫代碼時,編譯期已經確定了基本的代碼邏輯,所以編譯器會幫助我們將沒有使用到的代碼標記為 Dead code 最終不會打包到安裝包中。但 Objc 是典型的動態語言,很多邏輯都是在運行時決議的,我們通過靜態掃描的方式掃描出來的誤差會比較大,抖音對於這靜態結果初篩的得到未使用類的準確性只有 24% (總樣本 264 個,命中 64 個)

Objc 動態特性引入的的主要的問題包括:

一個類確實沒有被其他地方使用, 但是本身邏輯依賴 +load 、+initialize、__attribute__((constructor)) 在啟動時調用;MTLModel 等,通過運行時消息機制 assign value 的無法通過 classref 統計;典型的 DI 場景。如果一個類聲明遵循了某個 Protocol,外部使用的時候使用了這個 Protocol 進行方法調用。某個對象被另外一個對象引用,但是另外一個對象本身未被使用到。這時候會遺漏掉這個對象所屬 Class 的檢查。

動態篩查方案:

基於插樁的行級別代碼覆蓋率:

基於 GCOV 或者 LLVM Profile 二進位的插樁方案可以實現在運行時收集插樁數據來指導無用代碼的刪除。但插樁方案局限性也顯而易見,插樁會劣化二進位本身的大小和性能,同時原生的插樁方案是無法過審上線。數據收集只能局限於線下。

基於 Runtime 的輕量級運行時「類覆蓋率」方案:

Objc 的類首次調用類初始化時,+initialize 被執行,系統會自動標記已被調用,在 metaClass 中 data 的 flags 欄位第 29 位就存著這個這個狀態。可以使用 flags & RW_INITIALIZED 獲取。iOS14 之後這個值的獲取方式有變化。具體參考:WWDC:Advancements in the Objective-C runtime (https://developer.apple.com/videos/play/wwdc2020/10163/)。

#define RW_INITIALIZED (1<<29)
bool isInitialized() {
   return getMeta()->data()->flags & RW_INITIALIZED;
}

上報的數據可以讓我們了解我們線上真實的 Class 使用情況,對得到的數據不僅可以用來刪減未使用的代碼。還可以分辨使用率低的場景,如果是低頻且必須的場景可以考慮使用跨端技術這種對原生包大小影響比較小的方案實現。而如果這些場景是某個滲透率很低的需求可以考慮直接下線為其他需求做置換。

以上方案都在抖音上進行了落地。還有一些因為工程和歷史原因不能上線的優化,列在下面供大家參考:

動態庫的段壓縮。將動態庫中一些段進行壓縮存入到文件中,在動態庫加載的時候將這部分手動加載到內存中,將犧牲一部分啟動性能。Part 4. 影響包大小的一些編碼習慣和建議

由於 Objc 語言的特性,編寫的代碼會在編譯過程中出現生成各種類結構、方法籤名,protocol 結構體等等副產物。這些產物在我們工程很大很複雜的時候常常會導致我們安裝包大小極具劣化。所以在保證不影響編碼,嘗試一些對包大小友好的編碼方式。積少成多長期對包大小有正向影響。

Class Method vs C 函數

通常我們對於一些基礎和通用的函數會採用工具類的方式對外暴露。使用類方法完成功能。但當我們採用 Class Method, 這種方式在編譯的時候需要生成 Class 的類結構。調用的方法會通過 objc_methodSend。如果採用 C 函數的方式可以減小這部分的開銷。如果只是自己組件內部使用的私有的功能性函數還是建議使用 C 函數的方式實現。

Property vs IVAR

Objc 對於 Class 的 property,會自動的生成 set、get 方法,比如這個 property 是 Class 的私有屬性的時候,我們可以直接使用 ivar 來代替 property。減小這部分的包大小開銷。這裡需要注意,當我們使用 property 的 getter 實現 LazyLoad 或者 setter 存在一些其他副作用的時候還是需要保留 property 的。

減少 Block 的使用

我們知道 Block 是一個特殊的 OC 對象。需要佔用部分二進位空間來表徵一個 Block 對象。所以在非必要使用 Block 的場景。去掉 Block 實現可以優化不少包大小,常見的比如 Masonry 通過 Block 實現的鏈式調用。

縮減方法參數 & 函數參數的個數

我們調用一個函數的時候,傳入的參數會存在一個參數列表中。當我們調用的時候傳入參數很多的時候會對我們安裝包大小有較大的影響,尤其是類似網絡請求的的方法,動輒 7、8 個參數,而且調用的地方又很多。所以在對外 API 設計的時候如果參數超過 3 個嘗試通過構造對象解決傳參問題。

高頻率使用的宏不要使用多行的方式

這個問題常見於我們組件化依賴注入場景、Log 記錄等。當一個展開為 3 行的宏,經過上千次的調用之後最後佔用的大小也是非常恐怖的。

儘量避免代碼的複製粘貼

如果組件化做得不好或者一些大型的 app 存在一些業務閉環的中臺業務場景時候,代碼裡頭會存在不少的重複代碼。有些可能是改了前綴或者命名空間。可以考慮通過 PMD 對工程中的源碼進行掃描。將重複代碼進行統一。

參考文檔:

1. Apple App Thinning 文檔

https://help.apple.com/xcode/mac/current/#/devbbdc5ce4f

2. On-Demand Resources Guide

https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/On_Demand_Resources_Guide/Tagging.html)

3. Oz 優化- 外聯函數(Outlined Function)

http://lists.llvm.org/pipermail/llvm-dev/2016-August/104170.html

https://mnt.io/2016/12/06/reducing-code-size-using-outlining/

加入我們

我們是負責抖音客戶端基礎能力研發和新技術探索的團隊。我們在工程/業務架構,研發工具,編譯系統等方向深耕,支撐業務快速迭代的同時,保證超大規模團隊的研發效能和工程質量。在性能/穩定性等方面不斷探索,努力為全球數億用戶提供最極致的基礎體驗。

如果你對技術充滿熱情,歡迎加入抖音基礎技術團隊,讓我們共建億級全球化 App。目前我們在上海、北京、杭州、深圳均有招聘需求,內推可以聯繫郵箱: tech@bytedance.com ,郵件標題: 姓名 - 工作年限 - 抖音 - 基礎技術 - iOS/Android 

相關焦點

  • 抖音工程師:iOS 安裝包大小優化實踐篇
    客戶端開發的同學都知道「安裝包大小」是 App 重要的基礎體驗指標之一。今天將為大家介紹抖音在優化安裝包大小方向做的一些探索和嘗試。閱讀這篇文章將會花費 8 分鐘時間,閱讀完成之後你將對安裝包優化有一個整體的認知,文章內容包括:AppStore 對安裝包的限制沿革以及 App 花費精力優化 iOS 安裝包將獲得什麼收益;如何在線下準確把控安裝包大小對 AppStore 上影響;Part 1.
  • iOS性能優化09-安裝包瘦身
    其實是一個IPA包,那首先我們來看看安裝包的組成安裝包(ipa)主要由可執行文件、資源組成資源(圖片、音頻、視頻等)採取無損壓縮:網上有很多,我常用的像 TinyPng、Squoosh、圖好快 等等>去除沒用到的資源:大家可以試試GitHub上有個開源項目可以檢測項目裡沒用的資源文件 GitHub傳送門可執行文件瘦身編譯器優化 現在的新版Xcode已經自動給優化了,如果你的項目比較舊的話,可以去XCode設置這些選項,不確定的話最好都去搜下然後設置下 Strip Linked Product
  • 英雄聯盟手遊ios安裝教程 lol手遊ios怎麼安裝
    英雄聯盟手遊ios安裝教程 lol手遊ios怎麼安裝 2020-10-18 13:25 作者:我遊網
  • 悟飯遊戲廳ios版下載安裝
    對此類遊戲感興趣的玩家,快來挑戰悟飯遊戲廳ios版下載安裝吧悟飯遊戲廳ios版下載安裝軟體特色:學習工作太緊張,悟飯遊戲廳ios版下載安裝讓你心情愉悅1)海量經典免費遊戲隨便玩;
  • 咪嚕ios版遊戲下載安裝_咪嚕ios版手遊下載安裝_18183手機遊戲下載
    在你開始試玩百分網ios版下載安裝後,你就會被這個遊戲深深的吸引住。 咪嚕ios版下載安裝用戶評價: 對這款軟體實在是很滿意!挑不出毛病 咪嚕ios版下載安裝軟體特色: 【精心挑選好玩到爆】 愛玩遊戲更為輕鬆,點評試玩,更加直觀推薦應用絕不坑爹,小編親測,趣味十足!
  • 蘋果ipa包用超級籤名測試安裝到IOS系統手機上
    蘋果ipa包超級籤名是一種在APP內測時常常使用來安裝到IOS系統上的籤名,做了超級籤名的應用可以不上架App Store,不經過蘋果審核就可以上架。用戶安裝時可以直接安裝,不用像企業籤名那樣信任企業證書,技客超級籤名它的穩定性非常好,所以很多開發者再進行內測時,會首選超級籤名。
  • 安裝包清理
    安裝包清理 系統安全 大小: 0.27M
  • apk安裝包管理
    apk安裝包管理 系統安全 大小: 5.66M
  • 【iOS 原創】iOS抖音App越獄檢測分析
    其他工具安裝方式請自行查閱,這裡簡單說下fridaFrida是跨平臺的函數級跟蹤工具,可以提高分析效率。利用該工具可以很方便的調用進程內部函數;在實際分析過程中,lldb一般用來定位反調試,崩潰和指令級別的分析,而frida主要用作函數級別的分析,如修改函數輸入參數和返回值,列印調用棧,跟蹤調用的API流,用作逆向分析和滲透測試再好不過。
  • 抖音下載安裝2020
    抖音下載安裝2020擁有海量的短視頻供你觀看,多種精彩爆笑的幽默視頻等你來觀看,還有百變貼紙素材任你自由選擇,隨時隨地都能拿出手機記錄生活,分享到抖音,說不定下一個名人就是你,還在等什麼。
  • 做ios籤名的注意!以下這些問題將會導致app安裝出錯!
    在做ios籤名的時候,通常都會根據籤名的類型去選擇不同的打包方式。但是,錯誤的打包方式會直接導致籤名失敗,應用在安裝的時候出錯。其實,很大程度上是因為你在打包的時候選擇了錯誤的打包方式才會出現如此尷尬的局面。下面為大家整理一下大致原因,希望大家在做ios籤名的時候儘量避免出錯。
  • 小雞模擬器iOS版激活碼 iOS版安裝教程
    小夥伴們知道怎麼樣安裝嗎?知道激活碼在哪裡領取嗎?接下來九遊小編就來和大家詳細的說說小雞模擬器iOS版安裝教程,一起來看看吧! iOS小... 來了!來了!各位玩家一直在期盼的小雞模擬器iOS版終於要來咯!小夥伴們知道怎麼樣安裝嗎?知道激活碼在哪裡領取嗎?
  • 《極限競速7》體積驚人 安裝包大小99G
    據報導,Xbox One X版本的《極限競速7》安裝包高達100GB,這對玩家們來說可不是個好消息,尤其是對那些小水管寬帶來說。由於《極限競速7》中擁有超過700輛車型,並且還將附帶4K材質包,所以遊戲安裝包的體積如此驚人。
  • iOS摸魚周報 第三期
    ohmyzsh地址:https://github.com/ohmyzsh/ohmyzsh包管理器是什麼包管理器又稱軟體包管理系統,它是在電腦中安裝、配置、卸載、升級,有時還包含搜索、發布的工具組合。Homebrew是一款Mac OS平臺下的包管理器,擁有安裝、卸載、更新、查看、搜索等很多實用的功能。
  • 不想升級iOS10.3.2,怎麼關閉iOS自動更新?蘋果iOS10.3.2、iOS10.3...
    可是,我們也知道蘋果可能過段時間就會開始強制推送更新,不僅煩人還會偷偷下載固件包佔用手機空間,就問你怕不怕?!   面對這種煩人的機制,小編找到了兩種可以關閉 iOS 自動更新方法,通過安裝指定的描述文件可屏蔽 iOS 自動更新,避免蘋果更新提示的反覆騷擾。而且還能阻止蘋果偷偷地下載最新固件,從而節約手機的存儲空間,一舉兩得。
  • ​吹爆系列:深入探索 Android 包體積優化
    在 Android 性能優化的知識體系當中,包體積優化一直被排在優先級比較低的位置,從而導致很多開發同學對自身應用的大小並不重視。如何全面對應用的包體積進行 系統分析 及 針對性優化 呢?在這篇文章中,我們將一起進行深入地分析與探索。1、瘦身優勢我們首先來介紹下,為什麼我們需要做 APK 的瘦身優化?
  • 抖音大頭漫畫特效在哪?怎麼錄製?ios漫畫製作
    抖音大頭漫畫特效在哪?怎麼錄製?ios漫畫製作;老郭發現最近這段時間抖粉們在刷抖音的時候,總是能刷到一些卡通動漫大頭特效的視頻,這個新花樣玩法很炫酷,現在已然成了抖音熱門,因此受到抖粉們的熱捧,抖粉們發現在抖音系統自帶的特效裡並沒有這個,那麼,這個卡通動漫大頭特效是怎麼錄製的呢?
  • ios不越獄怎麼安裝ipa?
    那麼ios不yueyu應該怎麼安裝未上架App Store的ipa文件呢?可以使用蘋果籤名。進行蘋果籤名的應用,可以不用上架,不用越獄,直接安裝在iOS手機上。很多ios用戶會發現,一些遊戲、軟體,雖然App Store中找不到他們的應用,但他們的官網中是有ios下載二維碼的,掃碼就可以不通過App Store下載,他們大部分都是使用了蘋果籤名。蘋果籤名目前又可以分為蘋果企業籤名、蘋果超級籤名、和tf籤名。
  • 蘋果iOS13測試版下載-iOS13描述文件正式版下載「BETA固件...
    iOS13固件 系統工具 大小: 1.3G
  • 愛思助手ios在線安裝最新版
    軟體介紹愛思助手ios在線安裝最新版一款為科技愛好者推出資訊社區,大家可以了解到非常多最新的科技新聞資訊,各種好玩有趣的科技產品開闊你的眼界,讓你感受科技迅速發現的世界,這裡還聚集了一群喜歡科技喜歡遊戲的朋友們,大家可以在這裡一起聊聊自己喜歡的愛好,歡迎加入和大家一起玩呀!