由 Maciej Gorywoda
簡介
Android 平台在 Android Runtime 上執行,而 Android Runtime 是基於 JVM 的虛擬機器,儘管不完全相同,但與它非常相似。因此,可以用 Scala 撰寫 Android 應用程式,事實上,可以用多種方法來撰寫。在此文件中,我們將重點說明如何使用 GraalVM Native Image 和 JavaFX 撰寫使用 Scala 的現代 Android 應用程式。在本教學的最後,您會找到討論其他選項的教材連結。
如何使用 GraalVM Native Image 建置 Android 應用程式
需求
我們將使用 Linux。在 Windows 上,您可以遵循本教學並取得一個可運作的 Android 應用程式 如果您使用 WSL2。我們將使用 Maven 來建置。
從 這裡 下載最新的 GraalVM,基於 Java 11 的 Community Edition。透過建立環境變數 GRAALVM_HOME
指向 GraalVM 主目錄,透過將環境變數 JAVA_HOME
設定為 ${GRAALVM_HOME}
,以及透過將 ${GRAALVM_HOME}/bin
加入您的 PATH
來設定它為您的 JVM。如果您使用 Bash,請將以下列加入您的 ~/.bash_profile
export GRAALVM_HOME=<path to GraalVM home directory>
export JAVA_HOME=$GRAALVM_HOME
export PATH=$GRAALVM_HOME/bin:$PATH
當您輸入 java -version
時,現在應該會顯示類似這樣的內容
> java -version
openjdk version "11.0.10" 2021-01-19
OpenJDK Runtime Environment GraalVM CE 21.0.0 (build 11.0.10+8-jvmci-21.0-b06)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.0 (build 11.0.10+8-jvmci-21.0-b06, mixed mode, sharing)
(GraalVM 版本可能不同)
輸入 native-image
檢查路徑中是否已存在。如果沒有,請使用安裝
gu install native-image
由於 $GRAALVM_HOME/bin
在您的 PATH
中,gu
現在應該可以在您的主控台中使用。此外,閱讀此內容並安裝您需要的任何內容。
您需要 adb
(Android Debug Bridge)連線到您的 Android 裝置並在其中安裝應用程式。在此處可以找到更多相關資訊。
請確定您的 gcc
至少為版本 6。您可以嘗試執行下列步驟。除此之外,您需要一些特定的 C 函式庫(例如 GTK)來建置原生映像,而且各電腦有所不同,因此我無法明確告訴您該如何執行。不過這應該不是什麼大問題。只要追蹤錯誤訊息(指出您缺少某些內容)並在 Google 上搜尋如何安裝即可。在我的案例中,清單如下
libasound2-dev (for pkgConfig alsa)
libavcodec-dev (for pkgConfig libavcodec)
libavformat-dev (for pkgConfig libavformat)
libavutil-dev (for pkgConfig libavutil)
libfreetype6-dev (for pkgConfig freetype2)
libgl-dev (for pkgConfig gl)
libglib2.0-dev (for pkgConfig gmodule-no-export-2.0)
libglib2.0-dev (for pkgConfig gthread-2.0)
libgtk-3-dev (for pkgConfig gtk+-x11-3.0)
libpango1.0-dev (for pkgConfig pangoft2)
libx11-dev (for pkgConfig x11)
libxtst-dev (for pkgConfig xtst)
範例應用程式
如果您已到達此處,而且一切看似正常,這表示您可能應該能夠編譯並執行名為 HelloScala 的範例應用程式。HelloScala 是根據 HelloGluon 建立,而 HelloGluon 則來自 Gluon 範例。Gluon 是一家維護 JavaFX 並提供函式庫的公司,這些函式庫可在我們的程式碼與裝置(無論是桌上型電腦、Android 或 iOS)之間提供一層抽象。這有一些有趣的意涵:例如,您會在程式碼中看到我們會檢查我們是在桌上型電腦還是 Android 上,因為如果是在桌上型電腦上,則我們需要為應用程式提供視窗大小。如果我們是在 Android 上,我們可以讓應用程式的視窗佔滿整個畫面。如果您決定使用此技術堆疊撰寫更複雜的內容,您很快就會發現您可以使用 Gluon 的函式庫和 JavaFX(可能與 ScalaFX 搭配使用)來達成其他開發人員透過調整 Android SDK 所獲得的相同結果,同時您撰寫的程式碼也可以輕易地在其他平台上重複使用。
在 HelloScala 的 pom.xml
中,您會找到範例應用程式使用的外掛程式和相依項清單。讓我們來看看其中一些。
- 我們將使用 Java 16 和 Scala 2.13。
- 一個微小的 Scala 函式庫,可解決 Scala 2.13 和 GraalVM Native Image 之間互動中的 此問題。
- 對於 GUI,我們將使用 JavaFX 16。
- 我們將使用兩個 Gluon 函式庫:Glisten 和 Attach。Glisten 以專門為行動應用程式設計的額外功能豐富 JavaFX。Attach 是基礎平台上的抽象層。對我們來說,這表示我們應該能夠使用它來存取 Android 上的所有內容,從本機儲存空間到權限,再到推播通知。
- scala-maven-plugin 讓我們在 Maven 建置中使用 Scala (嗯,廢話)。謝謝您,David!
- gluonfx-maven-plugin 讓我們將 Gluon 相依模組和 JavaFX 程式碼編譯成原生映像。在它的組態中,您會找到
attachList
,其中包含我們需要的 Gluon Attach 模組:device
、display
、storage
、util
、statusbar
和lifecycle
。在這些模組中,我們將直接使用display
(如果我們在桌面上執行應用程式,而不是在行動裝置上以全螢幕模式執行,則設定應用程式視窗的尺寸)和util
(檢查我們是在桌面上還是行動裝置上執行應用程式),但其他模組是這兩個模組和 Gluon Glisten 所需要的。 - javafx-maven-plugin 是 gluonfx-maven-plugin 的需求。
程式碼
HelloScala 只是一個簡單的範例應用程式,實際的 Scala 程式碼只設定幾個小工具並顯示它們。Main
類別擴充自 Glisten 函式庫中的 MobileApplication
,然後在兩個方法中以程式化方式建構主視圖:init()
用於建立小工具,postInit(Scene)
用於裝飾小工具。由於我們希望在行動裝置上安裝應用程式之前先在我們的筆電上測試它,因此我們也使用 postInit
來檢查應用程式在什麼平台上執行,如果它是桌面,我們會設定應用程式視窗的尺寸。如果是行動裝置,則不需要這麼做,我們的應用程式會佔用螢幕上所有可用的空間。
在 JavaFX 中設定和顯示小工具的另一種方式是使用稱為 Scene Builder 的所見即所得編輯器,它會產生 FXML 檔案,這是 XML 的一個版本,然後你可以將其載入你的應用程式中。你可以在另一個範例中看到它是如何完成的:HelloFXML。對於更複雜的應用程式,你可能會混合這兩種方法:對於或多或少靜態的檢視使用 FXML,並在 UI 在一個檢視中因應事件而變更的地方以程式方式設定小工具(例如,可捲動的訊息清單)。
如何執行應用程式
建置 Android 原生映像需要時間,因此我們希望避免過於頻繁地執行。即使在第一次執行應用程式之前,你應該花一些時間在單元、元件和整合測試上,這樣一來,如果你在應用程式中變更某個項目,你仍然可以確保它在任何手動測試之前都能正確運作。然後,若要檢查 GUI 的外觀和運作方式,請使用
mvn gluonfx:run
如果一切看起來都很好,請建置原生映像… 但首先,針對你的桌面
mvn gluonfx:build gluonfx:nativerun
畢竟,我們在此處理的是跨平台解決方案。除非你想要測試應用程式的功能,而這些功能只會在行動裝置上運作,否則你可以先將其執行為獨立的桌面應用程式。這將再次讓你能夠測試應用程式的某些層級,而無需實際在 Android 裝置上執行它。然後,如果一切看起來都不錯,或者如果你決定略過這個步驟
mvn -Pandroid gluonfx:build gluonfx:package
成功執行此命令將在 target/client/aarch64-android/gvm
目錄中建立一個 APK 檔案。使用 USB 連接線將你的 Android 手機連接到電腦,讓電腦取得將檔案傳送到手機的權限,然後輸入 adb devices
以檢查你的手機是否已識別。它應該在主控台中顯示類似這樣的內容
> adb devices
List of devices attached
16b3a5c8 device
現在你應該可以使用 adb install <path to APK>
在已連接的裝置上安裝應用程式,稍後你應該會在裝置的主畫面看到一個新的圖示。當你按一下圖示時,它應該會開啟與應用程式的桌面版本大致相同的畫面。
安裝可能無法運作的原因有很多,其中最常見的原因之一是你的 Android 根本不允許以這種方式安裝應用程式。前往「設定」,尋找「開發人員選項」,然後在那裡啟用「USB 偵錯」和「透過 USB 安裝」。
如果一切都正常運作,而且你在裝置上看到應用程式的畫面,請輸入 adb logcat | grep GraalCompiled
以查看記錄輸出。現在你可以按一下應用程式畫面上的放大鏡圖示按鈕,你應該會看到 "log something from Scala"
印在主控台中。當然,在你撰寫更複雜的應用程式之前,請查看你選擇的 IDE 中的外掛程式,這些外掛程式可以更好地顯示來自 adb logcat
的記錄。例如
以下是開啟應用程式時,應用程式看起來的螢幕截圖。
後續步驟和其他有用的閱讀資料
如果你成功建置其中一個範例應用程式,而且想要撰寫更複雜的程式碼,至少有幾種方法可以學習如何執行
-
看看這些文章,了解 Scala 在 Android 上的歷史,以及撰寫 Android 應用程式的其他方法的討論:#1、#2。
- 閱讀更多內容並使用 JavaFX 進行實驗。你可以從其官方文件和 Jacob Jenkov 編寫的這份龐大教學清單 開始。
- 安裝 Scene Builder 並學習如何使用它來建置 GUI。除了文件之外,你可以在 YouTube 上找到許多相關教學。
- 查看 Gluon 的 Glisten 和 Attach 文件,了解如何讓你的應用程式在行動裝置上看起來更好看,以及如何取得裝置功能的存取權。
- 從 Gluon 的範例清單 下載範例並將其改寫為 Scala。改寫完成後,請告訴我!
- 研究 ScalaFX — 一個更具宣告性、Scala 慣用語法的外覆器,用於 JavaFX。
- 從 GitHub 上的「Scala on Android」儲存庫 下載其他範例。如果你撰寫了自己的範例應用程式,而且希望我將其納入,請與我聯絡。
- 加入我們的官方 Scala Discord — 我們在那裡有一個 #scala-android 頻道。
- 在「Learning Scala」Discord 上也有 #android 頻道。
- 最後,如果你有任何問題,你隨時可以在 Twitter 上找到我。