在 TS 中解析 ipa 文件

在 TS 中解析 ipa 文件

ipaXcode打包出來的APP的安裝包,通過解析ipa中的文件,我們可以獲得APPDisplayNameVersionBundleIdentifier等信息,
同時也可以獲取到APP證書的相關信息,包括APP安裝環境證書的有效期APP開通的功能可安裝設備的UDID公共秘鑰指紋等。

解析 ipa 可用的工具

在NPM 官網上搜索 app、ipa、package 或 parser 等信息,
可直接使用的插件有:app-info-parser,但是其不支持 TS,經過詢問,作者并不明確何時可以適配 TS。
js-app-parser是支持 TS 的解析插件,但是解析 ipa 時會出錯,解析 apk 時是正確的(解析非標準打包的 apk 會出錯,解決見下一篇)。
綜合分析以上插件源碼,找到 ipa 解析失敗問題并解決,創建一個支持 TSts-package-parser
js-app-parser解析出錯的地方是解析info.plist的時候出錯了。

分析 ipa

解析 ipa,實際需要解析的文件是 info.plistAppIcon
ipa 實際上就是壓縮包。只要將其解壓縮即可得到全部內容,再從中找到需要的文件,就可以得到 APP 的信息。

mobileprovision文件中包含 APP 的證書等信息,此文件可由后端進行解析。

解析 ipa
解壓縮 ipa

主流的解壓縮工具為 jszip,并支持TS,使用 jszip 解壓縮 ipa 文件,得到ipa里的所有文件。

解析過程中需要用到的方法

  // 創建jszip對象this._jsZip = new JSZip();/*** 解壓文件* @param blob 文件內容* @returns 文件數據:JSZip*/unZipFile(blob: Blob | ArrayBuffer) {return new Promise((resolve, reject) => {this._jsZip.loadAsync(blob).then((zipObjc: JSZip) => {return resolve(zipObjc);}).catch((e) => {return reject('解析File失敗');});});}/*** 生成文件* @param path 要壓縮的文件路徑* @param type 文件類型:OutputType* @returns 生成的文件*/zipFilePathToNeedType<T extends OutputType>(path: string, type: T) {return new Promise((resolve, reject) => {this._jsZip.file(path).async(type).then((result) => {return resolve(result);}).catch(() => {return reject('生成文件失敗');});});}

通過以上解壓縮方法即可得到解壓后的 ipa 對象。

  // 解壓ipathis.unZipFile(file).then((zipObjc: JSZip) => {const names = Object.getOwnPropertyNames(zipObjc.files);});// 通過zipObjc得到ipa的全部文件名稱和路徑const names = Object.getOwnPropertyNames(zipObjc.files);// 通過遍歷names得到info.plist文件const plistRegex = /^Payload\/(?:.*)\.app\/Info.plist$/;let plistPaht = '';for (let i = 0; i < names.length; i++) {if (plistRegex.test(names[i])) {plistPath = names[i];break;}}
解析 info.plist 文件

獲取到 info.plist 文件路徑后,讀取到文件內容,類型為:arraybuffer

使用 jszip 創建文件,將得到的文件,轉換為 buffer 文件。

  import bufferLib from 'buffer';import { parse as PlistParse } from 'plist';import bplist from 'bplist-parser';this.zipFilePathToNeedType(plistPath, 'arraybuffer').then((arrBuffer: ArrayBuffer) => {// 創建buffer對象const buffer = bufferLib.Buffer.from(arrBuffer);// 根據buffer的第一個元素設置bufferTpeconst bufferType = buffer[0] as number | string;// 解析結果對象let result = null;if (bufferType == 60 || bufferType == '<' || bufferType == 239) {result = PlistParse(buffer.toString()) as any;} else if (bufferType == 98 || bufferType == 'b') {result = bplist.parseBuffer(buffer)[0];} else {throw new Error('Unknown plist buffer type.');}}

至此即可解析出 info.plist 的信息。

Info.name = result.CFBundleDisplayName || result.CFBundleName;
Info.versionName = result.CFBundleShortVersionString;
Info.versionCode = result.CFBundleVersion;
Info.ubndleId = result.CFBundleIdentifier;
Info.platform = 'ios';
// 設置icon信息,解析icon需要用到
if (result.CFBundleIcons) {const icons = result.CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconFiles;if (icons) {Info.icon = icons[icons.length - 1];}
}
解析 AppIcon

獲取 icon 路徑、名稱等信息,解析獲取到 png 文件。

  // 使用 js-app-parser 解析icon的方法import { parsePNG } from 'js-app-parser/dist/ios/png-parse';// appIcon路徑const appIconRegex = /^Payload\/(?:.*)\.app\/AppIcon[0-9]{2}x[0-9]{2}@[2-3]x.png$/;/*** 解析ipa中的icon.png* @param zipObjc 已解析的ipa對象數據* @param bundleUploadInfo 已解析的info.plist數據對象* @returns ApplicationModel對象*/parserFileToPngIcon(zipObjc: JSZip, bundleUploadInfo: BundleUploadModel): Promise<BundleUploadModel> {return new Promise((resolve, reject) => {// 獲取ipa中的全部文件及路徑const names = Object.getOwnPropertyNames(zipObjc.files);// 解析info.plist時獲取的if (bundleUploadInfo.icon) {// icon的file對象let icon = void 0;for (let i = 0; i < names.length; i++) {if (names[i].indexOf(bundleUploadInfo.icon) >= 0) {// 將icon路徑生成file類型數據icon = zipObjc.files[names[i]];break;}}if (icon) {bundleUploadInfo.icon = icon.name;// 解析icon數據this.zipFilePathToNeedType(icon.name, 'uint8array').then((data: Uint8Array) => {const iconPng = parsePNG(data);bundleUploadInfo.iconSteam = iconPng;bundleUploadInfo.iconUrl = URL.createObjectURL(new Blob([iconPng]));resolve(bundleUploadInfo);}).catch((err) => {reject(err);});} else {resolve(bundleUploadInfo);}} else {resolve(bundleUploadInfo);}});}
壓縮生成文件

ipa 中其他重要的證書信息等存儲在 mobileprovision 中。同樣的通過 nams 獲取到 mobileprovision,
之后將 info.plist、mobileprovision 等文件壓縮為同一個文件。

  // 描述文件路徑const provisonRegex = /^Payload\/(?:._)\.app\/(?:._).mobileprovision$/;/*** 壓縮解析后需要的文件* @param bundleUploadInfo 解析后的對象* @returns BundleUploadModel*/async unzipFilePathToIpaOrApk(bundleUploadInfo: BundleUploadModel): Promise<BundleUploadModel> {const jszip = new JSZip();const paths = [];paths.push(bundleUploadInfo.plistPath);paths.push(bundleUploadInfo.provisionPath);for (let i = 0; i < paths.length; i++) {const path = paths[i];const name = path.substring(path.indexOf('app/') + 4);await this.zipFilePathToNeedType(path, 'blob').then((result: Blob) => {jszip.folder(`Payload/${bundleUploadInfo.name}.app/`).file(name, result);});}return new Promise((resolve, reject) => {jszip.generateAsync({type: 'blob', // 壓縮類型compression: 'DEFLATE', // STORE:默認不壓縮 DEFLATE:需要壓縮compressionOptions: {level: 9, // 壓縮等級1~9 1壓縮速度最快,9最優壓縮方式},mimeType: 'bundleUploadInfo/iphone',}).then((fileZip) => {bundleUploadInfo.ipaZip = fileZip;resolve(bundleUploadInfo);}).catch((err) => {reject(err);});});}
總結

ipa 的解析主要是解析 info.plist、appIcon。

應用之家即采用了此種方式進行解析。
上傳 ipa 后并能解析到應用的安裝環境證書的有效期APP開通的功能可安裝設備的UDID公共秘鑰指紋等具體信息。并提供下載統計等豐富功能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/206811.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/206811.shtml
英文地址,請注明出處:http://en.pswp.cn/news/206811.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python-算術運算符詳解

運算符 算術運算符 關系運算符 邏輯運算符 賦值運算符 算術運算符&#xff1a;加減乘除 %求余 **平方 // 先算乘方&#xff0c;再算乘除&#xff0c;最后是加減。括號可以改變優先級 0不能作為除數&#xff08;不論是整型0還是浮點0&#xff09; 除法截斷&#xff1a;舍棄小…

UDP群聊

客戶端 import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader…

LeetCode738. Monotone Increasing Digits

文章目錄 一、題目二、題解 一、題目 An integer has monotone increasing digits if and only if each pair of adjacent digits x and y satisfy x < y. Given an integer n, return the largest number that is less than or equal to n with monotone increasing digi…

使用VBA快速統計詞組(單詞組合)詞頻

實例需求&#xff1a;產品清單如A列所示&#xff0c;現在如下統計詞組詞頻。想必各位小伙伴都指定如何使用字典對象實現去重&#xff0c;進而實現單個單詞的詞頻統計。 但是統計詞組詞頻就沒有那么簡單了&#xff0c;為了便于演示&#xff0c;此處的詞組只限于兩個單詞的組合。…

自動駕駛右向輔助功能規范

目 錄 Contents 目錄 1. 介紹 Introduction. 8 1.1 此文檔的范圍和目的 Scope and Purpose of This Document 8 1.2 參考文檔References. 9 1.3 文檔的維護 Maintenance of the Document 10 1.4 縮略詞Abbreviations. 10 1.5 文檔概述Document Overview.. 11 1.6 功能…

GoLong的學習之路,進階,Viper(yaml等配置文件的管理)

本來有今天是繼續接著上一章寫微服務的。但是這幾天有朋友說&#xff0c;再寫Web框架的時候&#xff0c;遇到一個問題&#xff0c;就是很多的中間件&#xff08;redis&#xff0c;微信&#xff0c;mysql&#xff0c;mq&#xff09;的配置信息寫的太雜了&#xff0c;很不好管理。…

【解決辦法】Pycharm中新添加或者導入項目文件名紅色!

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 一、問題描述二、問題原因三、解決辦法 一、問題描述 Pycharm的代碼中添加新的文件夾&#xff0c;發現文件夾下的文件名是紅色的&#xff0c;如下圖&#xff1a; …

jvm-sandbox-repeater 精簡版部署之standalone模式

jvm-sandbox-repeater 僅僅提供了錄制回放的能力&#xff0c;如果需要完成業務回歸、實時監控、壓測等平臺&#xff0c;后面須要有一個數據中心負責采集數據的加工、存儲、搜索&#xff0c;repeater-console提供了簡單的demo示例&#xff1b;一個模塊管理平臺負責管理JVM-Sandb…

設計模式——單例模式(Singleton Pattern)

概述 單例模式確保一個類只有一個實例&#xff0c;而且自行實例化并向整個系統提供整個實例&#xff0c;這個類稱為單例類&#xff0c;它提供全局訪問的方法。單例模式是一種對象創建型模式。單例模式有三個要點&#xff1a;一是某個類只能有一個實例&#xff1b;二是它必須自行…

矩陣基本操作算法

題目描述&#xff1a; 題目描述 根據主函數和頭文件提示&#xff0c;編寫子函數void matrixInput(int (*mat)[COL]); void matrixPrint(int *mat[ROW]); void matrixAddT(int *mat); ? 分別實現矩陣的輸入&#xff0c;輸出&#xff0c;與自身的轉置相加&#xff1a;void matr…

微信小程序開發中的圖片缺少后自動居中問題的解決,自動居中樣式,自適應圖片多少的寫法

下面是寫的wxml的view樣式類似于web開發中的HTML文件 home-grid是我創建的一個父樣式&#xff0c;采用子絕父相的定位方式 我在home-grid的父view&#xff08;類似于web中div&#xff09;中包含了三個小的子樣式分別是下述代碼中的class“yellowstar”&#xff0c;class“maint…

Java---線程講解(二)

文章目錄 1. Runnable接口2. 賣票案例3. 同步代碼塊解決數據安全問題4. 同步方法解決數據安全問題5. 線程安全的類6. Lock鎖 1. Runnable接口 1. 創建線程的另一種方法是聲明一個實現Runnable接口的類&#xff0c;之后重寫run()方法&#xff0c;然后可以分配類的實例&#xff0…

基于remix+metamask+ganache的智能合約部署調用

在我們部署合約時為了讓它更接近真實區塊鏈去中心化體驗&#xff0c;我們需要調用小狐貍&#xff08;Metamask&#xff09;來進行真實交易&#xff0c;而metamask里沒有內置虛擬測試幣&#xff0c;我們需要進行調用Ganache來添加帶有虛擬測試幣的賬號。以上就是三者的關系&…

從 MLOps 到 LMOps 的關鍵技術嬗變

本文整理自 2023 年 9 月 3 日 QCon 全球軟件開發大會 2023 北京站 —— 從 MLOps 到 LMOps 分論壇的同名主題演講。 本次分享的內容結構如下&#xff1a; 從 MLOps 到 LMOps&#xff1b; MLOps 概述、挑戰與解決方案&#xff1b; LMOps 實施挑戰與關鍵技術&#xff08;大模…

[FPGA 學習記錄] 快速開發的法寶——IP核

快速開發的法寶——IP核 文章目錄 1 IP 核是什么2 為什么要使用 IP 核3 IP 核的存在形式4 IP 核的缺點5 Quartus II 軟件下 IP 核的調用6 Altera IP 核的分類 在本小節當中&#xff0c;我們來學習一下 IP 核的相關知識。 IP 核在 FPGA 開發當中應用十分廣泛&#xff0c;它被稱為…

Java最全面試題專題---1、Java基礎知識(2)

筆者有七八年的面試者經驗&#xff0c;負責公司技術同學的社招和校招&#xff0c;近些年面試過三四百個技術同學&#xff0c;考慮接近年底這個時段&#xff0c;整理并更新一些以往的面試經驗&#xff0c;希望同學們跳槽能有個更好的工作&#xff0c;如有需要的同學可以關注下筆…

Jenkins安裝

環境 Ubuntu&#xff0c; 其他平臺查看官方文檔 步驟 安裝jdk sudo apt-get install openjdk-8-jdk 安裝Jenkins first add the key to your system wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -Then add a Jenkins apt repository …

使用Golang構建高性能網絡爬蟲

目錄 一、Golang的特點 二、構建網絡爬蟲的步驟 三、關鍵技術和注意事項 使用協程進行并發處理 使用通道進行協程間的通信 合理控制并發數和處理速度 遵守網站使用協議和法律法規 防止被網站封禁或限制訪問 優化網頁解析和數據處理 異常處理和錯誤處理 日志記錄和監控…

Flink入門之部署(二)

三種部署模式 standalone集群&#xff0c;會話模式部署&#xff1a;先啟動flink集群 web UI提交shell命令提交&#xff1a;bin/flink run -d -m hadoop102:8081 -c com.atguigu.flink.deployment.Flinke1_NordCount./Flink-1.0-SNAPSHOT.jar --hostname hadoop102 --port 8888 …

vmware虛擬機17 安裝macos14過程及問題處理親測

前期準備 1、可引導可虛擬機安裝的macOS Sonoma 14 ISO鏡像安裝文件 我找到得地址&#xff0c;下載自行解決啦 2、VMware虛擬機應用軟件 官網下載就好&#xff0c;搜個碼搞定 3、解鎖工具macOS Unlocker 開始安裝&#xff1a; 1、打開VMware軟件&#xff0c;新建一個系統…