@modbender/capacitor-play-games 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/CapacitorPlayGames.podspec +17 -0
  3. package/LICENSE +22 -0
  4. package/Package.swift +36 -0
  5. package/README.md +611 -0
  6. package/android/build.gradle +76 -0
  7. package/android/consumer-rules.pro +4 -0
  8. package/android/proguard-rules.pro +2 -0
  9. package/android/src/main/AndroidManifest.xml +2 -0
  10. package/android/src/main/java/com/idleflowgames/playgames/AchievementsModule.kt +26 -0
  11. package/android/src/main/java/com/idleflowgames/playgames/LeaderboardsModule.kt +27 -0
  12. package/android/src/main/java/com/idleflowgames/playgames/Pgs.kt +48 -0
  13. package/android/src/main/java/com/idleflowgames/playgames/PlayGamesPlugin.kt +88 -0
  14. package/android/src/main/java/com/idleflowgames/playgames/SavedGamesModule.kt +119 -0
  15. package/android/src/main/java/com/idleflowgames/playgames/SignInModule.kt +83 -0
  16. package/dist/esm/definitions.d.ts +227 -0
  17. package/dist/esm/definitions.d.ts.map +1 -0
  18. package/dist/esm/definitions.js +2 -0
  19. package/dist/esm/definitions.js.map +1 -0
  20. package/dist/esm/index.d.ts +5 -0
  21. package/dist/esm/index.d.ts.map +1 -0
  22. package/dist/esm/index.js +7 -0
  23. package/dist/esm/index.js.map +1 -0
  24. package/dist/esm/web.d.ts +33 -0
  25. package/dist/esm/web.d.ts.map +1 -0
  26. package/dist/esm/web.js +45 -0
  27. package/dist/esm/web.js.map +1 -0
  28. package/dist/plugin.cjs.js +59 -0
  29. package/dist/plugin.cjs.js.map +1 -0
  30. package/dist/plugin.js +62 -0
  31. package/dist/plugin.js.map +1 -0
  32. package/ios/Plugin/AchievementsModule.swift +73 -0
  33. package/ios/Plugin/LeaderboardsModule.swift +75 -0
  34. package/ios/Plugin/Pgs.swift +40 -0
  35. package/ios/Plugin/Plugin.swift +74 -0
  36. package/ios/Plugin/SavedGamesModule.swift +102 -0
  37. package/ios/Plugin/SignInModule.swift +139 -0
  38. package/package.json +80 -0
@@ -0,0 +1,26 @@
1
+ package com.idleflowgames.playgames
2
+
3
+ import com.getcapacitor.PluginCall
4
+ import com.google.android.gms.games.PlayGames
5
+
6
+ internal class AchievementsModule(plugin: PlayGamesPlugin) : PgsModule(plugin) {
7
+ private val client get() = PlayGames.getAchievementsClient(activity)
8
+
9
+ fun unlock(call: PluginCall) {
10
+ val id = call.getString("id") ?: return call.reject("missing id")
11
+ client.unlock(id)
12
+ call.resolve()
13
+ }
14
+
15
+ fun increment(call: PluginCall) {
16
+ val id = call.getString("id") ?: return call.reject("missing id")
17
+ val steps = call.getInt("steps") ?: return call.reject("missing steps")
18
+ if (steps <= 0) return call.reject("steps must be > 0")
19
+ client.increment(id, steps)
20
+ call.resolve()
21
+ }
22
+
23
+ fun show(call: PluginCall) {
24
+ plugin.launchUiIntent(client.achievementsIntent, call, "onAchievementsUiResult")
25
+ }
26
+ }
@@ -0,0 +1,27 @@
1
+ package com.idleflowgames.playgames
2
+
3
+ import com.getcapacitor.PluginCall
4
+ import com.google.android.gms.games.PlayGames
5
+
6
+ internal class LeaderboardsModule(plugin: PlayGamesPlugin) : PgsModule(plugin) {
7
+ private val client get() = PlayGames.getLeaderboardsClient(activity)
8
+
9
+ fun submit(call: PluginCall) {
10
+ val id = call.getString("leaderboardId") ?: return call.reject("missing leaderboardId")
11
+ val score = call.getDouble("score") ?: return call.reject("missing score")
12
+ client.submitScoreImmediate(id, score.toLong())
13
+ .addOnSuccessListener { call.resolve() }
14
+ .addOnFailureListener { e ->
15
+ call.rejectFromException(e, "submitScore failed")
16
+ }
17
+ }
18
+
19
+ fun show(call: PluginCall) {
20
+ val id = call.getString("leaderboardId") ?: return call.reject("missing leaderboardId")
21
+ plugin.launchUiIntent(client.getLeaderboardIntent(id), call, "onLeaderboardUiResult")
22
+ }
23
+
24
+ fun showAll(call: PluginCall) {
25
+ plugin.launchUiIntent(client.allLeaderboardsIntent, call, "onLeaderboardUiResult")
26
+ }
27
+ }
@@ -0,0 +1,48 @@
1
+ package com.idleflowgames.playgames
2
+
3
+ import androidx.appcompat.app.AppCompatActivity
4
+ import com.getcapacitor.JSObject
5
+ import com.getcapacitor.PluginCall
6
+ import com.google.android.gms.common.api.ApiException
7
+ import com.google.android.gms.games.Player
8
+ import com.google.android.gms.tasks.Task
9
+
10
+ /** Shared base for the per-feature modules; carries the plugin back-reference. */
11
+ internal abstract class PgsModule(protected val plugin: PlayGamesPlugin) {
12
+ protected val activity: AppCompatActivity
13
+ get() = plugin.activity
14
+ }
15
+
16
+ /** Build a JSObject with a fluent block — `jsObject { put("k", v) }`. */
17
+ internal inline fun jsObject(builder: JSObject.() -> Unit): JSObject =
18
+ JSObject().apply(builder)
19
+
20
+ /** Reject a PluginCall, exposing a GMS ApiException statusCode as the Capacitor error code. */
21
+ internal fun PluginCall.rejectFromException(e: Exception, fallbackMsg: String) {
22
+ val message = e.message ?: fallbackMsg
23
+ val status = (e as? ApiException)?.statusCode
24
+ if (status != null) reject(message, status.toString(), e) else reject(message, e)
25
+ }
26
+
27
+ /** Resolve a void-yielding Task to a PluginCall (success resolves, failure rejects). */
28
+ internal fun Task<*>.bind(call: PluginCall, errorMsg: String = "operation failed") {
29
+ addOnSuccessListener { call.resolve() }
30
+ addOnFailureListener { e -> call.rejectFromException(e, errorMsg) }
31
+ }
32
+
33
+ /** Resolve a value-yielding Task to a PluginCall, mapping the result to a JSObject. */
34
+ internal inline fun <T> Task<T>.bind(
35
+ call: PluginCall,
36
+ errorMsg: String = "operation failed",
37
+ crossinline transform: (T) -> JSObject,
38
+ ) {
39
+ addOnSuccessListener { result -> call.resolve(transform(result)) }
40
+ addOnFailureListener { e -> call.rejectFromException(e, errorMsg) }
41
+ }
42
+
43
+ /** Serialise a PGS Player as the JS-side `PlayerInfo` shape. */
44
+ internal fun Player.toJsObject(): JSObject = jsObject {
45
+ put("playerId", playerId)
46
+ put("displayName", displayName ?: "")
47
+ iconImageUri?.toString()?.let { put("avatarUrl", it) }
48
+ }
@@ -0,0 +1,88 @@
1
+ package com.idleflowgames.playgames
2
+
3
+ import android.content.Intent
4
+ import androidx.activity.result.ActivityResult
5
+ import com.getcapacitor.JSObject
6
+ import com.getcapacitor.Plugin
7
+ import com.getcapacitor.PluginCall
8
+ import com.getcapacitor.PluginMethod
9
+ import com.getcapacitor.annotation.ActivityCallback
10
+ import com.getcapacitor.annotation.CapacitorPlugin
11
+ import com.google.android.gms.games.PlayGamesSdk
12
+ import com.google.android.gms.tasks.Task
13
+
14
+ /**
15
+ * Capacitor 8 plugin wrapping Google Play Games Services v2. Thin dispatcher to
16
+ * the per-feature modules; the `@ActivityCallback` UI-result handlers live here
17
+ * because Capacitor requires them on the Plugin subclass.
18
+ */
19
+ @CapacitorPlugin(name = "PlayGames")
20
+ class PlayGamesPlugin : Plugin() {
21
+ private val signIn by lazy { SignInModule(this) }
22
+ private val achievements by lazy { AchievementsModule(this) }
23
+ private val leaderboards by lazy { LeaderboardsModule(this) }
24
+ private val savedGames by lazy { SavedGamesModule(this) }
25
+
26
+ override fun load() {
27
+ super.load()
28
+ // Non-fatal: without Play Services, PGS calls resolve signedIn=false rather than crash.
29
+ runCatching { PlayGamesSdk.initialize(context) }
30
+ }
31
+
32
+ /** Expose listener emission to modules; `notifyListeners` is protected. */
33
+ internal fun emit(event: String, data: JSObject) =
34
+ notifyListeners(event, data)
35
+
36
+ /** Launch a PGS UI intent (achievements / leaderboards) via the activity-result bridge. */
37
+ internal fun launchUiIntent(
38
+ intentTask: Task<Intent>,
39
+ call: PluginCall,
40
+ callbackName: String,
41
+ ) {
42
+ intentTask
43
+ .addOnSuccessListener { intent ->
44
+ startActivityForResult(call, intent, callbackName)
45
+ }
46
+ .addOnFailureListener { e ->
47
+ call.rejectFromException(e, "PGS intent failed")
48
+ }
49
+ }
50
+
51
+ // ---- @PluginMethod entrypoints (JS-callable surface) -------------------
52
+
53
+ @PluginMethod fun initialize(call: PluginCall) = call.resolve()
54
+
55
+ @PluginMethod fun signIn(call: PluginCall) = signIn.signIn(call)
56
+ @PluginMethod fun isSignedIn(call: PluginCall) = signIn.isSignedIn(call)
57
+ @PluginMethod fun getPlayer(call: PluginCall) = signIn.getPlayer(call)
58
+ @PluginMethod fun requestServerSideAccess(call: PluginCall) = signIn.requestServerSideAccess(call)
59
+
60
+ @PluginMethod fun unlockAchievement(call: PluginCall) = achievements.unlock(call)
61
+ @PluginMethod fun incrementAchievement(call: PluginCall) = achievements.increment(call)
62
+ @PluginMethod fun showAchievements(call: PluginCall) = achievements.show(call)
63
+
64
+ @PluginMethod fun submitScore(call: PluginCall) = leaderboards.submit(call)
65
+ @PluginMethod fun showLeaderboard(call: PluginCall) = leaderboards.show(call)
66
+ @PluginMethod fun showAllLeaderboards(call: PluginCall) = leaderboards.showAll(call)
67
+
68
+ @PluginMethod fun loadSnapshot(call: PluginCall) = savedGames.load(call)
69
+ @PluginMethod fun saveSnapshot(call: PluginCall) = savedGames.save(call)
70
+ @PluginMethod fun listSnapshots(call: PluginCall) = savedGames.list(call)
71
+ @PluginMethod fun deleteSnapshot(call: PluginCall) = savedGames.delete(call)
72
+
73
+ // ---- @ActivityCallback handlers ----------------------------------------
74
+
75
+ @Suppress("unused") // referenced by name from launchUiIntent
76
+ @ActivityCallback
77
+ private fun onAchievementsUiResult(call: PluginCall?, result: ActivityResult) =
78
+ resolveUiResult(call, result)
79
+
80
+ @Suppress("unused")
81
+ @ActivityCallback
82
+ private fun onLeaderboardUiResult(call: PluginCall?, result: ActivityResult) =
83
+ resolveUiResult(call, result)
84
+
85
+ private fun resolveUiResult(call: PluginCall?, @Suppress("UNUSED_PARAMETER") result: ActivityResult) {
86
+ call?.resolve()
87
+ }
88
+ }
@@ -0,0 +1,119 @@
1
+ package com.idleflowgames.playgames
2
+
3
+ import com.getcapacitor.JSArray
4
+ import com.getcapacitor.JSObject
5
+ import com.getcapacitor.PluginCall
6
+ import com.google.android.gms.games.PlayGames
7
+ import com.google.android.gms.games.SnapshotsClient
8
+ import com.google.android.gms.games.snapshot.SnapshotMetadata
9
+ import com.google.android.gms.games.snapshot.SnapshotMetadataChange
10
+ import java.nio.charset.StandardCharsets
11
+ import java.util.concurrent.Executor
12
+ import java.util.concurrent.Executors
13
+
14
+ /** PGS Saved Games (Snapshots). Conflicts resolve most-recently-modified-wins (no merge). */
15
+ internal class SavedGamesModule(plugin: PlayGamesPlugin) : PgsModule(plugin) {
16
+ private val client get() = PlayGames.getSnapshotsClient(activity)
17
+
18
+ fun load(call: PluginCall) {
19
+ val name = call.getString("name") ?: return call.reject("missing name")
20
+ // Blocking snapshot I/O off the main thread (GMS Task listeners default to UI).
21
+ client.open(name, /* createIfNotFound = */ true, AUTO_RESOLVE)
22
+ .addOnSuccessListener(IO_EXECUTOR) { result ->
23
+ val snap = result.data
24
+ if (snap == null) {
25
+ call.resolve(jsObject { put("snapshot", JSObject.NULL) })
26
+ return@addOnSuccessListener
27
+ }
28
+ val bytes = snap.snapshotContents.readFully() ?: ByteArray(0)
29
+ val payload = jsObject {
30
+ put("name", snap.metadata.uniqueName)
31
+ put("description", snap.metadata.description ?: "")
32
+ put("modifiedAt", snap.metadata.lastModifiedTimestamp)
33
+ put("data", String(bytes, StandardCharsets.UTF_8))
34
+ }
35
+ client.discardAndClose(snap)
36
+ call.resolve(jsObject { put("snapshot", payload) })
37
+ }
38
+ .addOnFailureListener(IO_EXECUTOR) { e ->
39
+ call.rejectFromException(e, "snapshot load failed")
40
+ }
41
+ }
42
+
43
+ fun save(call: PluginCall) {
44
+ val name = call.getString("name") ?: return call.reject("missing name")
45
+ val data = call.getString("data") ?: return call.reject("missing data")
46
+ val description = call.getString("description") ?: ""
47
+
48
+ // Blocking snapshot I/O off the main thread.
49
+ client.open(name, /* createIfNotFound = */ true, AUTO_RESOLVE)
50
+ .continueWithTask(IO_EXECUTOR) { task ->
51
+ val snap = task.result?.data
52
+ ?: throw IllegalStateException("snapshot unavailable")
53
+ snap.snapshotContents.writeBytes(data.toByteArray(StandardCharsets.UTF_8))
54
+ val change = SnapshotMetadataChange.Builder()
55
+ .setDescription(description)
56
+ .build()
57
+ client.commitAndClose(snap, change)
58
+ }
59
+ .bind(call, "snapshot save failed")
60
+ }
61
+
62
+ fun list(call: PluginCall) {
63
+ client.load(/* forceReload = */ false).bind(call, "snapshot list failed") { result ->
64
+ val arr = JSArray()
65
+ result.get()?.use { buf ->
66
+ for (i in 0 until buf.count) arr.put(buf.get(i).toJsObject())
67
+ }
68
+ jsObject { put("snapshots", arr) }
69
+ }
70
+ }
71
+
72
+ fun delete(call: PluginCall) {
73
+ val name = call.getString("name") ?: return call.reject("missing name")
74
+ client.load(false)
75
+ .continueWithTask { task ->
76
+ val meta = task.result?.get()?.use { buf ->
77
+ buf.firstOrNull { it.uniqueName == name }?.freeze()
78
+ } ?: throw NoSuchElementException("snapshot '$name' not found")
79
+ client.delete(meta)
80
+ }
81
+ .bind(call, "snapshot delete failed")
82
+ }
83
+
84
+ private companion object {
85
+ const val AUTO_RESOLVE = SnapshotsClient.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED
86
+
87
+ // Serial daemon thread for snapshot file I/O.
88
+ val IO_EXECUTOR: Executor = Executors.newSingleThreadExecutor { r ->
89
+ Thread(r, "pgs-saved-games").apply { isDaemon = true }
90
+ }
91
+ }
92
+ }
93
+
94
+ private fun SnapshotMetadata.toJsObject(): JSObject = jsObject {
95
+ put("name", uniqueName)
96
+ put("description", description ?: "")
97
+ put("modifiedAt", lastModifiedTimestamp)
98
+ }
99
+
100
+ /** SnapshotMetadataBuffer has release() but isn't Closeable; provide a use {} of our own. */
101
+ private inline fun <R> com.google.android.gms.games.snapshot.SnapshotMetadataBuffer.use(
102
+ block: (com.google.android.gms.games.snapshot.SnapshotMetadataBuffer) -> R,
103
+ ): R {
104
+ try {
105
+ return block(this)
106
+ } finally {
107
+ release()
108
+ }
109
+ }
110
+
111
+ private fun com.google.android.gms.games.snapshot.SnapshotMetadataBuffer.firstOrNull(
112
+ predicate: (SnapshotMetadata) -> Boolean,
113
+ ): SnapshotMetadata? {
114
+ for (i in 0 until count) {
115
+ val m = get(i)
116
+ if (predicate(m)) return m
117
+ }
118
+ return null
119
+ }
@@ -0,0 +1,83 @@
1
+ package com.idleflowgames.playgames
2
+
3
+ import com.getcapacitor.PluginCall
4
+ import com.google.android.gms.common.ConnectionResult
5
+ import com.google.android.gms.common.GoogleApiAvailability
6
+ import com.google.android.gms.games.PlayGames
7
+
8
+ internal class SignInModule(plugin: PlayGamesPlugin) : PgsModule(plugin) {
9
+ private val signInClient get() = PlayGames.getGamesSignInClient(activity)
10
+ private val playersClient get() = PlayGames.getPlayersClient(activity)
11
+
12
+ fun signIn(call: PluginCall) {
13
+ val silent = call.getBoolean("silent", true) ?: true
14
+ // Interactive sign-in can crash uncatchably inside GMS's
15
+ // GamesResolutionActivity on devices with a broken Play Services install
16
+ // (some custom ROMs). Pre-flight the availability check and bail to
17
+ // signed-out rather than launch the activity. Silent auth shows no UI.
18
+ if (!silent) {
19
+ val gmsStatus = GoogleApiAvailability.getInstance()
20
+ .isGooglePlayServicesAvailable(activity)
21
+ if (gmsStatus != ConnectionResult.SUCCESS) {
22
+ resolveSignedOut(call)
23
+ return
24
+ }
25
+ }
26
+ val task = if (silent) signInClient.isAuthenticated else signInClient.signIn()
27
+ task
28
+ .addOnSuccessListener { result ->
29
+ if (result.isAuthenticated) resolveWithPlayer(call) else resolveSignedOut(call)
30
+ }
31
+ .addOnFailureListener {
32
+ resolveSignedOut(call)
33
+ }
34
+ }
35
+
36
+ fun isSignedIn(call: PluginCall) {
37
+ signInClient.isAuthenticated.bind(call, "auth check failed") { result ->
38
+ jsObject { put("signedIn", result.isAuthenticated) }
39
+ }
40
+ }
41
+
42
+ fun requestServerSideAccess(call: PluginCall) {
43
+ val serverClientId = call.getString("serverClientId")
44
+ if (serverClientId.isNullOrEmpty()) {
45
+ call.reject("serverClientId is required")
46
+ return
47
+ }
48
+ val forceRefresh = call.getBoolean("forceRefresh", false) ?: false
49
+ signInClient.requestServerSideAccess(serverClientId, forceRefresh)
50
+ .bind(call, "server-side access failed") { authCode ->
51
+ jsObject { put("authCode", authCode) }
52
+ }
53
+ }
54
+
55
+ fun getPlayer(call: PluginCall) {
56
+ playersClient.currentPlayer.bind(call, "player lookup failed") { player ->
57
+ player.toJsObject()
58
+ }
59
+ }
60
+
61
+ private fun resolveWithPlayer(call: PluginCall) {
62
+ playersClient.currentPlayer
63
+ .addOnSuccessListener { player ->
64
+ emitAndResolve(call, jsObject {
65
+ put("signedIn", true)
66
+ put("player", player.toJsObject())
67
+ })
68
+ }
69
+ .addOnFailureListener {
70
+ // Signed in but profile lookup failed: report signed-in, no profile.
71
+ emitAndResolve(call, jsObject { put("signedIn", true) })
72
+ }
73
+ }
74
+
75
+ private fun resolveSignedOut(call: PluginCall) {
76
+ emitAndResolve(call, jsObject { put("signedIn", false) })
77
+ }
78
+
79
+ private fun emitAndResolve(call: PluginCall, body: com.getcapacitor.JSObject) {
80
+ plugin.emit("signInStateChanged", body)
81
+ call.resolve(body)
82
+ }
83
+ }
@@ -0,0 +1,227 @@
1
+ import type { PluginListenerHandle } from "@capacitor/core";
2
+ /** A signed-in player's public profile. */
3
+ export interface PlayerInfo {
4
+ /** Stable, platform-assigned player id (PGS player id / GameKit `gamePlayerID`). */
5
+ playerId: string;
6
+ /** Display name as shown in Google Play Games / Game Center. */
7
+ displayName: string;
8
+ /** URL of the player's avatar image, when the platform exposes one. */
9
+ avatarUrl?: string;
10
+ }
11
+ /** Result of a sign-in attempt, or the payload of a sign-in state change. */
12
+ export interface SignInResult {
13
+ /** Whether the player is currently authenticated. */
14
+ signedIn: boolean;
15
+ /** The player profile, present only when `signedIn` is true. */
16
+ player?: PlayerInfo;
17
+ }
18
+ /** A saved-game snapshot together with its serialized payload. */
19
+ export interface Snapshot {
20
+ /** Stable unique name the snapshot was saved under. */
21
+ name: string;
22
+ /** Human-readable description stored with the snapshot. */
23
+ description: string;
24
+ /** Last-modified time, in epoch milliseconds. */
25
+ modifiedAt: number;
26
+ /** The serialized save payload as a UTF-8 string (encode binary yourself). */
27
+ data: string;
28
+ }
29
+ /** Snapshot metadata without the payload, as returned by `listSnapshots`. */
30
+ export interface SnapshotMeta {
31
+ /** Stable unique name of the snapshot. */
32
+ name: string;
33
+ /** Human-readable description stored with the snapshot. */
34
+ description: string;
35
+ /** Last-modified time, in epoch milliseconds. */
36
+ modifiedAt: number;
37
+ }
38
+ /**
39
+ * A GameKit identity-verification bundle
40
+ * (`GKLocalPlayer.fetchItems(forIdentityVerificationSignature:)`). A third-party
41
+ * server verifies `signature` against the certificate at `publicKeyUrl` to trust
42
+ * the Game Center `playerId` without relaying it through the untrusted client.
43
+ */
44
+ export interface IdentityVerificationSignature {
45
+ /** URL of Apple's public-key certificate used to verify `signature`. */
46
+ publicKeyUrl: string;
47
+ /** Base64-encoded signature over the verification payload. */
48
+ signature: string;
49
+ /** Base64-encoded random salt Apple mixed into the signed payload. */
50
+ salt: string;
51
+ /** Signature creation time, in epoch milliseconds (check freshness server-side). */
52
+ timestamp: number;
53
+ /** The player id the signature attests (GameKit `gamePlayerID`). */
54
+ playerId: string;
55
+ /** The app's bundle id, part of the signed payload. */
56
+ bundleId: string;
57
+ /** GameKit `teamPlayerID` (stable across the team's games), when available. */
58
+ teamPlayerId?: string;
59
+ /** GameKit `gamePlayerID` (stable per game), when available. */
60
+ gamePlayerId?: string;
61
+ }
62
+ /** Payload of the `signInStateChanged` event. */
63
+ export type SignInStateChangedEvent = SignInResult;
64
+ export interface PlayGamesPlugin {
65
+ /**
66
+ * Initialize the native games SDK. Idempotent.
67
+ *
68
+ * On Android this triggers `PlayGamesSdk.initialize`; on iOS it installs the
69
+ * GameKit authentication handler. Call once, after any App Tracking
70
+ * Transparency prompt has resolved, before the other methods.
71
+ *
72
+ * @since 0.1.0
73
+ */
74
+ initialize(): Promise<void>;
75
+ /**
76
+ * Sign in to the platform games service.
77
+ *
78
+ * `silent` (default `true`) attempts auto sign-in with no UI; on most devices
79
+ * this succeeds if the player has previously authenticated this game. Pass
80
+ * `silent: false` to force the full interactive flow, and only in response to
81
+ * an explicit user gesture.
82
+ *
83
+ * @since 0.1.0
84
+ */
85
+ signIn(opts?: {
86
+ silent?: boolean;
87
+ }): Promise<SignInResult>;
88
+ /**
89
+ * Whether a player is currently signed in.
90
+ * @since 0.1.0
91
+ */
92
+ isSignedIn(): Promise<{
93
+ signedIn: boolean;
94
+ }>;
95
+ /**
96
+ * Get the signed-in player's profile.
97
+ *
98
+ * On Android and iOS this rejects when no player is signed in. On web (the
99
+ * no-op fallback) it resolves an empty profile (`playerId: ""`).
100
+ * @since 0.1.0
101
+ */
102
+ getPlayer(): Promise<PlayerInfo>;
103
+ /**
104
+ * Request a one-time OAuth 2.0 server auth code for the signed-in Play Games
105
+ * player, for a backend to exchange for the AUTHORITATIVE player id (Google Play
106
+ * Games Services v2 `GamesSignInClient.requestServerSideAccess`).
107
+ *
108
+ * `serverClientId` is the OAuth 2.0 **web** client id backing the game; the code
109
+ * is redeemed against it server-side. `forceRefresh` (default `false`) requests a
110
+ * fresh code even if one was recently granted.
111
+ *
112
+ * Android only. iOS rejects (unimplemented); the web fallback resolves an empty
113
+ * `authCode`.
114
+ * @since 0.2.0
115
+ */
116
+ requestServerSideAccess(opts: {
117
+ serverClientId: string;
118
+ forceRefresh?: boolean;
119
+ }): Promise<{
120
+ authCode: string;
121
+ }>;
122
+ /**
123
+ * Fetch a GameKit identity-verification signature for the signed-in Game Center
124
+ * player (`GKLocalPlayer.fetchItems(forIdentityVerificationSignature:)`). A
125
+ * backend verifies the returned bundle against Apple's certificate to trust the
126
+ * player id rather than the untrusted client's claim. Rejects when no player is
127
+ * signed in.
128
+ *
129
+ * iOS only. Android rejects (unimplemented); the web fallback resolves an empty
130
+ * bundle.
131
+ * @since 0.2.0
132
+ */
133
+ fetchIdentityVerificationSignature(): Promise<IdentityVerificationSignature>;
134
+ /**
135
+ * Unlock an achievement by its platform id (Play Console achievement id on
136
+ * Android, App Store Connect / Game Center id on iOS).
137
+ * @since 0.1.0
138
+ */
139
+ unlockAchievement(opts: {
140
+ id: string;
141
+ }): Promise<void>;
142
+ /**
143
+ * Increment a partial (incremental) achievement.
144
+ *
145
+ * `steps` is interpreted differently per platform: on Android (PGS) it is a
146
+ * discrete step count toward the achievement's Play Console step total; on
147
+ * iOS (GameKit) it is added to `percentComplete` as percentage points.
148
+ * Compute a platform-appropriate value (e.g. via `Capacitor.getPlatform()`)
149
+ * so progress matches on both stores.
150
+ * @since 0.1.0
151
+ */
152
+ incrementAchievement(opts: {
153
+ id: string;
154
+ steps: number;
155
+ }): Promise<void>;
156
+ /**
157
+ * Show the platform's native achievements UI.
158
+ * @since 0.1.0
159
+ */
160
+ showAchievements(): Promise<void>;
161
+ /**
162
+ * Submit a score to a leaderboard by its platform id.
163
+ * @since 0.1.0
164
+ */
165
+ submitScore(opts: {
166
+ leaderboardId: string;
167
+ score: number;
168
+ }): Promise<void>;
169
+ /**
170
+ * Show the native UI for a single leaderboard.
171
+ * @since 0.1.0
172
+ */
173
+ showLeaderboard(opts: {
174
+ leaderboardId: string;
175
+ }): Promise<void>;
176
+ /**
177
+ * Show the native all-leaderboards UI.
178
+ * @since 0.1.0
179
+ */
180
+ showAllLeaderboards(): Promise<void>;
181
+ /**
182
+ * Load a saved-game snapshot by its stable name. Resolves `{ snapshot: null }`
183
+ * when no snapshot exists for that name.
184
+ * @since 0.1.0
185
+ */
186
+ loadSnapshot(opts: {
187
+ name: string;
188
+ }): Promise<{
189
+ snapshot: Snapshot | null;
190
+ }>;
191
+ /**
192
+ * Create or overwrite a saved-game snapshot. Conflicts are auto-resolved by
193
+ * most-recently-modified (last write wins), with no merge.
194
+ * @since 0.1.0
195
+ */
196
+ saveSnapshot(opts: {
197
+ name: string;
198
+ data: string;
199
+ description?: string;
200
+ }): Promise<void>;
201
+ /**
202
+ * List metadata for all of the player's snapshots.
203
+ * @since 0.1.0
204
+ */
205
+ listSnapshots(): Promise<{
206
+ snapshots: SnapshotMeta[];
207
+ }>;
208
+ /**
209
+ * Delete a saved-game snapshot by its stable name.
210
+ * @since 0.1.0
211
+ */
212
+ deleteSnapshot(opts: {
213
+ name: string;
214
+ }): Promise<void>;
215
+ /**
216
+ * Listen for sign-in state changes: an interactive sign-in completing, or the
217
+ * player signing out of the platform service system-wide.
218
+ * @since 0.1.0
219
+ */
220
+ addListener(event: "signInStateChanged", listener: (e: SignInStateChangedEvent) => void): Promise<PluginListenerHandle>;
221
+ /**
222
+ * Remove all listeners registered through this plugin.
223
+ * @since 0.1.0
224
+ */
225
+ removeAllListeners(): Promise<void>;
226
+ }
227
+ //# sourceMappingURL=definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import type { PlayGamesPlugin } from "./definitions";
2
+ declare const PlayGames: PlayGamesPlugin;
3
+ export * from "./definitions";
4
+ export { PlayGames };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,QAAA,MAAM,SAAS,iBAEb,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { registerPlugin } from "@capacitor/core";
2
+ const PlayGames = registerPlugin("PlayGames", {
3
+ web: () => import("./web").then((m) => new m.PlayGamesWeb()),
4
+ });
5
+ export * from "./definitions";
6
+ export { PlayGames };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,SAAS,GAAG,cAAc,CAAkB,WAAW,EAAE;IAC7D,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;CAC7D,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,CAAC"}