Skip to content
Back to skills

Mobile Development

ASecurity

Use when targeting Android/iOS — export and signing, permissions, plugins, in-app purchases, ads, app lifecycle, device features, and mobile performance

  • 792 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 3, 2026
developmentgojavakotlinc#bashnodedebuggingapici/cdperformance

Works with

  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned June 3, 2026

npx -y skills add jame581/GodotPrompter --skill mobile-development --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Mobile Development?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Mobile Development
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jame581-mobile-development/badge)](https://www.skillsdirectory.com/skills/jame581-mobile-development)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: mobile-development
description: Use when targeting Android/iOS — export and signing, permissions, plugins, in-app purchases, ads, app lifecycle, device features, and mobile performance
---

# Mobile Development

Ship a Godot 4.x game to Android and iOS. This covers the platform-specific deltas beyond a generic export: signing, lifecycle, permissions, plugins, IAP, device features, and the mobile renderer/perf budget.

> **Related skills:** **export-pipeline** for the generic export flow and CI/CD, **responsive-ui** for safe-area layout, **input-handling** for touch, **godot-optimization** for mobile performance, **csharp-godot** for C# mobile caveats.

---

## 1. Export & signing

**Android:** OpenJDK 17 and the Android SDK; set `Java SDK Path` + `Android SDK Path` in **Editor Settings** (per-user, not per-project). Generate a release keystore:

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

Preset fields: **Release / Release User / Release Password** (keystore and key passwords must currently match); uncheck **Export With Debug**. **AAB is mandatory for new Play uploads.** CI env overrides: `GODOT_ANDROID_KEYSTORE_RELEASE_{PATH,USER,PASSWORD}`.

**iOS:** macOS + Xcode. Export needs an **App Store Team ID** + a reverse-DNS bundle **Identifier**; Godot generates an `.xcodeproj` you build from Xcode. The iOS **simulator supports the Compatibility renderer only**.

A **custom Gradle build** (*Project → Install the Gradle Build template*) is **required for v2 plugins and IAP** (Godot 4.2+).

---

## 2. App lifecycle

Real `Node` notification constants: `NOTIFICATION_APPLICATION_PAUSED` (2015), `NOTIFICATION_APPLICATION_RESUMED` (2014), `NOTIFICATION_APPLICATION_FOCUS_IN`/`_OUT` (2016/2017), `NOTIFICATION_WM_GO_BACK_REQUEST` (1007, Android Back). **There is no `WM_CLOSE_REQUEST` on mobile.** Autosave on PAUSED; **iOS gives ~5 s** after pause to finish work before it kills the app.

### GDScript

```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# Equivalent

The docs only show `NotificationWMCloseRequest` verbatim; these PascalCase names follow the same convention.

```csharp
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;
    }
}
```

---

## 3. Permissions

Declare each permission in the export preset as `permissions/<name>`; request it at runtime with `OS.request_permission(name)`. The result arrives via `MainLoop`'s `on_request_permissions_result(permission, granted)`. The permission **must also be enabled in the preset**, not just requested.

### GDScript

```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# Equivalent

```csharp
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. Calling Android APIs (JavaClassWrapper) — Godot 4.4+

**Godot 4.4+ only.** `JavaClassWrapper.wrap("<java.class>")` calls Java/Kotlin classes with no plugin; the `AndroidRuntime` singleton (`Engine.get_singleton("AndroidRuntime")`) exposes `getActivity()`, `getApplicationContext()`, and `createRunnableFromGodotCallable(callable)`.

The simpler cross-platform alternative needs no 4.4: `Input.vibrate_handheld(duration_ms, amplitude)` (requires the `VIBRATE` permission; iOS needs iOS 13+). See [Plugins](references/plugins.md) for the full JavaClassWrapper/AndroidRuntime API, Toast/Intent recipes, and inner-class syntax.

### GDScript

```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# Equivalent

The docs are GDScript-only here; the exact C# Variant-marshaling chain (`.AsGodotObject()` on each Java return) is untested against a device — verify on a real 4.4+ Android build.

```csharp
// 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);
    }
}
```

---

## 5. Device features & safe area

`DisplayServer.get_display_safe_area() -> Rect2i` (Android/iOS) returns the usable region inside notches/cutouts; `get_display_cutouts()` (Android) lists the cutout rects. Motion sensors live on `Input` (`get_accelerometer/gravity/gyroscope/magnetometer`, returning `Vector3`, Android/iOS only).

### GDScript

```gdscript
func _ready():
    var safe := DisplayServer.get_display_safe_area() # Rect2i
    $UI.position = safe.position
    $UI.size = safe.size
```

### C# Equivalent

```csharp
public override void _Ready()
{
    Rect2I safe = DisplayServer.GetDisplaySafeArea();
    var ui = GetNode<Control>("UI");
    ui.Position = safe.Position;
    ui.Size = safe.Size;
}
```

---

## 6. Mobile performance & renderer

Use the **Mobile** (or **Compatibility**) renderer; the iOS simulator is Compatibility-only. Enable `rendering/textures/vram_compression/import_etc2_astc = true` (ETC2/ASTC) for Android texture compression. Keep single-arch APKs small; AABs split per-device automatically. Defer deep draw-call/batching tuning to **godot-optimization**.

---

## 7. C# on mobile

C# Android/iOS export is **Godot 4.2+ but experimental**. **Android C# export requires .NET 9+** (with Godot 4.5); iOS export only from macOS, and the simulator templates are x64-only. **C# cannot export to Web.** Test the C# export pipeline early — it is the riskiest part of a C# mobile project.

> **Deeper:** [Plugins (Android v2 / iOS)](references/plugins.md) · [In-app purchases & ads](references/iap-and-ads.md) · [Crash debugging](references/crash-debugging.md)

---

## Implementation Checklist

- [ ] Release keystore (Android) / provisioning + Team ID (iOS) configured
- [ ] AAB for Play uploads; Gradle build installed if using v2 plugins or IAP
- [ ] Autosave wired to `NOTIFICATION_APPLICATION_PAUSED` (iOS ~5 s budget respected)
- [ ] Required permissions enabled in the preset AND requested at runtime
- [ ] JavaClassWrapper usage labeled Godot 4.4+; fallbacks for 4.3 if needed
- [ ] UI anchored inside `get_display_safe_area()`; notch/cutout handled
- [ ] Mobile/Compatibility renderer + ETC2/ASTC compression enabled
- [ ] C# projects: verified .NET 9+ for Android export

Files in this skill

  • SKILL.md8 KB
  • references/crash-debugging.md1.3 KB
  • references/iap-and-ads.md3 KB
  • references/plugins.md3.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…