Python讀取iOS安裝包IPA中的信息和圖片

最近需要對(duì)所有的iOS和Android工程通過(guò)jenkins持續(xù)集成励烦,軟件的編譯、打包泼诱、企業(yè)分發(fā)版的ipa發(fā)布都需要自動(dòng)化坛掠。在做ipa自動(dòng)化發(fā)布時(shí),需要拿到一個(gè)app里面相關(guān)的信息治筒,比如顯示名稱屉栓、版本號(hào)、bundle identifier等等耸袜。
然后在Jenkins構(gòu)建任務(wù)中通過(guò)增加Python腳本針對(duì)每個(gè)版本生成IPA,plist和包含itms安裝鏈接的網(wǎng)頁(yè)友多。

首先需要對(duì)iOS ipa包的結(jié)構(gòu)有些了解。

iOS IPA文件結(jié)構(gòu)

首先堤框,一個(gè)ipa其實(shí)就是一個(gè)zip文件改了后綴名域滥。如果你把ipa的后綴改回.zip,那么你就能通過(guò)各種解壓軟件直接解壓了胰锌。

解壓后的目錄結(jié)構(gòu)是:

Payload
    |-- ...
    |-- ...
    |-- 軟件名.app
        |
        |-- ...
        |-- ...
        |-- Info.plist

其中,Info.plist就是軟件信息的所在藐窄。

但是別高興得太早资昧,這里的Info.plist并不是純文本文件重慢,而是一種被稱為Binary Plist的東西晤斩。之前在做iOS開(kāi)發(fā)時(shí)官紫,工程里面用的plist幾乎都是XML形式的純文本文件,所以一開(kāi)始我理所當(dāng)然地認(rèn)為這個(gè)也是純文本文件轿曙,結(jié)果在這里卡了半天。在命令行運(yùn)行man plist就能看到下面這段話:

The property list programming interface allows you to convert hierarchically structured combinations of these basic types to and from two formats: standard XML and an optimized, opaque binary format.
所以不能看到.plist結(jié)尾的文件就當(dāng)文本文件處理狸膏。

PYTHON中相應(yīng)的LIBRARY狡恬,biplist和plistlib

在知道ipa的結(jié)構(gòu)之后,就能知道需要用哪些Python library了棺亭,第一個(gè)是zipfile虎眨,這個(gè)庫(kù)能夠處理zip類型的文件,并且可以在不解壓的情況下讀取里面某個(gè)文件的內(nèi)容镶摘。另外一個(gè)是plistlib嗽桩。但是需要注意的是,在Python 3.4之前凄敢,這個(gè)庫(kù)是不支持 Binary Plist 的解析的碌冶。所以如果使用 Python 2.7 的話,需要使用三方庫(kù)biplist涝缝。

下面使用 Python 3.4 為例進(jìn)行解析扑庞。之所以選擇 Python 3.x 是因?yàn)?2.x 版本在處理 Unicode 和非 Unicode 混用時(shí)非常麻煩。而 Python 3.x 起拒逮,所有的 string 都使用 Unicode 編碼了罐氨,就跟 ObjC 中一樣。

import zipfile, plistlib, sys, re

def analyze_ipa_with_plistlib(ipa_path):
    ipa_file = zipfile.ZipFile(ipa_path)
    plist_path = find_plist_path(ipa_file)
    plist_data = ipa_file.read(plist_path)
    plist_root = plistlib.loads(plist_data)
    print_ipa_info (plist_root)

def find_plist_path(zip_file):
    name_list = zip_file.namelist()
    pattern = re.compile(r'Payload/[^/]*.app/Info.plist')
    for path in name_list:
        m = pattern.match(path)
        if m is not None:
            return m.group()

def print_ipa_info(plist_root):
    print ('Display Name: %s' % plist_root['CFBundleDisplayName'])
    print ('Bundle Identifier: %s' % plist_root['CFBundleIdentifier'])
    print ('Version: %s' % plist_root['CFBundleShortVersionString'])

if __name__ == '__main__':
    args = sys.argv[1:]
    if len(args) < 1:
        print ('Usage: python3 ipaanalyze.py /path/to/ipa')

    ipa_path = args[0]
    analyze_ipa_with_plistlib(ipa_path)

首先使用zipfile將ipa文件打開(kāi)消恍,zipfile中岂昭,namelist()方法能夠列出里面包含的所有文件路徑,并返回一個(gè)list狠怨。根據(jù)ipa的結(jié)構(gòu)约啊,我們要找的Info.plist是Payload/軟件名字.app/Info.plist,所以這里使用一個(gè)正則表達(dá)式找到這個(gè)文件路徑佣赖。

ZipFile.read()這個(gè)方法恰矩,能夠在不解壓zip文件的情況下讀取里面的內(nèi)容,在Python 3.4中返回的是bytes類型憎蛤,再使用plistlib.loads()載入外傅。其中,loads()是 Python 3.4 才加入的新API俩檬,它接收一個(gè)bytes對(duì)象萎胰,將其解析成相應(yīng)的Python對(duì)象。

這樣棚辽,這個(gè)plist文件就變成了一個(gè)dict技竟,從而可以取到里面的內(nèi)容。

如果使用 Python 2.7屈藐, 則可以用biplist代替榔组,這個(gè)庫(kù)使用的是跟 Python 2.7 中plistlib相同的API,由于不想改服務(wù)器上默認(rèn)的python2.7熙尉,我使用的是biplist。代碼如下:


   info_plist = workspace + "/build/Release-iphoneos/" + project + ".app/Info.plist"
   print(info_plist)

   try:
       plist = readPlist(info_plist)
    except (InvalidPlistException, NotBinaryPlistException), e:
       print "Not a plist:", e
       return -1

   display_name = plist['CFBundleDisplayName']
   identifier = plist['CFBundleIdentifier']
   short_version = plist['CFBundleShortVersionString']

   print ('Display Name: %s' % display_name)
   print ('Bundle Identifier: %s' % identifier)
   print ('Version: %s' % short_version)

如果不使用 Python搓扯,或者不想用這些類庫(kù)检痰,則可以通過(guò)一些外部程序來(lái)解決Binary Plist的讀取問(wèn)題。比如使用/usr/libexec/PlistBuddy或者是plutil锨推,這些都是 OS X 自帶的工具铅歼,通過(guò)它們,你可以讀取Plist中的指定項(xiàng)爱态,或者直接把plist變成JSON文件谭贪。

讀取ipa .app目錄下的圖片并還原

由于Xcode工程中圖標(biāo)的文件名和位置都不固定,拿到AppIcon需要分析工程文件和AppIcon.appiconset/Contents.json文件內(nèi)容锦担,感覺(jué)分析過(guò)程太復(fù)雜了俭识,容易出錯(cuò)誤,因此還是想通過(guò)分析編譯后的build/Release-iphoneos/myproject.app/包目錄下找洞渔。app中所有的圖片都在根目錄下套媚,但這些圖片文件已經(jīng)被xcode處理過(guò)了,在瀏覽器中顯示為空白磁椒,因此需要想辦法把圖片文件還原堤瘤。
在網(wǎng)上找到了一個(gè)python腳本,iPIn iPhone PNG Images Normalizer, 感覺(jué)這個(gè)代碼時(shí)間太久了浆熔,2007年寫的本辐,測(cè)試了下不能處理正確圖片。
在這篇文章的評(píng)論里面發(fā)現(xiàn)一個(gè)鏈接https://gist.github.com/urielka/3609051医增, 應(yīng)該是個(gè)2012年的改進(jìn)版本慎皱,看下面的評(píng)論說(shuō)是可用,實(shí)驗(yàn)了下果然可以叶骨。圖標(biāo)問(wèn)題解決了茫多,處理后的圖片可以在瀏覽器正常顯示了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末忽刽,一起剝皮案震驚了整個(gè)濱河市天揖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌跪帝,老刑警劉巖今膊,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異伞剑,居然都是意外死亡斑唬,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赖钞,“玉大人,你說(shuō)我怎么就攤上這事聘裁⊙┯” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵衡便,是天一觀的道長(zhǎng)献起。 經(jīng)常有香客問(wèn)我,道長(zhǎng)镣陕,這世上最難降的妖魔是什么谴餐? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮呆抑,結(jié)果婚禮上岂嗓,老公的妹妹穿的比我還像新娘。我一直安慰自己鹊碍,他們只是感情好厌殉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著侈咕,像睡著了一般公罕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耀销,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天楼眷,我揣著相機(jī)與錄音,去河邊找鬼熊尉。 笑死罐柳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的帽揪。 我是一名探鬼主播硝清,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼转晰!你這毒婦竟也來(lái)了芦拿?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤查邢,失蹤者是張志新(化名)和其女友劉穎蔗崎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體扰藕,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缓苛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片未桥。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡笔刹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冬耿,到底是詐尸還是另有隱情舌菜,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布亦镶,位于F島的核電站日月,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏缤骨。R本人自食惡果不足惜爱咬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绊起。 院中可真熱鬧精拟,春花似錦、人聲如沸虱歪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)实蔽。三九已至荡碾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間局装,已是汗流浹背坛吁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铐尚,地道東北人拨脉。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像宣增,于是被迫代替她去往敵國(guó)和親玫膀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容