iQuery的一個主要目標就是提供一個跨平臺的控件查詢機制,那就需要考慮如下幾個平臺差異性:
編程語言的差異,例如iOS可以使用Object-C、JavaScript等語言編程,Android平臺使用Java,而Windows 8平臺使用C#、C++,網頁自動化程序例如Selenium又支持很多編程語言。
iQuery在設計時就考慮到這些差異性,我們復用antlr這個工具,它已經提供了生成多種編程語言代碼的功能,可以很快生成C#、C++、JavaScript、Java、Object-C、Python、Ruby等代碼,這樣只要維護一套語法就可以了。
雖然當前只實現了Java和JavaScript的版本,但對其他編程語言的支持也很容易實現,這是iQuery的第一個擴展點。
控件的差異性,不僅各平臺有一些不同的控件,例如Android上的ExpandableListView在 iOS上就找不到對應的控件,而且同一個控件在不同平臺的名字也不一樣,例如iOS上的UIASwitch基本上可以等價于Android和 Windows 8上的Radio,這樣都是在設計iQuery都需要去考慮的。
針對各平臺控件的差異性,iQuery的做法是提供按類型名查詢控件的語法,例如在Andorid上可以直接用
“>> ExpandableListView”
這樣的查詢語句找到界面上所有的ExpandableListView,而在iOS上可以使用
“>> UIAScrollView”
而針對同一控件在各平臺名字不同的情況,iQuery的做法是提供一個偽類的概念,這個概念也是借自jQuery,例如下面的偽類就統一表示了各平臺下可以當作單選框按鈕的控件:
“:radio”
然而,在實現iQuery的時候,我們并不能假設:radio在Android上就是RadioButton控件,在iOS上就應該是 UIASwitch,在Windows Phone上就是RadioBox控件,因此我們決定將定義偽類的控制權交給開發者,這是iQuery的第二個擴展點。
控件屬性的差異性,例如同是按鈕控件,在iOS上就是UIAButton.name(),而在Android上卻又是mText屬性,甚至有些屬性在不同的平臺上,有的存在,有的不存在,比如說Android上有mBottom屬性,在iOS上就不存在。
跟解決控件的差異性方法類似,iQuery除了提供按屬性名和方法名讀取屬性值以外,例如
iOS上的
“:button [name = ‘確定’]”
Android上的
“:button [mText = ‘確定’]”
為了統一表達控件在各平臺通用的屬性,iQuery還提供了偽屬性的概念,比如上面的例子可以使用下面的查詢完成:
“:button [:text = ‘確定’]”
跟偽類一樣,偽屬性也是可以由開發者自定義,這是iQuery的第三個擴展點。
UI自動化框架的差異,例如 iOS UI自動化測試的框架必然和Andorid UI自動化測試框架不同,但無論如何不同,當今大部分操作系統的圖形界面都有下面的性質:
界面由控件樹組成。
各控件有屬性的概念。
為了盡可能的支持更多的框架,iQuery將上面的性質封裝成兩個接口,因此對新平臺的支持,只要實現這兩個接口就可以了
本文介紹擴展偽類、偽屬性和添加對新平臺支持的方法,后續文章會解釋支持其他編程語言的做法。
擴展偽類
在Java版本中,在iQA.Runtime.jar包里,可以通過iQueryParser. registerPseudoClass這個函數注冊一個新的偽類,步驟如下:
使用
iQueryParser. createParser(String iquery, boolean registerPseudo)
創建一個iQueryParser實例。
再使用iQueryParser. registerPseudoClass(String name, IPseudoClass func)注冊一個新的偽類,例如下面的代碼,注冊一個名為text的偽類,過濾方式為所有類型名以EditText結尾的控件:
parser.registerPseudoClass("text", new IPseudoClass() {
public boolean resolve(ITreeNode node) {
return filterByNameEndsWith(node, "EditText");
}
});
在JavaScript版本中,暫時不支持擴展偽類的做法,后續版本會添加這個功能。
擴展偽屬性
在Java版中,通過iQueryParser.registerPseudoAttribute函數注冊一個新的偽屬性,步驟如下:
使用iQueryParser. createParser(String iquery, boolean registerPseudo)創建一個iQueryParser實例。
再使用iQueryParser. registerPseudoAttribute (String name, IPseudoAttribute func)注冊一個新的偽屬性,例如下面的代碼,注冊一個名為bottom的偽類:
parser.registerPseudoAttribute("bottom", new IPseudoAttribute() {
public String resolve(ITreeNode node) {
return node.getProperty("mBottom").getValue();
}
});
在iOS的JavaScript版本中的做法是:
引入以下幾個JavaScript文件:
#import "common.js";
#import "antlr3-all-min.js";
#import "iQueryLexer.js";
#import "iQueryParser.js";
#import "error.js";
創建一個iQuery實例:
var iq = new iQuery(selector);
注冊偽屬性:
iq.parser.registerPseudoAttrs("bottom", function(uiaobj) {
if ( uiaobj != undefined && uiaobj.rect != undefined ) {
var rect = uiaobj.rect();
return rect.origin.y + rect.size.height;
}
});
添加對新平臺的支持
當前支持Java版本的擴展,擴展方式是:
在工程里添加iQA.Runtime.jar包依賴。