
本文主要介紹Fastlane的擴(kuò)展功能,基于UI Testing使用
snapshot與frameit進(jìn)行自動截屏、加殼。如果你還對Fastlane不了解,請先閱讀我上一篇文章《iOS開發(fā)fastlane從入門到入土(一):自動打包》
UI Testing
snapshot是基于UI Testing來實(shí)現(xiàn)的。UI Testing是蘋果在Xcode7上推出的一個自動化測試模塊。
1. 集成 UI Testing
新建一個UI Testing 的 target(如果項(xiàng)目中已經(jīng)存在,這一步可以略過)

點(diǎn)擊左上角的Scheme,選擇New Scheme,選擇新建的UITests

選擇新建的Scheme,選擇Edit Scheme,選擇Build,勾選Shared和Run

2. UI 行為錄制
首先,不要太擔(dān)心自己不會寫測試用例,UI Testing有個牛逼的功能就是可以錄制你的操作,你完全可以通過在錄制好的操作的恰當(dāng)點(diǎn)去生成截圖。當(dāng)然,如果你的app里需要更復(fù)雜的操作的話還是需要學(xué)習(xí)一下相關(guān)語法的。
一個新建的UITesting文件的基本結(jié)構(gòu)如下:
#import <XCTest/XCTest.h>
@interface XXXUITests : XCTestCase
@end
@implementation XXXUITests
- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
self.continueAfterFailure = NO;
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
[[[XCUIApplication alloc] init] launch];
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
- (void)testExample {
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
@end
選擇項(xiàng)目的Scheme,注意不要選擇UITests的Scheme,否則以下操作會報錯Please select a scheme where “xxx” is the executable

*注意:光標(biāo)一定要放在方法體內(nèi),不然紅色的圓點(diǎn)會變灰不可點(diǎn)擊
記錄一個簡單的
錄制完成后你可能會發(fā)現(xiàn)有報錯,例如以下這樣

這是Xcode的一個bug,只需要全局替換
\U替換為\u即可。你會發(fā)現(xiàn)上面獲取UI元素都是通過級聯(lián)查找到的,寫出來肯定會不美觀,如果你想更具可讀性,可以通過給控件設(shè)置
accessibilityIdentifier屬性來訪問。
使用command + U運(yùn)行UITests類中 每一個以test開頭的方法,或者直接點(diǎn)擊方法前面的播放按鈕運(yùn)行自動化測試

如果你運(yùn)行自動測試出現(xiàn)Pods庫頭文件找不到的錯,如下:

請前往以下的配置里將UITests在Debug和Release下改成Pod-xx.debug和Pod-xx.release(默認(rèn)都為None)

測試成功后方法前會出現(xiàn)?
關(guān)于UITesting更詳細(xì)的使用,可以閱讀onevcat的這篇博客
Snapshot
1. 配置 snapshot
進(jìn)入項(xiàng)目目錄,輸入以下命令,會在fastlane目錄下生成兩個文件:Snapfile和SnapshotHelper.swift
$ fastlane snapshot init
[?] ??
? Successfully created SnapshotHelper.swift './fastlane/SnapshotHelper.swift'
? Successfully created new Snapfile at './fastlane/Snapfile'
Snapfile文件:
# Uncomment the lines below you want to change by removing the # in the beginning
# 需要截圖的設(shè)備型號
devices([
#"iPhone 6",
#"iPhone 6 Plus",
#"iPhone 5",
#"iPhone 4s"
#"iPhone 8",
"iPhone 8 Plus",
#"iPhone SE",
"iPhone X"
])
languages([
"zh-Hans"
# "en-US",
# "de-DE",
# "it-IT",
# ["pt", "pt_BR"] # Portuguese with Brazilian locale
])
# The name of the scheme which contains the UI Tests
# scheme("SchemeName")
# Where should the resulting screenshots be stored?
# 截圖輸出目錄
# output_directory("./screenshots")
# remove the '#' to clear all previously generated screenshots before creating new ones
# 生成前清除所有截圖
clear_previous_screenshots(true)
# Arguments to pass to the app on launch. See https://docs.fastlane.tools/actions/snapshot/#launch-arguments
# launch_arguments(["-favColor red"])
# For more information about all available options run
# fastlane action snapshot
2. 導(dǎo)入SnapshotHelper
將SnapshotHelper.swift文件拖入到xxxUITests文件夾下,選擇加入哪個target的時候, 選擇加入到xxxUITests的target下

選擇加入的
target, 點(diǎn)擊 [確定] 以后,如果是OC項(xiàng)目會詢問你是否創(chuàng)建橋接文件(只有第一次拖入swift文件的時候才會提示, 你如果刪除了swift文件之后,再次向工程中拖入就不會提示讓你創(chuàng)建橋接文件了),文件名類似TargetName-Bridging-Header.h。
其實(shí)如果你是OC項(xiàng)目,不存在Swift文件里調(diào)用OC類,完全可以不創(chuàng)建這個文件,這個文件主要是用來import OC頭文件給Swift類調(diào)用的
3. 使用Snapshot自動截圖
在xxxUITests.m文件里#import "xxxUITests-Swift.h"引入頭文件,頭文件的名字是 “TargetName-Swift.h”(這個頭文件是系統(tǒng)默認(rèn)生成的,用來在OC里調(diào)用Swift類,不用我們手動創(chuàng)建,沒有智能提示,保證導(dǎo)入正確就可以了。)
// 引入這個類就引入了所有的Swift類
#import "xxxUITests-Swift.h"
在- (void)setUp方法中初始化Snapshot對象
- (void)setUp {
// In UI tests it is usually best to stop immediately when a failure occurs.
self.continueAfterFailure = NO;
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
XCUIApplication *app = [[XCUIApplication alloc] init];
[Snapshot setupSnapshot:app];
[app launch];
}
在測試用例方法適當(dāng)位置放入截圖代碼:
- (void)testExample {
XCUIApplication *app = [[XCUIApplication alloc] init];
[app.buttons[@"\u767b\u5f55"] tap];
// 截圖
[Snapshot snapshot:@"01Login" timeWaitingForIdle:10];
[app.buttons[@"nav profile"] tap];
}
運(yùn)行fastlane snapshot即可自動截圖
更多關(guān)于Screenshots的用法請參照官方文檔Screenshots Doc
Frameit
1. 安裝
使用frameit需要安裝依賴庫ImageMagick,官方推薦安裝方式:
brew install libpng jpeg imagemagick
如果你已經(jīng)安裝了imagemagick但是看到以下錯誤信息:
mogrify: no decode delegate for this image format `PNG'
你可能需要重新安裝并從源代碼構(gòu)建。運(yùn)行以下命令:
brew uninstall imagemagick; brew install libpng jpeg; brew install imagemagick --build-from-source
通過命令fastlane frameit setup或者fastlane frameit download_frames更新最近的設(shè)備外殼。
2. 使用
- 簡單使用
# 默認(rèn)為黑色外殼 支持顏色有white、silver、rose_gold、gold
frame_screenshots(white: true) #外殼為白色
- 進(jìn)階使用
如果你需要弄些背景和文字描述,那么你需要通過配置Framefile.json文件去定制化需求。
首先需要你在screenshots文件目錄下創(chuàng)建Framefile.json,cd到screenshots目錄輸入touch Framefile.json
然后進(jìn)入你的截圖多語言zh-Hans目錄下,新建title.strings和keyword.strings文件,這兩個文件是放標(biāo)題和關(guān)鍵字的。
注意:這兩個.strings文件一定要是UTF-8或者UTF-16 BE with BOM編碼,或者直接由Xcode生成,第一行必須是空行。
將背景圖放在screenshots目錄下,新建一個fonts文件夾,里面放你需要用到的字體文件,這里是官方的一個sample。
完成后你的目錄結(jié)構(gòu)應(yīng)該是這樣的:
Framefile.json文件:
{
"default": {
"keyword": {
"fonts": [
{
"font": "./fonts/PingFang.ttc",
"supported": ["en-US"]
},
{
"font": "./fonts/PingFang.ttc",
"supported": ["zh-Hans"]
}
]
},
"title": {
"fonts": [
{
"font": "./fonts/PingFang.ttc",
"supported": ["en-US"]
},
{
"font": "./fonts/PingFang.ttc",
"supported": ["zh-Hans"]
}
],
"color": "#545454" // 標(biāo)題顏色
},
// 自定義背景圖片
"background": "./background.jpg",
// 圖的內(nèi)邊距
"padding": 60,
// 是否完全顯示手機(jī)框 false 為底部會被隱藏部分視圖
"show_complete_frame": false,
// 關(guān)鍵字是否在標(biāo)題上面 false表示關(guān)鍵字與標(biāo)題在同一行
"stack_title" : true,
// 標(biāo)題在屏幕下方還是上方 false 為上方
"title_below_image": false,
// 外殼顏色 優(yōu)先級更高 (Valid values are BLACK,WHITE,GOLDandROSE_GOLD`)
"frame": "GOLD"
},
"data": [
{
"filter": "1", // 這是圖片名
"keyword": {
"color": "#d21559" // 關(guān)鍵字顏色
}
},
{
"filter": "2",
"keyword": {
"color": "#feb909"
}
},
{
"filter": "3",
"keyword": {
"color": "#aa4dbc"
}
},
{
"filter": "4",
"keyword": {
"color": "#31bb48"
}
}
]
}
title.strings文件:
"1" = "第一張圖標(biāo)題";
"2" = "第二張圖標(biāo)題";
"3" = "第三張圖標(biāo)題";
"4" = "第四張圖標(biāo)題";
keyword.strings文件:
"1" = "自動";
"2" = "打包";
"3" = "截圖";
"4" = "證書";
在Fastfile文件里寫個任務(wù):
desc "給截圖套殼"
lane :framePic do
frameit(
# 白色
white: true,
# 使用iPhone 5s替代iPhone SE框架
use_legacy_iphone5s: true,
# 使用iPhone 6s替代iPhone 7框架
use_legacy_iphone6s: true,
# 使用iPhone X 替代iPhone XS框架
use_legacy_iphonex: true,
# 截圖所在路徑
path: "./fastlane/screenshots"
)
end
運(yùn)行fastlane framePic

當(dāng)當(dāng)當(dāng)當(dāng)大功告成~

更多關(guān)于Frameit的用法請參照官方文檔Frameit Doc
