一、背景
在我們平時(shí)開(kāi)發(fā)過(guò)程中,需要頻繁的給測(cè)試人員打包測(cè)試,一般的流程都是:
Xcode打包 --> 導(dǎo)出ipa文件 --> 上傳蒲公英/fir.im --> 通知測(cè)試人員
一套流程下來(lái)得15分鐘左右,而且需要頻繁操作,相當(dāng)麻煩。所以趁最近比較閑,就想著寫(xiě)個(gè)腳本,只需要運(yùn)行腳本就能完成上述所有流程。
當(dāng)然了,也有非常成熟的自動(dòng)化構(gòu)建方案:Jenkins + fastlane,網(wǎng)上資料很多,本篇文章不做介紹。
二、需求分析
其實(shí)前面三步都很簡(jiǎn)單,特別是第一二步,都是Xcode自帶的命令。上傳也只需要去對(duì)應(yīng)的官網(wǎng)看看文檔也能找到相應(yīng)的方法,比較復(fù)雜的是最后一步,如何通過(guò)腳本通知測(cè)試人員。最簡(jiǎn)單的方法就是通過(guò)釘釘web hook機(jī)器人,但是我們一般辦公時(shí)都是使用QQ或微信,如果能直接通過(guò)腳本給QQ或微信發(fā)消息就好了。在之前web版QQ還未停用時(shí),網(wǎng)上也有很多方案能實(shí)現(xiàn)需求,現(xiàn)在都不能用了。此問(wèn)題也困擾了我好幾天,直到有一天看到
Mac微信助手,就在想他是怎么實(shí)現(xiàn)自動(dòng)回復(fù)消息的呢?這是一個(gè)開(kāi)源框架,相信有一定基礎(chǔ)的iOS開(kāi)發(fā)者應(yīng)該都能看懂,本篇文章也主要是分享并記錄自己學(xué)習(xí)的過(guò)程并作拋磚引玉的作用。
三、實(shí)現(xiàn)
1.Xcode打包并導(dǎo)出ipa
# 清除緩存
xcodebuild clean -workspace TongueCheck.xcworkspace -scheme $schemeName -configuration $configType
# 打包
xcodebuild archive -workspace TongueCheck.xcworkspace -scheme $schemeName -configuration $configType -archivePath $archivePath
echo "?? 正在導(dǎo)出ipa"
xcodebuild -exportArchive -archivePath $archivePath -exportPath $exportPath -exportOptionsPlist $optionsPath
其中
- schemeName 是工程的名字
- configType 是Debug或者Release,當(dāng)然還可以是自定義環(huán)境
- archivePath 是編譯文件生成的路徑
- exportPath 是導(dǎo)出ipa的路徑
- optionsPath 是配置文件plist的路徑,可以手動(dòng)用Xcode打包并導(dǎo)出一次,會(huì)自動(dòng)生成ExportOptions.plist文件
2. 上傳fir.im
需安裝工具 https://github.com/FIRHQ/fir-cli/blob/master/doc/install.md
fir login $apiToken
#發(fā)布應(yīng)用到fim
echo "?? 正在上傳fir.im"
addr=`fir publish "$exportPath/xxx.ipa" -c "$changeLog" --skip-update-icon | sed -n -E 's;^.*s*Published succeed: ([^ ]+)\s*.*$;\1;p'`
if [ -z "$addr" ] ; then
echo "?? fir publish之后獲取不到鏈接。重試。。"
exit 0
fi
echo "? 安裝包地址:$addr"
其中
- apiToken 登錄fir.im網(wǎng)頁(yè)版就能查詢(xún)到
- changeLog 是更新日志
3. 通知QQ或微信
QQ和微信都有相應(yīng)的開(kāi)源庫(kù) 下面我只介紹微信的,QQ的原理其實(shí)是一樣的。
我們把工程下載下來(lái),會(huì)發(fā)現(xiàn)Run Script里面有一段腳本
#!/bin/bash
app_name="WeChat"
framework_name="WeChatExtension"
app_bundle_path="/Applications/${app_name}.app/Contents/MacOS"
app_executable_path="${app_bundle_path}/${app_name}"
app_executable_backup_path="${app_executable_path}_backup"
framework_path="${app_bundle_path}/${framework_name}.framework"
# 備份WeChat原始可執(zhí)行文件
if [ ! -f "$app_executable_backup_path" ]
then
cp "$app_executable_path" "$app_executable_backup_path"
fi
cp -r "${BUILT_PRODUCTS_DIR}/${framework_name}.framework" ${app_bundle_path}
./"Rely"/insert_dylib --all-yes "${framework_path}/${framework_name}" "$app_executable_backup_path" "$app_executable_path"
閱讀之后會(huì)發(fā)現(xiàn),原理其實(shí)就是把工程編譯之后生成的framework,通過(guò)insert_dylib注入到Mac程序中,并替換掉原來(lái)的程序,同時(shí)也將原來(lái)的進(jìn)行了備份,方便卸載。
我們?cè)趍ain.mm中可以看到下面這一段代碼
static void __attribute__((constructor)) initialize(void) {
NSLog(@"++++++++ WeChatExtension loaded ++++++++");
if (@available(macOS 10.14, *)) {
[NSObject hookTheme];
}
[NSObject hookWeChat];
[NSObject hookMMChatsTableCellView];
[NSObject hookMMStickerMessageCellView];
}
看到這里,相信大家都能知道插件的原理了吧,就是對(duì)原函數(shù)進(jìn)行hook。至于如何知道原庫(kù)中的類(lèi)名以及方法名就不在本篇文章中介紹了,網(wǎng)上也有很多逆向相關(guān)的文章。
WeChat+hook.m是hook消息發(fā)送與接收的文件,現(xiàn)在我們可以調(diào)用hook之后的方法進(jìn)行消息發(fā)送了,那么如何用腳本調(diào)用方法呢?其實(shí)作者已經(jīng)提供了相應(yīng)的方法,但是我在看文檔時(shí)并未看到相關(guān)介紹,原因未知。其實(shí)方法也很簡(jiǎn)單,就是監(jiān)聽(tīng)本地端口,在收到請(qǐng)求后解析參數(shù),調(diào)用方法即可。具體代碼在YMWebServerManager.m 文件中。
當(dāng)然了,我們也可以自己實(shí)現(xiàn)一些需要,進(jìn)行二次開(kāi)發(fā)。
self.webServer addHandlerForMethod:@"POST" path:@"/wechat-plugin/send-message"
可以看到原插件中已經(jīng)存在我們需要的功能了,端口是52700,我們的腳本發(fā)送消息就很簡(jiǎn)單了
curl http://localhost:52700/wechat-plugin/send-message -X POST -d 'userId=xxx&content=測(cè)試注意啦!《XXX》iOS端有如下更新:
'$changeLog'
下載地址:'$addr''
其中
- userId 對(duì)方微信id 并不是微信號(hào),獲取方式我還不太清楚,我是通過(guò)斷點(diǎn)來(lái)看的... 相對(duì)而言QQ的userId對(duì)應(yīng)的就是QQ號(hào)或者群號(hào),多了一個(gè)type參數(shù),具體可以看開(kāi)源框架
- content 是發(fā)送的消息,目前只支持文本,不過(guò)已經(jīng)能滿(mǎn)足我們的需求了
總結(jié)
至此我們的需求也就可以實(shí)現(xiàn)了,我們只需要運(yùn)行腳本耐心等待,就能實(shí)現(xiàn)之前的一系列操作了。當(dāng)然了如果涉及到多人開(kāi)發(fā),在打包之前還應(yīng)加上拉取代碼等操作,相信也很簡(jiǎn)單。
如果有問(wèn)題可以留言或者加我QQ進(jìn)行交流。
免責(zé)聲明
- 使用插件有風(fēng)險(xiǎn),使用需謹(jǐn)慎。
- 本文只作學(xué)習(xí)與交流作用,不可用于商業(yè)和個(gè)人其他意圖。若使用不當(dāng),請(qǐng)使用者自行承擔(dān)。
- 如果您發(fā)現(xiàn)本文有侵犯您的知識(shí)產(chǎn)權(quán),請(qǐng)與我取得聯(lián)系,我會(huì)及時(shí)修改或刪除。huqigu@163.com