code

顯示具有 ios 標籤的文章。 顯示所有文章
顯示具有 ios 標籤的文章。 顯示所有文章

2018年1月4日 星期四

iOS testing 3 - XCode 9 new testing features

這是WWDC 2017 #409 "What's new in testing" 筆記。

New Async waiting API

通常會用到async API的情況如下:



之前Xcode6 我們需要這樣做async waiting:



上面程式要開啟遠端某個文件, 在實際上開啟之前(document.open()),我們先定義一個expectation,然後為此async operation設定expectation,當此operation真的完成的話,在success closure裡面我們就要關閉或說fulfill 這個expectation。

限制如下:
1. timeout會被判定成failure
2. waiting (e.g. waitForExpectations()) 是XCUITest instance method,綁死了
3. 沒有nested waiting


XCTWaiter
這是針對上面限制的改良,主要是把waiting從XCUITest分離出來:


timeout的處理方式提供了delegate或是 closure,或是XCTWaiter intance,更加彈性了。

另外記得去看XCTestExpectation的new features。

Multiple App UI Testing

現在可以在不同的target app間測試互動情況,有需要再研究。



不知道可不可以launch 3rd party來測試?

Performance of UI Testing

要找到畫面中的一個ui element,我們必須去做query。XCUIQuery是需要用到accessibility data,舊的做法是test app藉由interprocess communication,去要某個時間點target app的serialized "snapshot",就是app state snapshot:


這個做法在state相當龐大的時候(例如app使用超多記憶體),會有testing performance impact,甚至會造成某些testing timeout,使得test case被誤判成failure。更極端有可能因為query使用太多記憶體而process被killed。

要到snapshot,判別query的責任是落在test app身上。


xcode9的做法是:
(1) remote query: 減少interprocess data



現在改成只傳query data給target app,然後query在target app身上做(那還不是會造成target app performance impact?!),最後再把query results傳回給testing app。

所以這樣能夠減少testing app負擔,以及減少interprocess communication,這得到30%的記憶體與速度改善:





(2) query analysis: 透過分析來減少一個query要實現需要的最小的app states snapshot,這樣當然也可以減少運算時間與memory。



(3) programmer tools: 透過programmer對不同測試情境的知識,可以決定是何時可以做較短的query,提供"firstMatch"這類method讓query不用走完整個query data hierarchy。


firstMatch是改善最多的,但這是需要programmer對ui layout的了解才有辦法達成!

一個原則就是,你query的越精確,越會有好的testing performance,所以這樣也同樣無法依賴所謂的UI Recording,基本上是個廢物說實在的:




新架構避免使用的寫法

不要用block(closure) based NSPredicate,因為block不能被serialized,也不能在runtime被optimize:


上面說道的optimization都不能用了,所以避免使用block based NSPredicate 。



更好的test report: Activities / Attachments / Screen shots

activity是把一堆test command group起來,變成一個存活較久的test:



這個好處是讓test report看起來很簡潔,也比較有表達性:





XCode 9提供了screenshot api,可以讓XCUIElement或是整個screen都擷取快照圖片。
attachment則是讓test report把一些(包括screen shots) 想要跟activity 一起呈現在test report中的data包裹起來:



所以在test report中就會看到activity包含了attachments (此例中是screenshots):




動工吧!!!!

2017年12月23日 星期六

iOS Universal Links and Android App Links

Android App Links

我們可以把app中的content透過連結,讓使用者直接開啟app到那個特定的content,有以下兩種連結方方法可以做到:

Deep Links: 這是使用URL的方法,我們必須在app中加入intent filters,然後解析intent帶來的data來開啟相對應的activity。潛在問題是其他的app如果也listen相同的intent,則可以獲取此連結開啟權力

Android App Links (Android 6.0+ / api 23+): 設定一個app為某種link的default handler,使用者可以在Android系統設定中更改此設定。好處包括:
  • 需驗證HTTP URL domain ownership,不會被其他app冒用
  • 如果使用者沒安裝app的話,會直接導向web
  • support Instant Apps (不用安裝app就可以使用app)
  • 可以從以下地方導到app content:
    • mobile browser中點擊Google search結果
    • Google Search app
    • Android screen search
    • Google Assistant
可以說App Links是強化版本的URL scheme deep links。怎麼實現App Links呢?

簡單來說:
1. 放一個json file到一個https的網站,讓Android用來驗證網站所有權以及app關聯性。
2. 在app manifest宣告某個activity相關的intent filter,以及要設定autoVerify為true,這樣Android才會在launch activity的第一次就驗證關聯性。

很簡單,困難點反而是在怎麼建立一個https網站,如果對我這種backend白癡來說的話。

iOS Universal Links

iOS Universal Links跟Android App Links就是一樣的東西,行為:
  • 如果有安裝app,則點擊網頁中的link會開啟app中的某個特定畫面
  • 如果沒安裝app則開啟Safari導到這個link連結的網頁
  • 不會被開啟其他宣稱能handle此url的app (同樣經過網站所有權驗證)
  • 不過如果原本已經開啟此domain web page,就不會開啟app
所有權認證的方式跟App Links一樣,放一個json file在某個static path下面,大概長這樣:



上面9JA89QQLNQ是team id,可以在developer portal找到,後面接的就是app id,整個構起一個identify這個app的key, value是一個array (paths),標明哪些path可以由app來handle,如果整個網站都在app有對應的handler,那就像上面黃色字樣寫的"*"。

或是部分被app handle的話:




結論

這兩個平台提供的Dee[ Link方法對server端幾乎沒有影響,設計很好!


2017年12月6日 星期三

Keychain & TouchID 整合

Keychain

keychain是一個database,每個key-value pairs稱為一個keychain item,所有的values都加密過,特別適合用來儲藏小size的user secrets。

Keychain需要link ios Security.framework,我們的application透過SecItem API來存取keychain items:



app process透過SecItem API把我們的request丟給另一個process "securityd",這算是一個中間人,因為他雖然可以query Keychain database,但是並沒有decrypt keychain value的能力,所以"securityd"會再把這個encrypted value丟到Apple A7+ chip上面的硬體security code processor稱為 Secure enclave,由此module決定是否要decrypt。

Keychain安全性

1. 被使用者iphone密碼保護
2. 被使用者iphone 出廠設定的unique device secret保護
3. keychain只有當使用者解鎖之後才能access
4. access control (只有儲存data的app能access自己的data)

總之Keychain是Apple保護某個on disk的secrets的功能,我們可以確信此protection是安全的,但是我們application的責任就是:不能把解密過後的secrets長期放到memory中(e.g. global/static variables),或是透過網路傳送


SecItem APIs

SecItem是C API:






Data protection classes

Keychain裡面的item能否被access,藉由設定以下幾種可能的protection profiles給kSecAttrAccessible attribute:



包括以下幾種(詳見api document說明):



但是以上幾種不能確定使用者到底有沒有設定device passcode,除非使用以下:


上面這個protection class 是說keychain只有當user authenticate之後才能access,而且當user lock device之後就不能access。當passcode被移除的話,在Secure enclave上的passcode secret就會被移除,所以再也無法解密被保護的items。


Keychain Access Control List (ACL)

每當app要access被ACL和touch id保護的keychain item的時候,以下這個畫面就會跳出來:



輸入device passcode標準介面:



ACL定義:
1. authentication,藉由policy control:



2. item accessibility



Touch ID Authentication

touch ID可以用來當作authenticate,用來驗證可否存取keychain裡面的item,安全性來自Secure enclave,所有的touch id data都存放在secure enclave中,而且所有的touch id operations都在secure enclave中完成,即便OS kernel被compromised也不影響其安全性,因為是一個sandbox。

Secure enclave如果發現touch id數次驗證未過的話,就會強制只能透過device passcode authenticate,重新輸入device passcode之後就能恢復使用touch id authentication。

注意keychain key operations也是在secure enclave中完成,所以跟touch id搭配是非常適合的。

使用ACL來進行touch id authentication是由LocalAuthentication framework提供API來讓application使用:




Code Example

儲存secrets: 原本沒有ACL control的keychain storage如下


如果我們加上ACL control:



讀取secrets



SecItemCopyMatching會啟動LocalAuthentication 功能,所以系統的指紋辨試或是passcode輸入畫面就會出現。不過為了不要block main thread,這個SecItemCopyMatching最好是放到global queue中。



2017年11月22日 星期三

ios XCode9 Continuous Integration

名詞解釋

scheme: 就是build script
bot: 執行schemes,也可以排程的process
Integration: 每次bot執行一次稱為一次integration

Continuous Integration Chart


好處
1. 早期整合,早期發現問題
2. 在server build/test,不用浪費開發者時間
3. 可以排程,測試各版本simulators/devices
4. 產生報表


pre-XCode9: 安裝XCode Server

要先安裝macOS server app:


這邊先略過了,畢竟xcode9已經發表了。


post-XCode9

藏在xcode 裡面:

WWDC 2017有影片說明整合進去xcode。

1. automatic code signing
2. 整合進入xcode 9
3. 自動在simulators / devices 上測試


Code Signing

app需要簽名認證,辨別是真實發行者,ios在app runtime會檢查此數位簽名,才能才能確保以下三件事情:


製作一個signature需要以下三個文件:


1. certificate:
2. provisioning file:
3. entitlement:

以上的細節可以在2016 WWDC XCode Automatic Code Signing影片中詳細解釋。

簡單來說,Xcode 9最大的改進就是把automatic code signing放入 Xcode Server

也唯有automatic code signing才能讓xcode server去在手機上自動化測試app,因為需要code signing (只要target有設定automatic signing):



這背後依賴另一個command line executable : Xcodebuild,所以第三方CI server(e.g. jenkins) 也可以利用此Xcodebuild command去做automatic code signing。



Setup XCode Server in XCode 9

1. 先到xcode preferences打開xcode server:



把右上角switch打開會自動設定,結果如下:



2.  在accounts pane加入xcode server當成“開發者一員”,因為這樣才會有bot (軟體機器人)讓我們來排成做事:



至於Manual Signing影片中有講到,可以先略過。


Setup a bot

在product menu最後有一個"create bot",點下去之後xcode會自動去看目前project是否是來自某個git repository (猜測應該是去scan專案目錄)以及下載的branch,然後會要求設定登入帳號密碼。

之後會有一連串的設定,都可以先採取預設值就好,反正都可以在更改。
接下來會來到要不要授權此 "server team member"來管理 automatic signing issues:



建立bot之後,似乎會馬上進行一次integration,所謂的integration包含以下步驟:
(a) 從repository下載branch
(b) build app
(c) provisioning / signing
(d) test


Distribution Signing 

開發過程中打包的app 稱為archive,這是需要development signing,流程相對簡單。
如果要發布到app store,需要做distribution signing,把archive再打包成.ipa檔案:



事實上有三種distribution signing,adhoc / enterprise / app store:


XCode server可以distribute signing似乎是個很大個改進?不確定,總之台下有歡呼就是了,之後有需要用到再說吧。



優點

1. 整合性超高
2. 可以parallel test,比較神奇的是,某些simulator連launch都沒有,不知道怎麼測試出來的?



3. automatic signing



2017年11月21日 星期二

iOS test 2 - UI test & XCTest framework

XCode 7的新功能

首先罵一下apple,好少的official tutorial,好爛的documentation!!!
這一點Android好太多!!!!

這在WWDC 2015出現,可以選左邊這個連結觀看影片。

整個UI test架構主要由以下三個classes構成:



XCUIApplication

這是UIApplication的代理人 (proxy),會永遠啟動一個新的process,幫助我們clean app state,XCUIApplication也是所有XCUIElement的最上層,形成一個element hierarchy:




XCUIElement

這是UIApplication中的UI element的代理人。

要找到畫面中的一個XCUIElement,我們需要進行query,其實體化物件為XCUElementQuery。要做任何event synthesis (例如tapping) 或是access property的動作一定要是unique element,否則XCTest不知道要找哪一個才是正確的,所以就會被判定成failure!


XCUIElementQuery

有一個安全測試XCUIElement是否存在的屬性: exists。
使用exists屬性,即便UI element已經不存在,或是非唯一,都不會使得test case被判定成failure。

每個query都會回傳一個set,可能有零到多個elements,可以用subscript operator (e.g. [ ] )來取得:




Relationship Query

1. Descendents (所有在某個ui element下面的ui element):



2. Children (direct descendents):



3. Containment:
這是當一堆無法unique分出來的elements,例如uitableview cell,但是他們subviews會有獨特的元素,就可以query他們的containment relationship,來代表此cell的獨特性。


Filter a query

filter一個傳回來的query:
1. UI type


或者是方便的api:




2. ids: accessibility id / label / title

3. predicates

4. relationship




Query evaluation

算是lazy evaluation,只有當以下情況才會被evaluated:


Event Synthesis

這個就是模擬使用者能做的互動,所有程式通道都是跟真實互動時的通道一樣。

Non-accessible UI Elements

如果發現某些element看得到,但是無法在test case access的話,可能有以下原因: