mcpField
M
mobile-development

mobile-development

github.com/jame581开发930173 次安装2 周前更新
代码仓库

关于 mobile-development

面向 Godot 4.x 开发者的移动端开发技能,涵盖将游戏发布到 Android 和 iOS 的平台特有事项。重点包括签名、生命周期、权限、设备功能及移动端性能配置。

主要功能

  1. 01Android 与 iOS 导出及签名
  2. 02应用暂停与恢复处理
  3. 03权限声明和运行时请求
  4. 04Java API 与设备功能调用
  5. 05安全区域及设备方向适配
  6. 06移动渲染器与性能建议

适用场景

  1. 01配置 Android 发布密钥和 AAB
  2. 02处理应用暂停时的游戏存档
  3. 03适配刘海屏和设备旋转
  4. 04为移动端选择渲染器及纹理压缩

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jame581/godotprompter --skill mobile-development

安装后在 Claude Code 中输入/mobile-development确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
crash-debugging.md
iap-and-ads.md
plugins.md

详细介绍

移动开发

将 Godot 4.x 游戏发布到 Android 和 iOS。除了通用导出流程外,还涵盖平台特有的差异:签名、生命周期、权限、插件、IAP、设备功能,以及移动渲染器和性能预算。

相关技能: 通用导出流程和 CI/CD 请参阅 export-pipeline;安全区布局请参阅 responsive-ui;触控请参阅 input-handling;移动性能请参阅 godot-optimization;C# 移动端注意事项请参阅 csharp-godot。


1. 导出与签名

**Android:**安装 OpenJDK 17 和 Android SDK;在 Editor Settings 中设置 Java SDK Path 和 Android SDK Path(按用户设置,而非按项目设置)。生成发布密钥库:

keytool -v -genkey -keystore mygame.keystore -alias mygame -keyalg RSA -validity 10000

预设字段:Release / Release User / Release Password(目前密钥库密码和密钥密码必须相同);取消勾选 Export With Debug。**新上传到 Play 的应用必须使用 AAB。**CI 环境变量覆盖项:GODOT_ANDROID_KEYSTORE_RELEASE_{PATH,USER,PASSWORD}。

**iOS:**需要 macOS 和 Xcode。导出需要 App Store Team ID 和反向 DNS 格式的包 Identifier;Godot 会生成 .xcodeproj,供你在 Xcode 中构建。请使用 Compatibility 渲染器在 iOS 模拟器上测试——Forward+/Mobile 是否受支持取决于模拟器的 Metal 支持情况。

自定义 Gradle 构建(Project → Install the Gradle Build template)是 v2 插件和 IAP 的必需项(Godot 4.2+)。从 Godot 4.7 起,导出选项 Use Gradle Build 不再标记为实验性(GH-119172)——需要插件或 IAP 时,应将其视为标准流程。

⚠️ **Godot 4.7 中的变更:**已从 Android 导出中移除已弃用的 Google Play OBB 扩展文件支持(apk_expansion/* 导出选项)。仍依赖 APK 扩展文件的项目应改用 Android App Bundles 和 Play Asset Delivery,或安装现已包含旧版逻辑的独立 Godot OBB 插件。参见 GH-118283。


2. 应用生命周期

实际的 Node 通知常量:NOTIFICATION_APPLICATION_PAUSED(2015)、NOTIFICATION_APPLICATION_RESUMED(2014)、NOTIFICATION_APPLICATION_FOCUS_IN/_OUT(2016/2017)、NOTIFICATION_WM_GO_BACK_REQUEST(1007,Android 返回键)。**移动端没有 WM_CLOSE_REQUEST。**在 PAUSED 时自动保存;iOS 在暂停后约有 5 秒完成工作,之后系统会终止应用。

GDScript
func _notification(what: int) -> void:
    match what:
        NOTIFICATION_APPLICATION_PAUSED:
            SaveManager.save_game() # App backgrounded — persist now.
        NOTIFICATION_WM_GO_BACK_REQUEST:
            _confirm_quit()         # Android Back button.
C# 等效写法

文档只逐字展示了 NotificationWMCloseRequest;以下 PascalCase 名称遵循相同的命名惯例。

public override void _Notification(int what)
{
    switch ((long)what)
    {
        case NotificationApplicationPaused:
            SaveManager.SaveGame(); // App backgrounded — persist now.
            break;
        case NotificationWMGoBackRequest:
            ConfirmQuit();          // Android Back button.
            break;
    }
}
画中画(Android,Godot 4.7+)

DisplayServer.pip_mode_enter(window_id = 0) 可进入画中画模式;is_in_pip_mode(window_id = 0) 可报告当前状态;pip_mode_set_aspect_ratio(numerator, denominator, window_id = 0) 可设置画中画窗口的宽高比;pip_mode_set_auto_enter_on_background(auto_enter_on_background, window_id = 0) 可在应用进入后台时自动进入画中画模式。模式切换会通过 Node 通知传达:NOTIFICATION_APPLICATION_PIP_MODE_ENTERED(2019)/ NOTIFICATION_APPLICATION_PIP_MODE_EXITED(2020)。仅限 Android。

func _ready() -> void:
    DisplayServer.pip_mode_set_aspect_ratio(16, 9)
    DisplayServer.pip_mode_set_auto_enter_on_background(true)

func _notification(what: int) -> void:
    match what:
        NOTIFICATION_APPLICATION_PIP_MODE_ENTERED:
            _set_minimal_hud(true)  # PiP window is tiny — hide non-essential UI.
        NOTIFICATION_APPLICATION_PIP_MODE_EXITED:
            _set_minimal_hud(false)
public override void _Ready()
{
    DisplayServer.PipModeSetAspectRatio(16, 9);
    DisplayServer.PipModeSetAutoEnterOnBackground(true);
}

public override void _Notification(int what)
{
    switch ((long)what)
    {
        case NotificationApplicationPipModeEntered:
            SetMinimalHud(true);  // PiP window is tiny — hide non-essential UI.
            break;
        case NotificationApplicationPipModeExited:
            SetMinimalHud(false);
            break;
    }
}

3. 权限

在导出预设中将每项权限声明为 permissions/<name>;使用 OS.request_permission(name) 在运行时请求权限。结果会通过 MainLoop 的 on_request_permissions_result(permission, granted) 返回。必须同时在预设中启用该权限,仅发起请求还不够。

GDScript
func _ready():
    if "android.permission.POST_NOTIFICATIONS" not in OS.get_granted_permissions():
        OS.request_permission("android.permission.POST_NOTIFICATIONS")
    get_tree().on_request_permissions_result.connect(_on_perm_result)

func _on_perm_result(permission: String, granted: bool):
    print("%s granted: %s" % [permission, granted])
C# 等效写法
// Contains() on string[] needs: using System.Linq;
public override void _Ready()
{
    if (!OS.GetGrantedPermissions().Contains("android.permission.POST_NOTIFICATIONS"))
        OS.RequestPermission("android.permission.POST_NOTIFICATIONS");
    GetTree().OnRequestPermissionsResult += OnPermResult;
}

private void OnPermResult(string permission, bool granted)
    => GD.Print($"{permission} granted: {granted}");

4. 调用 Android API(JavaClassWrapper)— Godot 4.4+

Godot 4.4+。 JavaClassWrapper.wrap("<java.class>")(早期版本中已有,但从 4.4 起才实用)无需插件即可调用 Java/Kotlin 类;4.4 新增的 AndroidRuntime 单例(Engine.get_singleton("AndroidRuntime"))提供 getActivity()、getApplicationContext() 和 createRunnableFromGodotCallable(callable)。

更简单的跨平台替代方案无需 4.4:Input.vibrate_handheld(duration_ms, amplitude)(需要 VIBRATE 权限;iOS 需要 iOS 13+)。完整的 JavaClassWrapper/AndroidRuntime API、Toast/Intent 示例和内部类语法,请参阅 插件。

GDScript
# Godot 4.4+ — requires the VIBRATE permission in the export preset.
func vibrate_ms(duration_ms: int) -> void:
    if Engine.has_singleton("AndroidRuntime"):
        var runtime := Engine.get_singleton("AndroidRuntime")
        var context := runtime.getApplicationContext()
        var vibrator := context.getSystemService("vibrator")
        if vibrator.hasVibrator():
            var Effect = JavaClassWrapper.wrap("android.os.VibrationEffect")
            var effect = Effect.createOneShot(duration_ms, Effect.DEFAULT_AMPLITUDE)
            vibrator.vibrate(effect)
C# 等效实现

这里的文档仅适用于 GDScript;确切的 C# Variant 封送调用链(对每个 Java 返回值调用 .AsGodotObject())尚未在设备上测试,请在实际的 4.4+ Android 构建中验证。

// Godot 4.4+ — requires the VIBRATE permission in the export preset.
public void VibrateMs(int durationMs)
{
    if (!Engine.HasSingleton("AndroidRuntime")) return;
    var runtime = Engine.GetSingleton("AndroidRuntime");
    var context = runtime.Call("getApplicationContext").AsGodotObject();
    var vibrator = context.Call("getSystemService", "vibrator").AsGodotObject();
    if (vibrator.Call("hasVibrator").AsBool())
    {
        var effect = JavaClassWrapper.Wrap("android.os.VibrationEffect");
        var oneShot = effect.Call("createOneShot", durationMs, effect.Get("DEFAULT_AMPLITUDE"));
        vibrator.Call("vibrate", oneShot);
    }
}
从脚本实现 Java 接口(Godot 4.7+)

JavaClassWrapper.create_proxy(object: Object, interfaces: PackedStringArray) -> JavaObject 使用 Godot 对象实现指定的 Java 接口——该对象的方法签名必须与 Java 接口的方法签名匹配,Java 调用会转发到匹配的方法。create_sam_callback(sam_interface: String, callable: Callable) -> JavaObject 用于单抽象方法(SAM)接口,其 Callable 必须与 SAM 方法的参数和返回类型匹配。除 Android 外,这两个方法在所有平台上都返回 null。

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

func _demo() -> void:
    var print_proxy := PrintProxy.new()
    var printer := JavaClassWrapper.create_proxy(print_proxy, ["android.util.Printer"])
    printer.println("Hello Godot World!")

    var cb := func(content: String) -> void: print(content)
    var callback := JavaClassWrapper.create_sam_callback("android.util.Printer", cb)
    callback.println("Hello Godot World!")

这里的文档仅适用于 GDScript。CreateProxy 根据注册的方法名进行匹配,因此 C# 实现类的方法名必须与 Java 接口完全一致——在 C# 中优先使用 CreateSamCallback:

var cb = Callable.From((string content) => GD.Print(content));
var callback = JavaClassWrapper.CreateSamCallback("android.util.Printer", cb);
callback.Call("println", "Hello Godot World!");

5. 设备功能与安全区域

DisplayServer.get_display_safe_area() -> Rect2i(Android/iOS)返回刘海/缺口以内的可用区域;get_display_cutouts()(Android)列出缺口矩形。运动传感器位于 Input 上(get_accelerometer/gravity/gyroscope/magnetometer,返回 Vector3,仅适用于 Android/iOS)。

GDScript
func _ready():
    var safe := DisplayServer.get_display_safe_area() # Rect2i
    $UI.position = safe.position
    $UI.size = safe.size
C# 等效实现
public override void _Ready()
{
    Rect2I safe = DisplayServer.GetDisplaySafeArea();
    var ui = GetNode<Control>("UI");
    ui.Position = safe.Position;
    ui.Size = safe.Size;
}

Android 支持原生文件对话框(DisplayServer.file_dialog_show());从 Godot 4.7 起,所有设备都可使用原生文件选择器——已移除用于限制 FEATURE_NATIVE_DIALOG_FILE 支持的 Android 版本检查(GH-115257)。

Godot 4.7+: 屏幕触控摇杆请使用内置的 VirtualJoystick Control 节点,而不是自行搭建 TouchScreenButton 组件——完整 API 请参阅 input-handling(references/touch.md,“VirtualJoystick (Godot 4.7+)”)。

设备方向信号(Godot 4.7+)

设备方向变化时会触发 DisplayServer.orientation_changed(orientation: int)(Android/iOS):1 表示纵向,2 表示横向,0 表示未定义。

func _ready() -> void:
    DisplayServer.orientation_changed.connect(_on_orientation_changed)

func _on_orientation_changed(orientation: int) -> void:
    _relayout_hud(orientation == 2)  # 1 portrait, 2 landscape, 0 undefined.
public override void _Ready()
{
    DisplayServer.Singleton.Connect(DisplayServer.SignalName.OrientationChanged,
        Callable.From((long orientation) => RelayoutHud(orientation == 2)));
}

6. 移动端性能与渲染器

使用 Mobile(或 Compatibility)渲染器;在 iOS 模拟器上优先使用 Compatibility。启用 rendering/textures/vram_compression/import_etc2_astc = true(ETC2/ASTC)以进行 Android 纹理压缩。尽量减小单架构 APK 的体积;AAB 会自动按设备拆分。深入的绘制调用/批处理调优请交由 godot-optimization 处理。


7. 移动端 C#

C# Android/iOS 导出从 Godot 4.2+ 起支持,但仍属实验性功能。Android C# 导出需要 .NET 9+(搭配 Godot 4.5);iOS 导出仅支持从 macOS 进行(导出过程也会构建 arm64 + x86_64 模拟器程序集)。C# 无法导出到 Web。 尽早测试 C# 导出流程——这是 C# 移动端项目中风险最高的部分。

深入了解: 插件(Android v2 / iOS) · 应用内购买与广告 · 崩溃调试


实施检查清单

  • 已配置发布密钥库(Android)/描述文件 + Team ID(iOS)
  • Play 上传使用 AAB;使用 v2 插件或 IAP 时已安装 Gradle 构建工具
  • 已将自动保存接入 NOTIFICATION_APPLICATION_PAUSED(遵守 iOS 约 5 s 的时间限制)
  • 已在预设中启用所需权限,并在运行时请求这些权限
  • 已标明 JavaClassWrapper 用法要求 Godot 4.4+;如有需要,为 4.3 提供回退方案
  • UI 锚定在 get_display_safe_area() 内;已处理刘海/挖孔
  • 已启用 Mobile/Compatibility 渲染器和 ETC2/ASTC 压缩
  • C# 项目:已确认 Android 导出使用 .NET 9+
  • 已将 Play OBB/APK 扩展文件迁移到 App Bundles 并使用 Play Asset Delivery,或已安装 Godot OBB 插件(Godot 4.7 已移除内置支持)
  • PiP(Android):已配置宽高比和自动进入;HUD 会响应 PIP_MODE 通知(Godot 4.7+)

评论

支持 Markdown