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.
Checking the stable version of the documentation...
与 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 的 LocalDateTime 和 DateTimeFormatter 类。通过 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,可以让你实现这一点。
将 JavaClassWrapper 和 AndroidRuntime 插件结合使用,可以让开发者在不离开 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)
范例:将一张图片保存到 Android 相册
# 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()
# Create the File and Uri.
var Uri = JavaClassWrapper.wrap("android.net.Uri")
var File = JavaClassWrapper.wrap("java.io.File")
var file = File.File(file_path_to_image_here)
var uri = Uri.fromFile(file)
# Set Action and Data of Intent.
intent.setAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
intent.setData(uri)
# Broadcast it.
activity.sendBroadcast(intent)