作者:Maciej Gorywoda
简介
Android 平台运行在 Android 运行时上,Android 运行时是一个基于 JVM 的虚拟机,虽然不完全相同,但 它与 JVM 非常相似。因此,可以使用 Scala 编写 Android 应用程序,事实上,可以使用多种方法来实现。本文档将重点介绍如何使用 GraalVM Native Image 和 JavaFX 编写现代的 Scala Android 应用程序。在本教程的最后,您将找到讨论其他选项的材料链接。
如何使用 GraalVM Native Image 构建 Android 应用程序
要求
我们将使用 Linux。在 Windows 上,如果您使用 WSL2,则可以按照本教程进行操作并获得可用的 Android 应用程序 。 为了构建,我们将使用 Maven。
从 这里下载最新的基于 Java 11 的 GraalVM 社区版。通过创建指向 GraalVM 主目录的环境变量 GRAALVM_HOME
,通过将环境变量 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
gu
现在应该在你的控制台中可用,因为 $GRAALVM_HOME/bin
在你的 PATH
中。此外,阅读此内容 并安装你需要的任何东西。
你需要 adb
,“Android 调试桥”,来连接你的 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,来自 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 的 WYSIWYG 编辑器,它生成 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 文件。将您的 Android 手机通过 USB 线连接到电脑,允许电脑向手机发送文件,然后输入 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 频道。
- 在“学习 Scala”Discord 上还有一个 #android 频道。
- 最后,如果您有任何问题,您始终可以在 Twitter 上找到我。