unified_game_services_google_play_android

Native Google Play Games provider for unified_game_services, backed by the Play Games v2 Java SDK reached over package:jni — pure Dart, no Flutter. Android only.

Most apps should use unified_game_services_google_play (auto-selects this on Android, REST elsewhere) rather than depending on this package directly.

Why this exists

The REST provider (unified_game_services_google_play_rest) talks to Google's cloud and so cannot fire the native Play Services achievement/leaderboard toasts on Android. This provider routes writes through the on-device Play Games client, so unlocks and score submissions show the native overlay. Authentication is handled by Play Services — there is no OAuth token to manage.

package:jni/jnigen reach the Java SDK via JNI (the same approach objective_c uses for GameKit), so this stays within the repo's no-Flutter constraint. games_services is banned because it uses Flutter platform channels — JNI does not.

Host requirements

This package is pure Dart, but the SDK needs the host (the engine/app embedding Dart on Android) to supply the Android runtime — the same "host supplies the runtime" shape as Steam (needs the Steam client) and Game Center (needs a signed bundle + run loop):

  1. A running ART VM with package:jni initialized against it (host hands the JavaVM*/JNIEnv to JNI on startup).
  2. An activityResolver (JObject Function()) passed to the constructor — invoked fresh before each native call so a volatile activity is never cached (e.g. () => ANativeActivity.clazz for a stable engine activity).
  3. The APK bundles com.google.android.gms:play-services-games-v2 and declares the Play Games app id <meta-data> in its manifest.

Status

  • Implemented: the native-UX writes — unlockAchievement, incrementAchievement, revealAchievement, submitScore, and the provider-specific setAchievementStepsAtLeast. signIn() triggers the native sign-in flow and returns the player; isSignedIn() and getCurrentPlayer() (id + display name, no avatar) read the SDK's Task results.
  • Reads: getAchievements (definitions + progress, native steps), getLeaderboard (top 1–25 scores; daily/weekly/all-time, public/friends) and getPlayerScore (global rank at any position). The payload types are opaque in the committed bindings, so their getters are called reflectively by JNI signature (lib/src/play_games_data.dart); regenerating the bindings with those classes included would make that unnecessary.
  • signOut() throws PlatformOperationException: Play Games v2 has no programmatic sign-out.
  • Runtime-verified on a Flutter Android host (see the family's ..._flutter example/): signIn() fires the native Play Games sign-in overlay, proving the JNI path reaches the live SDK (VM/Activity wiring + bindings work). Write toasts and the Task-backed read path still need a configured Play Console game + tester account to fully exercise.

Native screens

The provider advertises GameCapability.overlays: showAchievementsUI() and showLeaderboardsUI({leaderboardId}) open the native Play Games screens (the unified leaderboard id is translated to the Play Games id). showOverlay() is not supported by Play Games and throws PlatformOperationException. The player must be signed in.

Bindings

lib/src/playgames_bindings.dart is generated and committed. Regenerate with:

ANDROID_SDK_ROOT=/path/to/sdk tool/regenerate_bindings.sh [PLAY_GAMES_VERSION]

Needs the Android SDK (for android.jar), a JDK ≤ 21 (the ASM summarizer), and network access to Google's Maven. The script resolves the Play Games aar + transitive deps, extracts each classes.jar, and runs jnigen against that classpath. Keep the runtime jni dependency aligned with the jnigen version (jnigen 1.x → jni ^1.0.3; committed bindings were generated with jnigen 0.16.0 and not yet regenerated).

License

MIT — see LICENSE. Independent, unofficial; not affiliated with any platform vendor. See the repository NOTICE.md.

Libraries

unified_game_services_google_play_android
Native Google Play Games provider for unified_game_services, backed by the Play Games v2 Java SDK over package:jni.