iOS程序員效率提升利器之AppleScript
這篇文章和大家分享我平時(shí)工作時(shí),用來提升效率的神器之一:AppleScript。
AppleScript 雖然是一種腳本語言,但在我看來是最接近自然語言和最不具備計(jì)算機(jī)特質(zhì)的編程語言了。即使沒有計(jì)算機(jī)基礎(chǔ),在閱讀基礎(chǔ)文檔和幾個(gè)樣例腳本之后,馬上就能動(dòng)手寫出實(shí)用的腳本工具。
我感覺很多使用 Mac 系統(tǒng)的同學(xué)可能都沒意識(shí)到,與自己每天作伴的 Mac 系統(tǒng)上還有這么一個(gè)強(qiáng)大高效的腳本語言,可以從各個(gè)方面提升自己的工作效率。接下來的文章和大家分享我使用 AppleScript 的兩個(gè)場(chǎng)景。
在開始之前,先簡單概括下 AppleScript 的應(yīng)用環(huán)境。我們的 Mac 系統(tǒng)從應(yīng)用的角度來看,其實(shí)就是一堆 App 的集合,系統(tǒng)自帶的 App(Mail,Safari,Terminal 等)和安裝的第三方 App(Firefox,Chrome,Outlook,iTerm 等),這些主流的 App 其實(shí)都向系統(tǒng)暴露了一些實(shí)用接口,用來將一些高頻操作自動(dòng)化。誰來調(diào)用這些接口呢?AppleScript。AppleScript 可以將這些 App 和 App 內(nèi)部的數(shù)據(jù),都當(dāng)作對(duì)象來訪問,甚至可以將不同 App 串聯(lián),自動(dòng)化之后形成一個(gè) workflow。
如何編寫 AppleScript 呢?Mac 自帶腳本編輯和運(yùn)行工具,通過 Spotlight Search 搜索 Script Editor 即可。運(yùn)行 Script Editor 之后,通過菜單 File -> Open Dictionary 即可打開如下圖所示一個(gè)文檔,里面列出來所有支持 AppleScript 的 App,以及各個(gè) App 所支持的接口調(diào)用。
提升工作效率,避免重復(fù)勞動(dòng)
我最近在研究如何降低 App 的 Crash 率,每天都要實(shí)時(shí)監(jiān)控是否有新的 crash 發(fā)生。所有可能嚴(yán)重的 crash 警報(bào)都通過郵件發(fā)送到我郵箱,一旦收到警報(bào)我需要將郵件中的 crash id 復(fù)制出來,去另一個(gè)網(wǎng)頁工具里查詢。每天早上看著一大堆警報(bào),如果要將所有的 crash id 手動(dòng)復(fù)制出來,一個(gè)個(gè)貼入網(wǎng)頁里查詢,操作很繁瑣。AppleScript 可以輕松將這個(gè)流程自動(dòng)化,一鍵搞定。步驟如下:
郵件分類
郵件都是保存在 Microsoft Outlook 中,我首先設(shè)置一個(gè) rule,將所有郵件標(biāo)題包含 Trending Crash:xxx 字樣的郵件都存入一個(gè)子文件夾:iOS-Crash。
遍歷郵件
再通過 AppleScript 遍歷 iOS-Crash 目錄下所有文件:
- tell application "Microsoft Outlook"
- set theMessages to messages of folder "iOS-Crash" of default account
- repeat with theMessage in theMessages
- end repeat
- end tell
上面這段腳本讀起來是不是一目了然?就像是在和 siri 聊天一樣,告訴 siri 遍歷某個(gè)目錄下的全部郵件。
提取 Crash ID
AppleScript 的另一個(gè)強(qiáng)大之處是可以和系統(tǒng)自帶的各類常用命令行工具(比如 grep,sed,awk 等)交互,這意味著對(duì)文本和文件的操作可以游刃有余。接下來我要通過 sed 工具來提取郵件中的 Crash ID:
- tell application "Microsoft Outlook"
- set theMessages to messages of folder "iOS-Crash" of default account
- set crash_id_set to {}
- repeat with theMessage in theMessages
- set msgContent to plain text content of theMessage
- tell me to set crash_id to do shell script "echo " & quoted form of msgContent & " | sed -E -n 's_.* crash_id:(.+)}_\\1_1p'"
- if crash_id is not in crash_id_set and the length of crash_id > 0 then
- set crash_id_set to crash_id_set & crash_id
- end if
- end repeat
- end tell
關(guān)鍵代碼是這一行:
- tell me to set crash_id to do shell script "echo " & quoted form of msgContent & " | sed -E -n 's_.* crash_id:(.+)}_\\1_1p'"
AppleScript 用 tell xxx 的方式來切換腳步運(yùn)行環(huán)境,比如
- tell application "Microsoft Outlook"
是切換到 Outlook 的進(jìn)程中。
- tell me to
是切換到當(dāng)前用戶的運(yùn)行環(huán)境,因?yàn)槲覀円獔?zhí)行命令行腳步,需要更高級(jí)權(quán)限,所以要切換到當(dāng)前用戶進(jìn)程。
接下來通過 echo 將郵件的內(nèi)容傳遞給 sed,并提取出 crash-id,將值傳回 AppleScript 中的便利 crash_id,放入數(shù)組中。
拼裝 url 并在瀏覽器中打開
這是最后一步,將上面提取結(jié)果在瀏覽器中打開:
- tell application "Microsoft Outlook"
- set theMessages to messages of folder "iOS-Crash" of default account
- set crash_id_set to {}
- set param to ""
- repeat with theMessage in theMessages
- set msgContent to plain text content of theMessage
- tell me to set crash_id to do shell script "echo " & quoted form of msgContent & " | sed -E -n 's_.* crash_id:(.+)}_\\1_1p'"
- if crash_id is not in crash_id_set and the length of crash_id > 0 then
- set crash_id_set to crash_id_set & crash_id
- end if
- end repeat
- repeat with crash_id in crash_id_set
- set param to param & "%22" & crash_id
- end repeat
- tell me to do shell script "cat ~/Documents/AppleScripts/ios_crash_url | sed -n -E s_crash_ids_" & quoted form of param & "_p | xargs open "
- end tell
url 原始信息保存在文件 ios_crash_url 中,使用 sed 做簡單替換之后,將 url 傳遞個(gè) open 命令即可。
最后添加個(gè)命令 alias,就可以做到一鍵完成了。
- alias ioscrash='osascript /Users/fenggao/Documents/AppleScripts/outlook_ios_crash.scpt'
代碼重構(gòu)
我還使用過 AppleScript 來重構(gòu) Objective C 代碼,原理很簡單,將 Xcode 中選中的代碼以 text 的形式傳遞給 AppleScript,再通過 AppleScript 傳遞給命令行來操作。或者將 Xcode 當(dāng)前打開的類文件 path 通過 AppleScript 傳遞給命令行工具,接下來就是基礎(chǔ)的文件操作了,各類工具任由你選,比如我們可以使用本地編譯好的 clang 來分析類文件,來進(jìn)行針對(duì) Objective C 語法特征的文本修改。當(dāng)我們有大量的代碼文件需要修改,而且修改的規(guī)則遵循某個(gè)相同的 pattern 時(shí),使用腳本能起到事半功倍的效果。
通過 osascript 命令執(zhí)行 AppleScript 是方式之一,另一種方式是通過 Service。每個(gè) App 在菜單里都有 Services 一項(xiàng)。我們可以通過 Automator 來添加每個(gè) App 都能使用的 Service。
我們可以把一個(gè) Service 想象成一個(gè) workflow,而一個(gè) workflow 可以包含若干個(gè) action,執(zhí)行 AppleScript 就可以是其中的一個(gè) action。
首先通過 Spotlight Search 啟動(dòng) Automator,啟動(dòng)之后選擇創(chuàng)建 Service。之后可以看到所以支持的 action,選擇 Run AppleScript 并拖動(dòng)到右側(cè)的 workflow 區(qū)域,即可執(zhí)行某個(gè) AppleScript 了。當(dāng)然也可以拖動(dòng) Run Shell Script 到 workflow 區(qū)域,各個(gè) action 之間可以通過 stdin 傳遞數(shù)據(jù)。如下圖所示:
所有創(chuàng)建保存之后的 service 都會(huì)自動(dòng)保存到 ~/Library/Services/ 目錄下,一旦保存我們就可以在應(yīng)用的 services 目錄下看到我們的目標(biāo),比如我保存 xcode-text.workflow 之后。我在 Xcode 中選擇某些代碼,右鍵就可以看到我所創(chuàng)建的 service 了,如圖:
關(guān)鍵字:automator->service->action->applescript
總結(jié)
AppleScript 的應(yīng)用場(chǎng)景很廣泛,且很容易上手。一些 Mac App 的核心功能甚至都是利用 AppleScript 來編寫的。比如 Mac 上的剪貼板工具,就是通過 AppleScript 來操作其他應(yīng)用的當(dāng)前編輯文本,來實(shí)現(xiàn)歷史查找和插入功能。工具的強(qiáng)大與否在于使用之人如何用之,工具都是越用越稱手。