Unreal Engine SDK
Preview · 0.1.0-beta.3 · Unreal Engine 5.4–5.7 · Android and iOS
Download PushHub for Unreal, extract it into YourGame/Plugins/PushHub, regenerate project files, and enable the plug-in.
Android dependencies. Nothing else to install. The plug-in's PushHub_APL.xml adds PushHub's Maven repository (https://docs.pushhub.kemegames.com/maven, limited to the com.kemegames.pushhub group) and com.kemegames.pushhub:pushhub-android:0.1.0-beta.7 to the Android Gradle project Unreal generates, so Gradle downloads the core and its dependencies. Earlier versions named the dependency without a repository that hosts it, so you had to put the AAR in Maven local; that step is no longer needed. Add your Firebase configuration. The APL text was applied to a Gradle app shaped like Unreal's and built (scripts/sdk-consumer-validation/unreal.mjs), but no Unreal Engine build has run, so the plug-in stays Preview.
Use the game-instance PushHubSubsystem from Blueprint or C++:
auto* Push = GetGameInstance()->GetSubsystem<UPushHubSubsystem>();
Push->Configure(AppId, TEXT("ph_pub_YOUR_KEY"));
Push->Start();
Push->Track(TEXT("level_completed"), {{TEXT("level"), TEXT("20")}});
Blueprint operations report through OnOperationComplete(Success, ErrorClass). The Android Plugin Language receipt declares the native Android core; iOS links UserNotifications and Security. Provider credentials remain in the PushHub workspace.
The module also loads in the editor and on desktop (Win64, Mac, Linux), so Blueprints that use the subsystem compile there. Off-device, nothing reaches the network: operations report UnsupportedPlatform and remote config uses your in-app defaults.
This archive is a source Preview. Unreal editor/package builds and engine-minor binary archives are not labeled Stable until the Phase 4E matrix passes.
Native bridges
- Android: the subsystem calls
com.kemegames.pushhub.unreal.PushHubUnrealBridgein the PushHub Android SDK over JNI, and results return to the game thread.PushHub_APL.xmladdscom.kemegames.pushhub:pushhub-android:0.1.0-beta.7from PushHub's Maven repository, which includes the engine bridges (Android SDK 0.1.0-beta.5 and later do). If the bridge class is missing, the plug-in logs one warning and behaves as it does in the editor. - iOS: Unreal doesn't compile Swift, so the iOS bridge is a framework you build on macOS. Build
Source/ThirdParty/IOS/PushHubUnrealBridge.swifttogether with the PushHub iOS SDK (Swift 5 language mode) into a framework namedPushHubUnreal. The bridge calls the iOS SDK'sPushHub.config, so it needs the next iOS SDK release, which is pending a macOS build. PlacePushHubUnreal.xcframework(orPushHubUnreal.embeddedframework.zip) inSource/ThirdParty/IOS/.PushHub.Build.cslinks it when it's present. Without it, iOS builds use in-app config defaults only and operations reportUnsupportedPlatform. - iOS registration:
Startneeds the APNs device token. If Unreal hasn't reported one yet,Startasks iOS to register for remote notifications (no permission prompt), waits for the token, and then registers. If iOS can't provide a token, for example on a simulator,OnOperationCompletereportsRemoteNotificationsUnavailable. CallRequestNotificationPermissionto show the permission prompt.
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. The functions are on UPushHubSubsystem, under PushHub | Remote Config in Blueprint.
Remote config needs Unreal SDK 0.1.0-beta.2 or later. On Android, the 0.1.0-beta.2 PushHub_APL.xml adds Android SDK 0.1.0-beta.6, and the 0.1.0-beta.3 one adds 0.1.0-beta.7. On iOS it needs the PushHubUnreal framework described above.
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.
Push->SetConfigDefaults({
{TEXT("starter_coins"), TEXT("100")},
{TEXT("maintenance_mode"), TEXT("false")},
{TEXT("welcome_text"), TEXT("Welcome!")},
{TEXT("store_layout"), TEXT("{\"tabs\":[\"offers\",\"coins\"]}")},
});
// Or keep the JSON types, for example from a bundled file:
Push->SetConfigDefaultsFromJson(TEXT("{\"starter_coins\":100,\"maintenance_mode\":false}"));
SetConfigDefaults takes text, which is what Blueprint maps hold. The typed getters read "true", "42", "1.5" and JSON objects or arrays. Both functions replace the previous defaults. SetConfigDefaultsFromJson returns false and keeps the defaults if the text isn't a JSON object.
Fetch on load
// In a UObject, for example your game instance:
UFUNCTION() void OnConfigFetched(bool bSuccess, bool bChanged, const FString& Error);
FPushHubConfigFetched Done;
Done.BindDynamic(this, &UMyGameInstance::OnConfigFetched);
Push->FetchAndActivateConfig(/*bForce*/ false, Done);
In Blueprint, call Fetch And Activate Config and bind a custom event to On Complete. bChanged is true when the active values changed.
Fetching needs a registered installation, so fetch after Start has completed. On Android, the native SDK reports a changed device context (for example a new app version) before it fetches, so targeting conditions use current values.
To apply config only at a safe moment, such as a loading screen, fetch and activate separately. FetchConfig downloads without changing the getters, and ActivateConfig later applies what was fetched. It returns true when values changed.
Read values
const int64 Coins = Push->GetConfigInt(TEXT("starter_coins"));
const bool bMaintenance = Push->GetConfigBool(TEXT("maintenance_mode"));
const double Multiplier = Push->GetConfigFloat(TEXT("price_multiplier"));
const FString Text = Push->GetConfigString(TEXT("welcome_text"));
const FString LayoutJson = Push->GetConfigJson(TEXT("store_layout")); // raw JSON text, or ""
const EPushHubConfigSource Source = Push->GetConfigSource(TEXT("starter_coins")); // Remote, Default or Static
const TMap<FString, FString> All = Push->GetAllConfig();
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). Pass GetConfigJson text to FJsonSerializer or FJsonObjectConverter::JsonObjectStringToUStruct for typed data. The getters never fail, and they read a cached snapshot, so they're cheap to call every frame. Keys follow Unreal's FString comparison, so they're case-insensitive: don't use two keys that differ only in case.
Listen for updates
UFUNCTION() void OnConfigUpdated(const TArray<FString>& ChangedKeys);
Push->OnConfigUpdated.AddDynamic(this, &UMyGameInstance::OnConfigUpdated);
OnConfigUpdated broadcasts on the game thread after an activation that changed values. It receives only the keys that were added, removed or changed. In Blueprint, bind to On Config Updated.
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 fails the game. The completion receives bSuccess = false and the error text, a warning is logged, and the active values stay as they were. 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 the value you pass to SetConfigMinimumFetchInterval. Inside the interval, a fetch succeeds and uses the stored config. Pass bForce = true to skip the interval in development builds. Each fetch times out after 10 seconds.
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: from Unreal SDK 0.1.0-beta.2, whose
PushHub_APL.xmladds Android SDK 0.1.0-beta.6, 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 that Unreal SDK 0.1.0-beta.3 adds can configure itself when Android starts the game's process for a refresh, but that hasn't been validated with Unreal, so don't rely on it. See SDK support levels. - iOS: needs the
PushHubUnrealframework, like remote config itself. Enable Remote Notifications Support under Project Settings → Platforms → iOS, and check that the packagedInfo.plistlistsremote-notificationunderUIBackgroundModes(add it through Additional Plist Data if it doesn't). Unreal's app delegate answers iOS itself and hands the payload to the game as JSON, so fetch from your game instance when the payload is a PushHub refresh. Add"Json"to your module's dependencies, then:
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.
#include "Misc/CoreDelegates.h"
#include "Serialization/JsonReader.h"
#include "Serialization/JsonSerializer.h"
#include "PushHubSubsystem.h"
void UMyGameInstance::Init()
{
Super::Init();
FCoreDelegates::ApplicationReceivedRemoteNotificationDelegate.AddUObject(this, &UMyGameInstance::HandleRemoteNotification);
}
// Declared in the header as: void HandleRemoteNotification(FString Json, int AppState);
void UMyGameInstance::HandleRemoteNotification(FString Json, int AppState)
{
TSharedPtr<FJsonObject> Payload;
FString Action;
if (FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(Json), Payload) && Payload.IsValid()
&& Payload->TryGetStringField(TEXT("pushhub_action"), Action) && Action == TEXT("config_refresh"))
{
GetSubsystem<UPushHubSubsystem>()->FetchAndActivateConfig(true, FPushHubConfigFetched());
}
}
On iOS this refresh is reliable while the game runs in the foreground. Because Unreal completes iOS's background handling straight away, a refresh that arrives while the game is suspended may not finish, and the next launch fetch picks the config up instead.
On Android, the native SDK activates the new values right away. The subsystem's getters show them, and OnConfigUpdated broadcasts, the next time the game calls FetchAndActivateConfig or ActivateConfig (a call inside the minimum interval makes no request but still picks them up), or at the next launch. Instant refresh is best effort, so keep fetching on load.
Platforms
- Android: uses the native Android SDK's config API through
PushHubUnrealBridge. - iOS: uses the iOS SDK's
PushHub.configthrough thePushHubUnrealframework. Without the framework, the getters return your in-app defaults. - Editor and desktop: no network calls. The getters return your in-app defaults, fetches complete with
bSuccess = falseandUnsupportedPlatform, and the plug-in logs this once.