Qt on Android Episode 1(翻譯)

    在 KDAB ( the Qt experts ) 上看到了  BogDan Vatra 的 Qt on Android 的系列文章,生了翻譯的念頭,那就開始吧。

    我會跟隨 BogDan Vatra  在 KDAB 上的的部落格文章進行翻譯,如需轉載,請註明譯者 foruok ( 2014-4-14日 我正式取得了 BogDan Vatra 和 KDAB 的授權 )。

    本文的英文連結原文:Qt on Android Episode 1 ,作者為 BogDan Vatra 。中文譯者 foruok 。轉載請註明出處 http://blog.csdn.net/foruok 。

    這裡先對 BogDan Vatra作個簡單介紹:

    BogDan Vatra ,今年 34 歲(和我同歲,哈哈), 居住在羅馬尼亞中部的布拉索夫城。

    BogDan Vatra 有 13 年多的 C/C 開發經驗,11 年多的 Qt 開發經驗。 BogDan Vatra 主導開發過多個開源專案,  eXaro (exaro.sf.net) ,  Necessitas , Ministro (Qt on Andriod) 是比較著名且有影響力的三個。 

    eXaro 是基於 Qt  的、開源的、免費的報表引擎,與 Windows 下的水晶報表類似。

    Necessitas 是由 BogDan Vatra 建立的開源專案,是針對 Android 平臺的 Qt 移植版本,在釋出後大獲成功。後來 BogDan Vatra 將其中的一個移植版本貢獻給 Qt Project ,是 Qt 5.2 中 Android 功能的前身。

    Ministro 是 BogDan Vatra 為了在同一 Android 裝置上多個使用 Qt 的應用之間共享 Qt 庫而設計的解決方案。

    BogDan 目前為 KDAB 進行開發工作。

   

    以下是譯文。

    我打算針對 Qt on Android 這個主題撰寫一個系列文章。

    第一篇文章的內容:它(注:指 Qt on Android)如何開始、怎樣工作、當前的狀態、應當對 Qt 5.2 期望什麼以及我對 Qt 5.3 的計劃。下一篇文章我會把重點放在如何搭建安卓開發環境上。

    我們開始吧。

    它(注:指 Qt on Android )到底是怎麼開始的呢?

    2009年6月,我作為一個資深的 Linux 開發者加入了 ROUTE 66 。我的第一個任務是把現有的導航引擎移植到安卓平臺上。那時候 Google  還沒有釋放任何的官方 NDK ,所以我必須自己從 Android 原始碼建立一個我自己的 NDK 。

    不久以後,我完成了一個可以在 Android 上工作的引擎。我開始喜歡 Android 了,但是我總覺得缺了點東西,而且是我非常關注在意的東西。——那就是 Qt,我鍾愛的框架。這( Qt )就是缺失的那點東西!我對自己說,我必須為它做點什麼。

    2009年的10月份, Nokia (嗯,那時候 Qt 歸 Nokia 所有,什麼日子啊……)釋出了Lighthouse 專案。 Lighthouse 專案的建立,是為了讓開發者們更方便的把 Qt 移植到任意的平臺上。

    2009 年 12 月後期(我想是聖誕節之後),我有足夠的空閒時間可以開始移植工作。我選擇了  Lighthouse 專案,儘管它還是一個非常年輕的研究性專案。據我所知,我的 Android 移植,是第一個使用 Lighthouse 的移植。僅僅過了一個月( 2010 年 1 月),我在我的手機上看到了 Qt 繪製出來的第一個圖形。那種感覺,實在是好極了。

    幾個月後,當 Qt 達到一個相對良好的狀態後,我開始了 Qt Creator 外掛和 Ministro (注:Ministro 是一個全系統的 Qt 的共享庫安裝程式/服務提供者的服務)的工作。這個 Qt Creator 外掛使得使用者可以非常方便的在安卓裝置或模擬器上管理、開發、部署、執行、除錯 Qt 應用程式。

    即使幾乎一切都到位了,還是沒多少人願意使用,因為他們必須手動編譯所有東西。因此我決定為此做點兒工作。

    2011 年,在 Nokia 宣佈他們的重大戰略轉移的幾個星期之後,我釋出了第一個可用的 Qt Android SDK 。這就是 Necessitas 專案怎麼開始的,之後它獲得了巨大的成功,我決定加入 KDE ,在它的佑護下繼續專案。為什麼選擇 KDE ?因為我們擁有同一個目標:保持 Qt 的強大和對所有人免費。而且我可以使用他們出色的系統來發布 Qt 庫。

    最初釋放的(Qt Android) SDK 只能在 Linux 下使用。很快地, Ray Donnelly 聯絡了我並且把 SDK 移植到了 Windows 和 Mac 上。如果你在這些平臺上使用 Necessitas (和and Qt5 Android SDK  ),你應該感謝這個傢伙。

    和 Ray 及其他人一起,我們完成了 Necessitas SDK 的很多很多次釋出。

    因為(我們的) Qt Creator 外掛非常成功,我在 2012 年提交了這個外掛,那時候 Qt 仍然歸 Nokia 所有!

    2012 年 11 月,為了 Qt 5 的整合,我向 Qt Project 貢獻了這個安卓移植版本。這裡得作個宣告:只有 Qt 5 是在 Qt Project 的佑護下開發的,Qt 4 仍由 KDE Necessitas 專案所擁有。

    讓我們大概地看看 Qt on Android 是如何工作的,我不會去太深入細節,但足夠讓你瞭解它是如何工作的。

    就像我之前寫的,移植是基於  Lighthouse 專案的。  Lighthouse (現在更名為 QPA )是 Qt 的一個平臺抽象層。基本上這一層介於 Qt 與平臺之間,簡化了移植工作。因為 Android 應用程式使用 Java 語言編寫,不可能直接把 Qt 的事件迴圈和 Android 的事件迴圈直接連起來,我必須把 Qt 的主事件迴圈移動到一個執行緒中。如果你想擴充套件你的應用程式,必須明白這個事實:Qt 的事件迴圈和 Java UI 是執行在不同的執行緒中。即便在 Google 增加了 NativeActivity 之後,我們也不可能使用它,主要是因為它沒有暴露 Qt 需要的所有特性。

    一個 Qt for Android 應用程式包含兩個大的部分:

  • 原生部分,包含一個或多個動態庫檔案( .so ),實際上就是你的 Qt 應用程式。如果你選擇捆綁 Qt 庫,那麼也包含所有需要的庫檔案。
  • Android 相關部分,這部分又包含下面幾部分:
    • Android manifest ,這是你應用程式的入口。 Android 使用這個檔案決定啟動哪個應用或活動,它描述了應用需要的許可權、 Android API 版本等等資訊
    • 兩個 Java 類,載入依賴項和你的應用。它們也是 Qt QPA 和 Android 世界之間的由 Java 實現的橋樑的一部分。
    • Ministro service .aidl 檔案。這是兩個用於和 Ministro service 通訊的介面。 Ministro service 是部署方案之一,稍後會詳細的討論。
    • 其它的一些資源,如 assets, strings, images 等等。

    所有這些組成部分被組織在一個包中,這個包代表了你最終的應用程式。現在讓我們看看這些部分如何一起工作。

    當你的應用程式啟動時, Android 使用 manifest 檔案啟動一個活動( Activity )。這個活動是你應用程式中 Java 世界魔法的一小部分。為了在不中斷現有應用的前提下更新 Qt 庫, Java 部分被分割為兩塊:一部分攜帶你的應用程式(的一部分),另外一部分(一個 Java 庫,一個 .jar 檔案)包含了 QPA 外掛的所有邏輯。

    攜帶你的應用程式的第一個 Java 部分負責尋找依賴(注:原文為 missing ,但我覺得翻譯為依賴更好些)的庫( Qt 和 Java )並載入他們。同時它也轉發所有的事件(觸控、應用程式狀態變更、螢幕變化等)給第二個 Java 部分。

    第二個 Java 部分負責與 Qt 通訊。它包括 Android QPA 外掛需要的邏輯,例如建立和管理繪圖表面( drawing surface ),虛擬鍵盤處理等等。

    那麼,第一個 Java 部分查詢、載入所有依賴的庫和你的應用並且轉發所有事件給第二個部分,但你的 main 函式是怎樣被呼叫的呢?好吧,QPA 外掛做了這件事兒。不,我沒搞錯! QPA 外掛確確實實在你的應用啟動之前已經載入了(實際上在你的應用被載入前它已經載入了)。

    好吧,讓我來解釋為什麼我有這樣一個瘋狂的設計。

    我的夢想是找到一個方法,以便開發人員可以只編譯他們為 Android 開發的 Qt 應用,因此我必須找到一個途徑來呼叫 main 方法(我不想強制你為你的應用建立其它名字的入口函式,比如 WinMain)。

    問題是,為了從 Java 中呼叫一個 native 方法,你必須先註冊那個方法,否則你就不能呼叫它(注:這裡指 jni 的呼叫方式),在這種情境下, QPA 應運而生。 QPA 外掛被載入後,它註冊了少數幾個 native 函式,Java 部分使用這些函式作為橋樑,進一步地呼叫 native 世界中的更多函式。在 Java 部分載入完所有的庫和你的應用之後,它只需要呼叫 startQtApplication 這個由 QPA 外掛在之前註冊過的 native 方法。這個方法搜尋方法符號表找到 main 方法後,建立一個執行緒並在該執行緒中執行 main 方法。它必須建立一個執行緒,因為呼叫 main 方法會阻塞呼叫者直到 main 方法退出,而我們必須保持 Android  UI 執行緒自由(非阻塞)以便執行 Android 事件迴圈。

    在稍後的一篇文章中,我將介紹如何使用 JNI 在 Java 和 C/C 之間進行呼叫。

    最後,讓我們看看 Qt on Android 的當前狀態,你能從 Qt 5.2 得到什麼,以及 Qt 5.3 for Android 的計劃。

    Qt Essentials status:


    Qt Add-Ons status:

    感謝您花時間閱讀。

    下次再見的時候我們討論怎樣搭建 Qt for Android 開發環境。

    下一篇:Qt on Android Episode 2(翻譯)