Godot SDK
Preview · 0.1.0-beta.3 · Godot 4.2–4.5 (Android exports: 4.5) · GDScript and C#
Download PushHub for Godot, copy addons/pushhub into the project, and enable the plug-in. The Android core ships inside it; there is no iOS plug-in yet.
PushHub.configure(APP_ID, "ph_pub_YOUR_KEY")
PushHub.start()
PushHub.identify("player-1842", {"tier": "gold"})
PushHub.track("level_completed", {"level": "20"})
The autoload exposes start, permission, identity, consent, events, open handling, reset, diagnostics, and deep-link signals. started(installation_id) fires when start() registers the installation, and operation_failed(error_class) fires when a native operation fails. A C# facade is included. Native storage and retry behavior stays in the Android/iOS cores.
Android export
The Android core ships in the zip as addons/pushhub/android/pushhub-release.aar, the file name the export plug-in loads. It is the same file as com.kemegames.pushhub:pushhub-android:0.1.0-beta.7 in PushHub's Maven repository, so you don't download or rename an AAR any more. On Godot 4.2 and later, the plug-in's export script adds the AAR and the dependencies from its POM to Android exports: Firebase Messaging 24.1.0, AndroidX Core KTX 1.15.0, Security Crypto 1.1.0-alpha06, WorkManager 2.10.0, Kotlin coroutines 1.9.0 and the Kotlin standard library 2.1.0. All of them come from Google's Maven repository and Maven Central, which Godot's Android build template already uses.
Godot version. AndroidX Core 1.15 and WorkManager 2.10 need compileSdk 35. Godot 4.5's Android build template compiles against API 35. The 4.3 and 4.4 templates compile against 34 and fail the build's AAR metadata check, unless you raise compileSdk in res://android/build/config.gradle (untested). In the Android export preset:
- Turn on Use Gradle Build.
- Set Gradle Build › Min SDK to
23or higher. The PushHub AAR needs Android 6.0.
Add your Firebase configuration. The AAR registers the PushHubNative singleton the autoload calls. Don't also enable the legacy android/pushhub.gdap descriptor, or the AAR is added twice.
Verification so far: the zip's contents, the AAR against the Maven repository, the export plug-in's dependencies against the POM, and a Gradle build with the shape of a Godot export are checked by scripts/sdk-consumer-validation/godot.mjs. No Godot export or device run has happened, so the plug-in stays Preview.
iOS stays Preview until the protected macOS pipeline produces the signed XCFramework and the Godot export matrix passes.
Remote config
Remote config lets you change values in a shipped game, such as starter coins, a maintenance flag or a store layout, from the PushHub dashboard. You reach it through PushHub.config, an instance of PushHubRemoteConfig.
Remote config needs Godot SDK 0.1.0-beta.2 or later. On Android it also needs the Android SDK AAR 0.1.0-beta.5 or later (0.1.0-beta.6 adds instant refresh). Godot SDK 0.1.0-beta.3 ships the 0.1.0-beta.7 AAR.
Setup and defaults
Set in-app defaults before you read any value. The getters use them before the first fetch and for any key the server leaves out.
PushHub.config.set_defaults({
"starter_coins": 100,
"maintenance_mode": false,
"welcome_text": "Welcome!",
"store_layout": {"tabs": ["offers", "coins"]}, # a Dictionary, an Array, or a JSON string
})
set_defaults replaces the previous defaults, and a null value is ignored. To load defaults from a bundled JSON file, pass its text to set_defaults_from_json(text). It returns false if the text isn't a JSON object.
Fetch on load
func _ready() -> void:
PushHub.started.connect(_on_pushhub_started)
PushHub.configure(APP_ID, "ph_pub_YOUR_KEY")
PushHub.start()
func _on_pushhub_started(_installation_id: String) -> void:
var changed: bool = await PushHub.config.fetch_and_activate() # true when the active values changed
Fetching needs a registered installation, so call it once start() has finished, which the started signal tells you. Before each fetch, the native SDK reports a changed device context (for example a new app version), so targeting conditions use current values.
If you'd rather not await, connect to the fetch_completed(success, changed) signal and call PushHub.config.fetch_and_activate() without await.
To apply config only at a safe moment, such as a loading screen, fetch and activate separately:
await PushHub.config.fetch() # downloads, but the getters don't change yet
# ...later, on the loading screen
if PushHub.config.activate():
apply_config()
Read values
var coins: int = PushHub.config.get_int("starter_coins")
var maintenance: bool = PushHub.config.get_bool("maintenance_mode")
var multiplier: float = PushHub.config.get_float("price_multiplier")
var text: String = PushHub.config.get_string("welcome_text")
var layout = JSON.parse_string(PushHub.config.get_json("store_layout")) # Dictionary or Array
var value := PushHub.config.get_value("starter_coins")
if value.source == PushHubRemoteConfig.Source.REMOTE:
print("coins come from the dashboard: ", value.as_int())
var everything: Dictionary = PushHub.config.get_all() # key -> resolved value
Each getter looks for the active remote value first, then your in-app default, and otherwise returns the type's zero value ("", false, 0, 0.0, or "" for JSON). get_value(key) returns a PushHubRemoteConfig.Value with value, source (REMOTE, DEFAULT or STATIC) and the same as_string(), as_bool(), as_int(), as_float() and as_json() conversions. The getters never fail, and they read a cached snapshot, so they're cheap to call every frame.
Godot parses every JSON number as a float. The SDK turns whole numbers back into int, so get_string("starter_coins") returns "100", not "100.0".
Listen for updates
PushHub.config.updated.connect(func(keys: PackedStringArray):
if "maintenance_mode" in keys:
refresh_maintenance_banner()
)
updated fires on the main thread after an activation that changed values. It receives only the keys that were added, removed or changed.
Offline behaviour
The native SDK stores the active values, ETag, version and last fetch time on the device. After configure, the last activated config is available offline and on the next cold start, before any network call.
A failed fetch never raises an error. fetch_and_activate() and fetch() return false, log a warning with push_warning, and keep the active values. Each fetch sends the stored ETag, so an unchanged config costs a 304 Not Modified.
Fetch interval
A fetch reaches the network at most once per interval. The interval is the larger of the server's minimumFetchIntervalSeconds (900 seconds by default) and PushHub.config.minimum_fetch_interval_seconds. Inside the interval, a fetch succeeds and uses the stored config. Pass true to skip the interval in development builds. Each fetch times out after 10 seconds.
PushHub.config.minimum_fetch_interval_seconds = 3600
await PushHub.config.fetch_and_activate(OS.is_debug_build())
Instant refresh
When you publish, roll back or schedule a publish with Notify devices set to Test devices only or All players, PushHub sends the environment's devices a silent message.
- Android: with the Android SDK AAR 0.1.0-beta.6 or later, the native SDK fetches and activates the newer config with no game code while the game is running. Only that case is supported: the Android core 0.1.0-beta.7 in Godot SDK 0.1.0-beta.3 can configure itself when Android starts the game's process for a refresh, but that hasn't been validated with Godot, so don't rely on it.
PushHub.configshows the new values, andupdatedfires, the next time the game callsfetch_and_activate()oractivate()(a call inside the minimum interval makes no request but still picks them up), or at the next launch. - iOS: not available yet, because the iOS plug-in doesn't include remote config (see Platforms).
Signed config is not available in this SDK. It has no API to set trusted signing keys, so it accepts unsigned config even when Config signing is turned on for the environment. Native verification exists in the Android core only when your own Android code sets the keys. See SDK support levels.
Instant refresh is best effort, so keep fetching on load.
C#
PushHubClient.Config wraps the autoload's PushHub.config, so keep the PushHub plug-in enabled:
var config = GetNode<PushHubClient>("PushHubClient").Config;
config.SetDefaults(new Godot.Collections.Dictionary { ["starter_coins"] = 100 });
bool changed = await config.FetchAndActivateAsync();
long coins = config.GetInt("starter_coins");
config.Updated += keys => GD.Print(string.Join(", ", keys));
Platforms
- Android: uses the native Android SDK's config API through the
PushHubNativeplug-in. - iOS: the iOS plug-in binary doesn't include the config methods yet, so iOS exports use your in-app defaults. The SDK checks for the methods and starts fetching once an iOS plug-in provides them:
configFetchAndActivate(force, request_id),configFetch(force, request_id),configActivate(),configActiveValues()andconfigSetMinimumFetchInterval(seconds), completing through aconfig_completed(request_id, success, result, error)signal. - Editor and desktop: no network calls. The getters return your in-app defaults, the fetch methods return
false, and the SDK logs this once.