Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

与 Android API 集成

Android 平台拥有众多 API 以及丰富的第三方库生态,涵盖了广泛且多样的功能,如推送通知、分析、身份验证、广告等。

Godot 核心功能不直接集成这些特性,因此 Godot 很早就提供了 Android 插件系统Android 插件系统 使开发者能够使用 Java 或 Kotlin 代码创建 Godot Android 插件,从而在 Godot 项目中通过 GDScript、C# 或 GDExtension 访问和使用 Android API 或第三方库。

class MyAndroidSingleton(godot: Godot?) : GodotPlugin(godot) {
        @UsedByGodot
        fun doSomething(value: String) {
                // ...
        }
}

然而,编写 Android 插件需要具备 Java 或 Kotlin 代码的知识,而大多数 Godot 开发者并不具备这些技能。因此,许多 Android API 和第三方库没有可供开发者使用的 Godot 插件接口。实际上,这也是开发者指出无法从其他游戏引擎切换到 Godot 的主要原因之一。

为了解决这个问题,我们在 Godot 4.4 中引入了一些工具,简化了开发者访问 Android API 和第三方库的过程。

JavaClassWrapper(Godot 单例)

JavaClassWrapper is a Godot singleton which allows creating instances of Java / Kotlin classes, implementing Java / Kotlin interfaces, and calling methods on them using only GDScript, C# or GDExtension.

var LocalDateTime = JavaClassWrapper.wrap("java.time.LocalDateTime")
var DateTimeFormatter = JavaClassWrapper.wrap("java.time.format.DateTimeFormatter")

var datetime = LocalDateTime.now()
var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss")

print(datetime.format(formatter))

在上面的代码片段中,JavaClassWrapper 被用来从 GDScript 访问 Java 的 LocalDateTimeDateTimeFormatter 类。通过 JavaClassWrapper,我们可以像调用 GDScript 方法一样,直接在 GDScript 中调用 Java 类的方法。

class PrintProxy:
    func println(content: String) -> void:
        print(content)

var print_proxy = PrintProxy.new()
var printer_object = JavaClassWrapper.create_proxy(print_proxy, ["android.util.Printer"])
printer_object.println("Hello Godot World!")

In the code snippet above, JavaClassWrapper is used to implement the Java android.util.Printer interface from GDScript using a Object as the implementation. The instantiated proxy can then be passed to Java methods that accept a android.util.Printer parameter.

Check out the JavaClassWrapper documentation to learn more about its API.

AndroidRuntime 插件

JavaClassWrapper 非常有用,但在 Android 上做许多操作时,你需要访问各种 Android 生命周期 / 运行时对象。AndroidRuntime 插件是一个 built-in Godot Android plugin,可以让你实现这一点。

JavaClassWrapperAndroidRuntime 插件结合使用,可以让开发者在不离开 GDScript 或使用除 Godot 以外的任何工具的情况下,访问和使用 Android API。这对于 Godot 在 Android 开发中的推广来说是 重大的 进展:

  • 如果你只需要做一些简单的操作,或者只使用第三方库的一小部分,你无需创建插件

  • 该方案支持开发者快速集成 Android 原生功能

  • 它允许开发者仅使用 GDScript 和 JavaClassWrapper 创建 Godot 插件(无需 Java 或 Kotlin)

备注

对于使用 gradle 导出的项目,Godot 会自动包含它在项目 addons 目录中找到的 .jar.aar 文件。因此,要使用第三方库,你只需将其 .jar.aar 文件放入 addons 目录,即可通过 JavaClassWrapper 直接在 GDScript 中调用其方法。

示例:显示 Android Toast 提示

# Retrieve the AndroidRuntime singleton.
var android_runtime = Engine.get_singleton("AndroidRuntime")
if android_runtime:
    # Retrieve the Android Activity instance.
    var activity = android_runtime.getActivity()

    # Create a Godot Callable to wrap the toast display logic.
    var toast_callable = func():
        # Use JavaClassWrapper to retrieve the android.widget.Toast class, then make and show a toast using the class APIs.
        var ToastClass = JavaClassWrapper.wrap("android.widget.Toast")
        ToastClass.makeText(activity, "This is a test", ToastClass.LENGTH_LONG).show()

    # Wrap the Callable in a Java Runnable and run it on the Android UI thread to show the toast.
    activity.runOnUiThread(android_runtime.createRunnableFromGodotCallable(toast_callable))

示例:触发设备震动

# Retrieve the AndroidRuntime singleton.
var android_runtime = Engine.get_singleton("AndroidRuntime")
if android_runtime:
    # Retrieve the Android Vibrator system service and check if the device supports it.
    var vibrator_service = android_runtime.getApplicationContext().getSystemService("vibrator")
    if vibrator_service and vibrator_service.hasVibrator():
        # Configure and run a VibrationEffect.
        var VibrationEffect = JavaClassWrapper.wrap("android.os.VibrationEffect")
        var effect = VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE)
        vibrator_service.vibrate(effect)

示例:访问内部类

可通过 $ 符号访问 Java 内部类:

# Accessing 'VERSION' class, which is an inner class from the 'android.os.Build' class.
var version = JavaClassWrapper.wrap("android.os.Build$VERSION")
var sdk_int = version.SDK_INT
if sdk_int == 30:
    # Do something specific on android 11 devices.
else:
    # All other devices

示例:调用构造函数

通过调用与类同名的方法来调用构造函数。

此示例创建了一个用于发送文本的 Intent:

# Retrieve the AndroidRuntime singleton.
var android_runtime = Engine.get_singleton("AndroidRuntime")
if android_runtime:
    var Intent = JavaClassWrapper.wrap("android.content.Intent")
    var activity = android_runtime.getActivity()
    var intent = Intent.Intent() # Call the constructor.
    intent.setAction(Intent.ACTION_SEND)
    intent.putExtra(Intent.EXTRA_TEXT, "This is a test message.")
    intent.setType("text/plain")
    activity.startActivity(intent)