王詩宇,劉洪星 ,2,范家佳
1.武漢理工大學 計算機科學與技術學院,武漢 430063
2.武漢理工大學 交通物聯(lián)網(wǎng)技術湖北省重點實驗室,武漢 430070
為支持市場上存在的多種移動平臺(Android、iOS等),需對同一移動應用進行多次開發(fā)。對于同一移動應用,雖然其界面構件、整體布局以及后臺邏輯處理不需要做出很大的調(diào)整,但必須使用不同的技術實現(xiàn)同一用戶界面的不同版本[1]。用戶界面開發(fā)所耗費的時間和其代碼量在整個應用軟件開發(fā)過程中所占比重較大,是一個成本高、耗時的任務。當前大部分移動用戶界面開發(fā)方法都是面向運行平臺的,與具體的編程語言密切相關,以手工編碼為主,這種開發(fā)方式存在開發(fā)效率低、維護成本高、難以移植等缺點,因此需要研究跨平臺的用戶界面開發(fā)的有效方法。
模型驅(qū)動架構[2](Model Driven Architecture,MDA)是國際標準化組織OMG制定的具有標準性質(zhì)并被廣泛認可的軟件開發(fā)框架,它將軟件開發(fā)的注意焦點從代碼提升到模型這一更高的抽象層次。交互流建模語言(Interaction Flow Modeling Language,IFML)是OMG制定的可視化建模標準,用于表達軟件應用前端的內(nèi)容、用戶交互、行為控制[3]。Brambilla等人在IFML基礎上提出了Mobile IFML,使其能夠描述移動應用特征[4-5]。
模型驅(qū)動的移動用戶界面開發(fā)過程如圖1所示,其中Mobile IFML處于MDA架構的M2層[6],用于表示平臺無關[7]的移動用戶界面概念模型(Mobile User Interface Conceptual Model,MUICM)。要得到具體的移動用戶界面(Android平臺用戶界面、iOS平臺用戶界面、微信小程序用戶界面等),需執(zhí)行模型轉(zhuǎn)換操作,自動或半自動地生成用戶界面程序代碼。
圖1 模型驅(qū)動的移動用戶界面開發(fā)過程
本文以Android 為目標平臺,研究移動用戶界面概念模型到Android原生應用用戶界面代碼的轉(zhuǎn)換方法與工具。
模型到代碼的轉(zhuǎn)換可直接生成目標代碼,減少人工編寫的代碼量,大幅度提高開發(fā)效率。在該過程中需要考慮兩種不同的環(huán)境:模型處理器和目標環(huán)境。模型處理器是模型解析器、概念模型和代碼生成器有機組合的整體;目標環(huán)境是為生成最終代碼及其周邊環(huán)境準備的[8]。模型轉(zhuǎn)換的核心是映射規(guī)則(Mapping Rules)和轉(zhuǎn)換算法(Transformation Algorithm)。映射規(guī)則把模型中的元素映射為目標代碼中的具體元素,是模型轉(zhuǎn)換的前提[9];轉(zhuǎn)換算法負責模型處理器的調(diào)度[10],定義映射規(guī)則的執(zhí)行步驟和順序。
Mobile IFML 提供了一組基本構件(Construct)和連接規(guī)則(Connection Rules)。其中,MUICM元素表示MUICM 的頂層模型元素,可直接或間接包含其他所有模型元素;Screen(屏幕容器)元素是移動用戶界面的基本單元,用來描述界面組件的嵌套關系,可自身嵌套也可容納其他界面組件;List(列表)元素是一種視圖組件,表示移動用戶界面中的列表組件,必須嵌套于屏幕容器,可容納粒度更小的視圖組件;SelectionField(選擇域)元素表示移動用戶界面中允許用戶在一組選項中選擇其中一個或多個的區(qū)域,其余元素定義見文獻[3-4]。
借助Mobile IFML 表示得到的移動用戶界面概念模型基本構件遵循MVC(Model-View-Controller)軟件設計模式[3]。概念模型的邏輯結構表現(xiàn)為XML形式[11],如圖2所示。其中,
圖2 概念模型的XML表示
概念模型文件整體呈現(xiàn)為樹形結構,以圖2的概念模型為例,其樹形結構如圖3 所示。在樹形結構中,XML 節(jié)點與概念模型元素對應,節(jié)點屬性與概念模型元素屬性對應。如MUICM節(jié)點與模型中的MUICM元素對應;Screen 節(jié)點與模型中的Screen 元素對應,該節(jié)點 name、isHome 屬性與 Screen 元素的 name、isHome 屬性對應;SimpleField節(jié)點與模型中的SimpleField元素對應,該節(jié)點 name 屬性與 SimpleField 元素 name 屬性對應。根據(jù)組件粒度大小的不同可將樹形結構分為不同層次,每層出現(xiàn)的節(jié)點類型來自于特定的元素類型集合,用M1表示第一層節(jié)點類型集合,M2表示第二層節(jié)點類型集合,M3 表示第三層節(jié)點類型集合,以此類推。以M1和M2為例,對集合進行簡單說明,M1={MUICM},表示樹形結構的根(Root)節(jié)點類型只能是MUICM;M2={Screen,MViewComponent,OtherAction,CameraAction,MicrophoneAction,DataBindingGroup,NotificationEvent,MSensorEvent,MResourceEvent,NavigationFlow,Data-Flow},表示樹形結構的第二層節(jié)點類型來源于M2 集合中的元素類型。圖3中樹形結構的高度為四層,第一層僅包含MUICM 根節(jié)點,第二層包含Screen 節(jié)點,第三層包含 Form 節(jié)點,第四層包含 SimpleField、Label、SubmitEvent 等節(jié)點。從理論上來說,概念模型的樹形結構可以無限高,但結合實際移動應用中用戶界面的層次結構,屏幕容器的直接嵌套層數(shù)不宜過多,本研究將屏幕容器的直接嵌套層次限制為三層,整個樹形結構的高度最多為六層。
圖3 概念模型樹形結構
概念模型樹形結構是n(n≥0)個節(jié)點的有限集合。當n>0 時,有且僅有一個名稱為MUICM的根節(jié)點;根節(jié)點MUICM 作為對樹形結構的組織,不進行轉(zhuǎn)換;當n>1 時,除根節(jié)點以外的其余節(jié)點可以分為m(m>0)個互不相交的有限集合T1,T2,…,Tm,其中每一個集合本身也是一個樹形結構,稱為根節(jié)點的子樹,是模型轉(zhuǎn)換研究的重點;父節(jié)點和子節(jié)點之間代表一種嵌套關系,父節(jié)點容納子節(jié)點,子節(jié)點嵌套于父節(jié)點;對于嵌套于同一父節(jié)點的子節(jié)點,先出現(xiàn)的子節(jié)點優(yōu)先級較高。
Android構建用戶界面的方式有三種:(1)使用XML布局文件控制用戶界面;(2)在Java 代碼中控制用戶界面;(3)使用XML布局文件和Java代碼混合控制用戶界面。最后一種構建方式將變化小、行為比較固定的組件放在XML布局文件中進行管理,變化較多、行為較復雜的組件交給Java代碼進行管理。
本文采用第三種方式構建用戶界面。對于MUICM的視圖層(View)元素,生成XML標簽,并在Java代碼中獲取該界面組件;對于MUICM的控制層(Controller)和模型層(Model)元素,生成Java 類和方法并與相關界面組件關聯(lián),實現(xiàn)用戶與特定界面組件的交互、界面跳轉(zhuǎn)等功能。
映射規(guī)則的左側(cè)是移動用戶界面概念模型元素,右側(cè)是包含元數(shù)據(jù)的最終用戶界面代碼段,可分為四類,結合實例對不同類型的映射規(guī)則進行說明,如圖4所示。
圖4 映射規(guī)則實例
(1)直接映射:模型元素直接映射為目標代碼中的元素,如模型中的Label元素可映射為Android代碼中的TextView元素。
(2)屬性相關映射:針對同一模型元素,根據(jù)其屬性不同映射為目標代碼中的不同元素,如SelectionField元素,對其數(shù)據(jù)類型為Boolean 的isMultiSelection 屬性進行判斷,若為真,則映射為CheckBox 元素,否則映射為RadioButton元素。
(3)用戶交互相關映射:針對同一模型元素,根據(jù)用戶交互結果映射為目標代碼中的不同元素,如Simple-Field 元素,根據(jù)用戶選擇的目標元素類型可映射為EditText元素、AutoCompleteTextView元素或MultiAuto-CompleteTextView元素。
(4)父元素類型相關映射:針對同一模型元素,根據(jù)其是否有某類型的父元素映射為目標代碼中的不同元素,如Screen 元素,若其有類型為Screen 的父元素則映射為Fragment元素,否則映射為Activity元素。
轉(zhuǎn)換算法的工作實質(zhì)是讀取模型文件,解析得到所有模型元素;讀取映射規(guī)則文件,解析得到所有映射規(guī)則;對于每一個模型元素,調(diào)用與之匹配的映射規(guī)則進行轉(zhuǎn)換,得到目標元素,生成最終用戶界面代碼。本文設計的MUICM到Android用戶界面代碼轉(zhuǎn)換算法如下所示。
輸入:MUICM文件。
輸出:目標代碼文件。
步驟1 對XML 結構描述的概念模型文件進行解析,獲得概念模型根節(jié)點MUICM。
步驟2 獲取概念模型中所有類型為Screen 的直接子節(jié)點集合S(v),如果S(v)為空集,則結束,否則,執(zhí)行步驟3。
步驟3 獲取S(v)中的第一個節(jié)點v。
步驟4 生成以該節(jié)點name 屬性值為文件名稱的Java文件和XML文件。
步驟5 獲取v的所有類型非Screen 的直接子節(jié)點E(e),如果E(e)為空集,則轉(zhuǎn)向步驟11,否則,執(zhí)行步驟6。
步驟6 獲取E(e)的第一個節(jié)點e。
步驟7 獲取與該節(jié)點匹配的映射規(guī)則集合MR,按照如下判斷進行轉(zhuǎn)換:(1)若映射規(guī)則集中規(guī)則的個數(shù)為1,則直接進行轉(zhuǎn)換,生成目標類或目標標簽;(2)若映射規(guī)則集中規(guī)則的個數(shù)大于1,則根據(jù)映射規(guī)則中定義的條件進行匹配,若能匹配,則進行轉(zhuǎn)換,生成目標類或目標標簽。
步驟8 在得到目標類或目標標簽的基礎上,添加相關代碼細節(jié)信息,寫入步驟4 生成的Java 文件和XML文件中。
步驟9 獲取e的所有子節(jié)點集合E(e),若E(e)為空集,則執(zhí)行步驟10,否則轉(zhuǎn)向步驟6。
步驟10 獲取e的下一個兄弟節(jié)點ev,若ev為空,則執(zhí)行步驟11,否則轉(zhuǎn)向步驟7。
步驟11 獲取v的所有類型為Screen的直接子節(jié)點集合S(v) ,若S(v) 為空集,則執(zhí)行步驟12,否則轉(zhuǎn)向步驟3。
步驟12 獲取v的下一個兄弟節(jié)點bv,若bv為空,則結束,否則轉(zhuǎn)向步驟4。
在代碼生成之前,用戶可對移動用戶界面概念模型進行手動非實時驗證。如:同一Screen元素包含的元素name屬性唯一等。轉(zhuǎn)換算法根據(jù)源模型元素之間的邏輯關系和層次對生成目標代碼中的元素進行組合,保證代碼中各元素之間的組成關系符合其源模型元素在概念模型中的關系和約束,真正地實現(xiàn)概念模型到目標代碼的整體轉(zhuǎn)換,而不僅僅是單一的元素映射。轉(zhuǎn)換算法中補充的代碼段嚴格遵循Android 中XML 和Java 語言的規(guī)范,模型的合法性以及補充代碼的規(guī)范性等均保證了目標代碼的良構(well-formed)和有效(valid),即生成的目標代碼結構符合Android 用戶界面代碼中XML 和Java語言的一系列結構規(guī)則。同時,結構正確的代碼可以通過上下文有關性質(zhì)的檢查,包含類型檢查、一致性檢查、相關名字檢查、名字作用域分析檢查等。經(jīng)過轉(zhuǎn)換得到的目標代碼,可構建出基本的具體移動用戶界面,用戶可進行界面組件的添加和細化、界面布局的調(diào)整以及邏輯層代碼的填充完善,得到最終移動用戶界面。
模板(template)可以看作是目標代碼的原型,與目標代碼相似度較高,可讀性較強。模板化的代碼生成器包含三個主要組件:模板、語境和生成器。模板是目標文本文件的源文本,包含動態(tài)部分和靜態(tài)部分,其中動態(tài)部分由標注表示,標注會調(diào)用語境對象生成元素;語境是動態(tài)數(shù)據(jù)的源,即生成模板所需的數(shù)據(jù)模型,本文中的語境為移動用戶界面概念模型;生成器是結合模板和語境生成最終結果的工具,控制模板生成程序的執(zhí)行。對不同的語境使用同樣的模板,可生成對應的輸出結果。本文采用基于模板的代碼生成語言,構建模板化代碼生成器,對上述映射規(guī)則和轉(zhuǎn)換算法進行實現(xiàn)。
Acceleo[12]是 OMG的M2T(MOF Model to Text)規(guī)范[13]的標準實現(xiàn),是一個基于MDA 的開源自動代碼生成器,作為Eclipse 插件集成于Eclipse IDE 中。符合元模型類型(UML、ECore、用戶自定義的元模型等)的模型都可以作為Acceleo 的輸入,得到符合目標編程語言的任意代碼文件,如C、Java、Python等。Acceleo由多個成為模塊(module)的文件構成。其中,模塊以輸入模型遵從的元模型的URI 作為參數(shù),由模板構成;模板是文本產(chǎn)生式規(guī)則(text production rules)的序列(sequence);文本產(chǎn)生式規(guī)則是靜態(tài)文本(static text)、注釋(comments)、表達式(expressions)、模板調(diào)用(template invocation)和塊(block)的序列。本文按照Acceleo 的語法規(guī)則定義了映射規(guī)則和配置文件模板。映射規(guī)則模板包含MUICM 中各元素模板,如Screen 元素模板等,是映射規(guī)則的實現(xiàn),可包含子模板也可嵌套于其他模板中。
本研究定義的模板較多,本文重點介紹映射規(guī)則模板,限于篇幅,僅展示其中一個。以圖4 中的第二種映射規(guī)則為例,展示SelectionField元素模板,如圖5所示,第11行對該元素isMultiSelction屬性判斷,第12~16行用于生成CheckBox控件,第18~22行用于生成RadioButton控件。模板中的表達式是文本產(chǎn)生式規(guī)則的動態(tài)部分,如 aSelectionField.isMultiSelection、[aSelectionField.name.toLowerCase()/],與輸入的概念模型密切相關,主要是對模型特定元素特定屬性的動態(tài)獲取,該部分會在執(zhí)行時替換為輸入模型元素的相關屬性值。
在映射規(guī)則模板和配置文件模板的基礎上,按照圖6 所示的執(zhí)行過程實現(xiàn)最終代碼的自動或半自動生成。激活器(activator)對代碼生成器的生命周期進行控制,包括代碼生成器的啟動(start)和停止(stop);代碼生成器(code generator)負責對執(zhí)行過程的調(diào)度,是轉(zhuǎn)換算法的實現(xiàn),通過指定源模型文件、目標代碼文件路徑,配置模塊文件,設置運行參數(shù)列表完成其初始化,構建代碼生成所需環(huán)境,為生成目標文件做準備。首先,代碼生成器以一種深度優(yōu)先遍歷和廣度優(yōu)先遍歷結合的方式依次讀取模型解析器解析出的模型元素;然后,調(diào)用模塊文件,文本產(chǎn)生式規(guī)則中的文件(file)塊生成初始的目標文件,循環(huán)(for)塊根據(jù)滿足條件的元素個數(shù),零或多次執(zhí)行循環(huán)體中的模板,條件(if)塊根據(jù)條件的真假決定是否執(zhí)行條件中的模板;調(diào)用Acceleo 提供的函數(shù)獲取模型元素,如eContents()函數(shù)返回當前元素的直接子元素序列,ancestor()函數(shù)返回當前元素的父元素序列,在此基礎上獲取與該元素相關的信息,并根據(jù)模型元素匹配文件中的模板,寫入目標文件。靜態(tài)文本原樣寫入目標文件,注釋不做任何處理,Java 服務在查詢(query)塊中進行注冊并在模板中進行調(diào)用,保證用戶與模型轉(zhuǎn)換過程的交互,獲取用戶交互結果,寫入目標文件;最后,得到目標代碼文件。
圖5 SelectionField元素模板
圖6 代碼生成執(zhí)行過程
為了支持上述代碼生成過程,本文基于Eclipse 平臺[14]實現(xiàn)了一個支持移動用戶界面開發(fā)的輔助工具。下面基于該工具,結合實例,展示模型驅(qū)動的移動用戶界面開發(fā)方法和執(zhí)行效果。
移動用戶界面開發(fā)工具的目標,是輔助開發(fā)者進行界面的設計與實現(xiàn)。該工具框架分為四層,分別為Eclipse基礎平臺、Eclipse集成開發(fā)環(huán)境、基礎工具框架、應用層,如圖7 所示。以Eclipse 作為基礎平臺,依托EMF(Eclipse Modeling Framework)、GMF(Graphical Modeling Framework)、OCL(Object Constraint Language)、Acceleo和RCP(Rich Client Platform)插件組成一個集成開發(fā)環(huán)境,開發(fā)圖形化編輯窗口,實現(xiàn)概念模型的可視化創(chuàng)建;開發(fā)模型處理器,實現(xiàn)概念模型到用戶界面代碼的轉(zhuǎn)換;配置彈出菜單[15],調(diào)用模型轉(zhuǎn)換功能,支持模型驅(qū)動的移動用戶界面開發(fā)。
圖7 移動用戶界面開發(fā)工具框架
移動用戶界面開發(fā)工具的主界面如圖8 所示。應用該工具進行界面開發(fā)的具體步驟如下:
步驟1 界面需求分析,分析待開發(fā)移動應用界面的主要組件、界面支持的事件、界面之間的跳轉(zhuǎn)關系以及應用所需權限。
步驟2 概念建模,將步驟1中的組件、事件、界面跳轉(zhuǎn)及權限抽象成界面開發(fā)工具支持的模型元素,并在圖形化編輯器中進行概念建模。
步驟3 模型轉(zhuǎn)換,對步驟2中建立的概念模型執(zhí)行轉(zhuǎn)換,模型中的部分元素需要通過用戶交互決定目標元素,生成目標代碼。
步驟4 利用相關開發(fā)工具(如Android Studio),對生成的目標代碼進行人工調(diào)整和優(yōu)化,包括添加業(yè)務邏輯代碼,調(diào)整界面布局,最后進行編譯。編譯完成后的軟件項目可在模擬器上調(diào)試,也可打包成安裝程序文件在Android設備上實際運行。
本節(jié)基于實現(xiàn)的移動用戶界面開發(fā)工具開發(fā)圖書管理App。該應用提供登錄、注冊、展示書籍列表等功能。圖8中的圖形化編輯窗口展示了注冊、登錄和主界面的概念模型,通過點擊彈出菜單調(diào)用模型轉(zhuǎn)換功能,完成用戶界面代碼的生成,運行結果如圖9所示。
圖8 開發(fā)工具主界面
圖9 生成用戶界面實例
在該實例中,根據(jù)204 行XML 代碼半自動地生成適配于Android平臺的界面代碼,其中XML代碼行數(shù)為622 行,Java 代碼行數(shù)為657 行,調(diào)整后的應用包含661行XML代碼,835行Java代碼。借助該工具對具有不同組件的界面進行多次開發(fā)實驗,結果表明,代碼生成率即自動生成代碼行數(shù)占最終總代碼行數(shù)的比率均在80%左右。由于概念模型不涉及控件具體位置及界面布局的元素,暫不能生成該部分代碼,需要手動添加;模型中對業(yè)務邏輯部分元素的引用是獨立的,暫不能實現(xiàn)該部分代碼的復用。模型驅(qū)動的移動用戶界面開發(fā)方法縮短了得到應用初始版本的時間,提高了開發(fā)效率。
針對現(xiàn)階段移動用戶界面重復開發(fā)的問題,本文以移動用戶界面概念模型為基礎,定義了概念模型到Android 用戶界面代碼的映射規(guī)則,借助基于模板的代碼生成語言對映射規(guī)則進行實現(xiàn);設計并實現(xiàn)了模型轉(zhuǎn)換算法,以深度和廣度優(yōu)先遍歷算法結合的方式對模型元素進行遍歷,匹配映射規(guī)則;開發(fā)了一個支持該模型轉(zhuǎn)換的移動用戶界面開發(fā)工具原型,用戶利用該工具先設計用戶界面概念模型(平臺無關模型),之后,該工具可自動或半自動地將概念模型轉(zhuǎn)換成Android用戶界面代碼。
目前,該開發(fā)工具只支持概念模型到Android 平臺代碼的轉(zhuǎn)換,對概念模型到iOS 平臺、微信小程序等用戶界面代碼的轉(zhuǎn)換還未實現(xiàn),這是本文下一步需要進行的工作。