@modbender/capacitor-play-games 0.3.0 → 0.4.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.0] - 2026-09-08
9
+
10
+ ### Removed
11
+
12
+ - iOS support, entirely: the `ios/` sources, `Package.swift`,
13
+ `CapacitorPlayGames.podspec`, and `fetchIdentityVerificationSignature()` (the
14
+ GameKit identity-verification bundle it returned) along with the
15
+ `IdentityVerificationSignature` interface. The Swift was inherited from
16
+ upstream and had never been compiled or run — nothing had been through
17
+ Xcode — so this deletes no working functionality. The package is now
18
+ Android plus a safe web no-op fallback.
19
+
20
+ ### Changed
21
+
22
+ - `package.json` `description` no longer claims iOS support.
23
+
8
24
  ## [0.3.0] - 2026-09-08
9
25
 
10
26
  Forked from `@idleflowgames/capacitor-play-games` 0.2.1. Upstream's GitHub
package/README.md CHANGED
@@ -1,9 +1,8 @@
1
1
  # @modbender/capacitor-play-games
2
2
 
3
- Capacitor 8 plugin for platform games services: **Google Play Games Services
4
- (PGS v2)** on Android and **Apple GameKit / Game Center** on iOS, with a safe
5
- no-op fallback on web. One TypeScript API covers sign-in, achievements,
6
- leaderboards, and saved games across both platforms.
3
+ Capacitor 8 plugin for **Google Play Games Services (PGS v2)** on Android,
4
+ with a safe no-op fallback on web. One TypeScript API covers sign-in,
5
+ achievements, leaderboards, and saved games.
7
6
 
8
7
  ## About this fork
9
8
 
@@ -13,17 +12,22 @@ This is a fork of [`@idleflowgames/capacitor-play-games`](https://www.npmjs.com/
13
12
  Upstream's GitHub repository — `github.com/idleflowgames/capacitor-play-games`,
14
13
  the URL its own `package.json` still points at — returned 404 on 2026-09-08,
15
14
  while the npm package remained published. The source here was recovered from
16
- that published tarball rather than forked through GitHub. The Kotlin, Swift,
17
- Gradle and podspec files ship in the tarball and are vendored byte-for-byte. The
18
- TypeScript layer does **not** ship — the package carries `dist/` only, and its
19
- sourcemaps set `sourcesContent: false` — so `src/` here was reconstructed from
20
- `dist/esm/*.js` plus the emitted `.d.ts`. The declarations retained every doc
21
- comment, which makes that reconstruction faithful rather than a rewrite.
22
-
23
- That claim is checked rather than asserted: building `src/` here reproduces
24
- upstream's published `dist/` exactly all six emitted files, both the `.js` and
25
- the `.d.ts`, are identical to the ones in the 0.2.1 tarball once formatting is
26
- normalised.
15
+ that published tarball rather than forked through GitHub. At recovery, the
16
+ Kotlin, Swift, Gradle and podspec files shipped in the tarball and were
17
+ vendored byte-for-byte. The TypeScript layer did **not** ship — the package
18
+ carried `dist/` only, and its sourcemaps set `sourcesContent: false` — so
19
+ `src/` here was reconstructed from `dist/esm/*.js` plus the emitted `.d.ts`.
20
+ The declarations retained every doc comment, which made that reconstruction
21
+ faithful rather than a rewrite.
22
+
23
+ That claim was checked rather than asserted, at 0.3.0, before any of the
24
+ changes below: building `src/` as reconstructed reproduced upstream's
25
+ published `dist/` exactly — all six emitted files, both the `.js` and the
26
+ `.d.ts`, were identical to the ones in the 0.2.1 tarball once formatting was
27
+ normalised. That is what established the reconstruction was faithful. It is a
28
+ historical checkpoint, not a standing guarantee — the 0.4.0 changes below
29
+ (iOS removed, in particular) mean this tree no longer reproduces upstream's
30
+ `dist/`, by design.
27
31
 
28
32
  ### Changes from upstream 0.2.1
29
33
 
@@ -32,9 +36,12 @@ normalised.
32
36
  `kotlin { compilerOptions { ... } }` block, but never applies the plugin, so
33
37
  Gradle rejects that block with `Could not find method kotlin()` before
34
38
  compiling any source. One line.
35
- - Renamed to the `@modbender` scope, and the SwiftPM product renamed with it —
36
- Capacitor derives that product name from the full scoped package name, so the
37
- two cannot drift apart. See the comment in `Package.swift`.
39
+ - Renamed to the `@modbender` scope.
40
+ - **iOS support removed entirely** (0.4.0): the `ios/` sources, `Package.swift`,
41
+ `CapacitorPlayGames.podspec`, and `fetchIdentityVerificationSignature()`. The
42
+ Swift was inherited from upstream and had never been compiled or run —
43
+ nothing had been through Xcode. The package is now Android plus a safe web
44
+ no-op fallback; see the changelog for the full rationale.
38
45
 
39
46
  Deliberately unchanged: the Android namespace is still
40
47
  `com.idleflowgames.playgames`. Keeping it means this tree diffs cleanly against
@@ -61,8 +68,7 @@ Worth knowing: the module keeps upstream's own buildscript classpath pinning AGP
61
68
  That combination was expected to be a second conflict and is not — it resolves
62
69
  and builds green as-is.
63
70
 
64
- The TypeScript builds and typechecks clean on TypeScript 7.0.2. **iOS remains
65
- untested**; nothing here has been through Xcode.
71
+ The TypeScript builds and typechecks clean on TypeScript 7.0.2.
66
72
 
67
73
  The original MIT copyright is retained in [LICENSE](./LICENSE) alongside this
68
74
  fork's.
@@ -76,21 +82,16 @@ bunx cap sync
76
82
 
77
83
  ## Supported platforms
78
84
 
79
- | Platform | Backing API | Notes |
80
- | -------- | ---------------------------------------------------- | ----------------------------------------------------------- |
81
- | Android | Google Play Games Services v2 (`play-services-games-v2`) | Requires PGS configured in the Google Play Console. |
82
- | iOS | Apple GameKit / Game Center | Requires the Game Center capability + App Store Connect setup. |
83
- | Web | none | Every method resolves to a safe default (signed out, empty). |
85
+ | Platform | Backing API | Notes |
86
+ | -------- | -------------------------------------------------------- | ------------------------------------------------------------ |
87
+ | Android | Google Play Games Services v2 (`play-services-games-v2`) | Requires PGS configured in the Google Play Console. |
88
+ | Web | none | Every method resolves to a safe default (signed out, empty). |
84
89
 
85
90
  ## Platform setup
86
91
 
87
92
  Achievement and leaderboard **ids are yours**: the plugin takes opaque id strings
88
- and passes them straight through to the platform. Create them in the Google Play
89
- Console (Android) and App Store Connect / Game Center (iOS), then pass the
90
- matching id at each call site. The two platforms issue different ids for the same
91
- logical achievement, so keep a per-platform map in your app.
92
-
93
- ### Android
93
+ and passes them straight through to Play Games Services. Create them in the
94
+ Google Play Console, then pass the matching id at each call site.
94
95
 
95
96
  Configure Play Games Services v2 in the Google Play Console, then wire your
96
97
  project id into Android resources and the app manifest (see Google's
@@ -113,17 +114,6 @@ project id into Android resources and the app manifest (see Google's
113
114
  `google-services.json` is not required for PGS v2 on its own; it is only needed
114
115
  if you also wire Firebase.
115
116
 
116
- ### iOS
117
-
118
- Enable the **Game Center** capability on your app target in Xcode and create the
119
- app's achievements / leaderboards in App Store Connect. The system presents the
120
- Game Center sign-in UI.
121
-
122
- > If your app shows an App Tracking Transparency (ATT) prompt, request it
123
- > **before** calling `initialize()`. iOS suppresses an ATT prompt shown while
124
- > Game Center's "Welcome back" banner is on screen, and `initialize()` is what
125
- > can trigger that banner.
126
-
127
117
  ## Usage
128
118
 
129
119
  ```ts
@@ -137,8 +127,8 @@ if (!signedIn) {
137
127
  await PlayGames.signIn({ silent: false });
138
128
  }
139
129
 
140
- await PlayGames.unlockAchievement({ id: platformAchievementId });
141
- await PlayGames.submitScore({ leaderboardId: platformLeaderboardId, score: 1234 });
130
+ await PlayGames.unlockAchievement({ id: achievementId });
131
+ await PlayGames.submitScore({ leaderboardId, score: 1234 });
142
132
 
143
133
  // Cross-device saves:
144
134
  await PlayGames.saveSnapshot({ name: "main", data: JSON.stringify(state) });
@@ -162,7 +152,6 @@ On web every method resolves to a safe default, so gate feature usage behind
162
152
  * [`isSignedIn()`](#issignedin)
163
153
  * [`getPlayer()`](#getplayer)
164
154
  * [`requestServerSideAccess(...)`](#requestserversideaccess)
165
- * [`fetchIdentityVerificationSignature()`](#fetchidentityverificationsignature)
166
155
  * [`unlockAchievement(...)`](#unlockachievement)
167
156
  * [`incrementAchievement(...)`](#incrementachievement)
168
157
  * [`showAchievements()`](#showachievements)
@@ -189,11 +178,9 @@ On web every method resolves to a safe default, so gate feature usage behind
189
178
  initialize() => Promise<void>
190
179
  ```
191
180
 
192
- Initialize the native games SDK. Idempotent.
193
-
194
- On Android this triggers `PlayGamesSdk.initialize`; on iOS it installs the
195
- GameKit authentication handler. Call once, after any App Tracking
196
- Transparency prompt has resolved, before the other methods.
181
+ No-op. `PlayGamesSdk.initialize` runs automatically when the plugin
182
+ loads, driven by the Capacitor bridge — this call exists only to keep
183
+ the API symmetric with the web fallback.
197
184
 
198
185
  **Since:** 0.1.0
199
186
 
@@ -206,7 +193,7 @@ Transparency prompt has resolved, before the other methods.
206
193
  signIn(opts?: { silent?: boolean | undefined; } | undefined) => Promise<SignInResult>
207
194
  ```
208
195
 
209
- Sign in to the platform games service.
196
+ Sign in to Google Play Games.
210
197
 
211
198
  `silent` (default `true`) attempts auto sign-in with no UI; on most devices
212
199
  this succeeds if the player has previously authenticated this game. Pass
@@ -247,8 +234,8 @@ getPlayer() => Promise<PlayerInfo>
247
234
 
248
235
  Get the signed-in player's profile.
249
236
 
250
- On Android and iOS this rejects when no player is signed in. On web (the
251
- no-op fallback) it resolves an empty profile (`playerId: ""`).
237
+ Rejects when no player is signed in. On web (the no-op fallback) it
238
+ resolves an empty profile (`playerId: ""`).
252
239
 
253
240
  **Returns:** <code>Promise&lt;<a href="#playerinfo">PlayerInfo</a>&gt;</code>
254
241
 
@@ -271,8 +258,7 @@ Games Services v2 `GamesSignInClient.requestServerSideAccess`).
271
258
  is redeemed against it server-side. `forceRefresh` (default `false`) requests a
272
259
  fresh code even if one was recently granted.
273
260
 
274
- Android only. iOS rejects (unimplemented); the web fallback resolves an empty
275
- `authCode`.
261
+ The web fallback resolves an empty `authCode`.
276
262
 
277
263
  | Param | Type |
278
264
  | ---------- | ---------------------------------------------------------------- |
@@ -285,36 +271,13 @@ Android only. iOS rejects (unimplemented); the web fallback resolves an empty
285
271
  --------------------
286
272
 
287
273
 
288
- ### fetchIdentityVerificationSignature()
289
-
290
- ```typescript
291
- fetchIdentityVerificationSignature() => Promise<IdentityVerificationSignature>
292
- ```
293
-
294
- Fetch a GameKit identity-verification signature for the signed-in Game Center
295
- player (`GKLocalPlayer.fetchItems(forIdentityVerificationSignature:)`). A
296
- backend verifies the returned bundle against Apple's certificate to trust the
297
- player id rather than the untrusted client's claim. Rejects when no player is
298
- signed in.
299
-
300
- iOS only. Android rejects (unimplemented); the web fallback resolves an empty
301
- bundle.
302
-
303
- **Returns:** <code>Promise&lt;<a href="#identityverificationsignature">IdentityVerificationSignature</a>&gt;</code>
304
-
305
- **Since:** 0.2.0
306
-
307
- --------------------
308
-
309
-
310
274
  ### unlockAchievement(...)
311
275
 
312
276
  ```typescript
313
277
  unlockAchievement(opts: { id: string; }) => Promise<void>
314
278
  ```
315
279
 
316
- Unlock an achievement by its platform id (Play Console achievement id on
317
- Android, App Store Connect / Game Center id on iOS).
280
+ Unlock an achievement by its Play Console achievement id.
318
281
 
319
282
  | Param | Type |
320
283
  | ---------- | ---------------------------- |
@@ -333,11 +296,8 @@ incrementAchievement(opts: { id: string; steps: number; }) => Promise<void>
333
296
 
334
297
  Increment a partial (incremental) achievement.
335
298
 
336
- `steps` is interpreted differently per platform: on Android (PGS) it is a
337
- discrete step count toward the achievement's Play Console step total; on
338
- iOS (GameKit) it is added to `percentComplete` as percentage points.
339
- Compute a platform-appropriate value (e.g. via `Capacitor.getPlatform()`)
340
- so progress matches on both stores.
299
+ `steps` is a discrete step count toward the achievement's Play Console
300
+ step total, and must be greater than 0 the call rejects otherwise.
341
301
 
342
302
  | Param | Type |
343
303
  | ---------- | ------------------------------------------- |
@@ -354,7 +314,7 @@ so progress matches on both stores.
354
314
  showAchievements() => Promise<void>
355
315
  ```
356
316
 
357
- Show the platform's native achievements UI.
317
+ Show the native Google Play Games achievements UI.
358
318
 
359
319
  **Since:** 0.1.0
360
320
 
@@ -367,7 +327,7 @@ Show the platform's native achievements UI.
367
327
  submitScore(opts: { leaderboardId: string; score: number; }) => Promise<void>
368
328
  ```
369
329
 
370
- Submit a score to a leaderboard by its platform id.
330
+ Submit a score to a leaderboard by its Play Console leaderboard id.
371
331
 
372
332
  | Param | Type |
373
333
  | ---------- | ------------------------------------------------------ |
@@ -485,7 +445,7 @@ addListener(event: "signInStateChanged", listener: (e: SignInStateChangedEvent)
485
445
  ```
486
446
 
487
447
  Listen for sign-in state changes: an interactive sign-in completing, or the
488
- player signing out of the platform service system-wide.
448
+ player signing out of Google Play Games system-wide.
489
449
 
490
450
  | Param | Type |
491
451
  | -------------- | --------------------------------------------------------------------- |
@@ -531,28 +491,9 @@ A signed-in player's public profile.
531
491
 
532
492
  | Prop | Type | Description |
533
493
  | ----------------- | ------------------- | ----------------------------------------------------------------------------- |
534
- | **`playerId`** | <code>string</code> | Stable, platform-assigned player id (PGS player id / GameKit `gamePlayerID`). |
535
- | **`displayName`** | <code>string</code> | Display name as shown in Google Play Games / Game Center. |
536
- | **`avatarUrl`** | <code>string</code> | URL of the player's avatar image, when the platform exposes one. |
537
-
538
-
539
- #### IdentityVerificationSignature
540
-
541
- A GameKit identity-verification bundle
542
- (`GKLocalPlayer.fetchItems(forIdentityVerificationSignature:)`). A third-party
543
- server verifies `signature` against the certificate at `publicKeyUrl` to trust
544
- the Game Center `playerId` without relaying it through the untrusted client.
545
-
546
- | Prop | Type | Description |
547
- | ------------------ | ------------------- | ----------------------------------------------------------------------------- |
548
- | **`publicKeyUrl`** | <code>string</code> | URL of Apple's public-key certificate used to verify `signature`. |
549
- | **`signature`** | <code>string</code> | Base64-encoded signature over the verification payload. |
550
- | **`salt`** | <code>string</code> | Base64-encoded random salt Apple mixed into the signed payload. |
551
- | **`timestamp`** | <code>number</code> | Signature creation time, in epoch milliseconds (check freshness server-side). |
552
- | **`playerId`** | <code>string</code> | The player id the signature attests (GameKit `gamePlayerID`). |
553
- | **`bundleId`** | <code>string</code> | The app's bundle id, part of the signed payload. |
554
- | **`teamPlayerId`** | <code>string</code> | GameKit `teamPlayerID` (stable across the team's games), when available. |
555
- | **`gamePlayerId`** | <code>string</code> | GameKit `gamePlayerID` (stable per game), when available. |
494
+ | **`playerId`** | <code>string</code> | Stable, platform-assigned Play Games player id. |
495
+ | **`displayName`** | <code>string</code> | Display name as shown in Google Play Games. |
496
+ | **`avatarUrl`** | <code>string</code> | URL of the player's avatar image, when the platform exposes one. |
556
497
 
557
498
 
558
499
  #### Snapshot
@@ -604,7 +545,7 @@ bun run verify # typecheck + build
604
545
  ```
605
546
 
606
547
  The TypeScript bridge is built to `dist/` (ESM + CJS + types). The native sources
607
- under `android/` and `ios/` ship in the package and are wired up by `npx cap sync`.
548
+ under `android/` ship in the package and are wired up by `npx cap sync`.
608
549
 
609
550
  ## License
610
551
 
@@ -1,9 +1,9 @@
1
1
  import type { PluginListenerHandle } from "@capacitor/core";
2
2
  /** A signed-in player's public profile. */
3
3
  export interface PlayerInfo {
4
- /** Stable, platform-assigned player id (PGS player id / GameKit `gamePlayerID`). */
4
+ /** Stable, platform-assigned Play Games player id. */
5
5
  playerId: string;
6
- /** Display name as shown in Google Play Games / Game Center. */
6
+ /** Display name as shown in Google Play Games. */
7
7
  displayName: string;
8
8
  /** URL of the player's avatar image, when the platform exposes one. */
9
9
  avatarUrl?: string;
@@ -35,45 +35,19 @@ export interface SnapshotMeta {
35
35
  /** Last-modified time, in epoch milliseconds. */
36
36
  modifiedAt: number;
37
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
38
  /** Payload of the `signInStateChanged` event. */
63
39
  export type SignInStateChangedEvent = SignInResult;
64
40
  export interface PlayGamesPlugin {
65
41
  /**
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.
42
+ * No-op. `PlayGamesSdk.initialize` runs automatically when the plugin
43
+ * loads, driven by the Capacitor bridge — this call exists only to keep
44
+ * the API symmetric with the web fallback.
71
45
  *
72
46
  * @since 0.1.0
73
47
  */
74
48
  initialize(): Promise<void>;
75
49
  /**
76
- * Sign in to the platform games service.
50
+ * Sign in to Google Play Games.
77
51
  *
78
52
  * `silent` (default `true`) attempts auto sign-in with no UI; on most devices
79
53
  * this succeeds if the player has previously authenticated this game. Pass
@@ -95,8 +69,8 @@ export interface PlayGamesPlugin {
95
69
  /**
96
70
  * Get the signed-in player's profile.
97
71
  *
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: ""`).
72
+ * Rejects when no player is signed in. On web (the no-op fallback) it
73
+ * resolves an empty profile (`playerId: ""`).
100
74
  * @since 0.1.0
101
75
  */
102
76
  getPlayer(): Promise<PlayerInfo>;
@@ -109,8 +83,7 @@ export interface PlayGamesPlugin {
109
83
  * is redeemed against it server-side. `forceRefresh` (default `false`) requests a
110
84
  * fresh code even if one was recently granted.
111
85
  *
112
- * Android only. iOS rejects (unimplemented); the web fallback resolves an empty
113
- * `authCode`.
86
+ * The web fallback resolves an empty `authCode`.
114
87
  * @since 0.2.0
115
88
  */
116
89
  requestServerSideAccess(opts: {
@@ -120,20 +93,7 @@ export interface PlayGamesPlugin {
120
93
  authCode: string;
121
94
  }>;
122
95
  /**
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).
96
+ * Unlock an achievement by its Play Console achievement id.
137
97
  * @since 0.1.0
138
98
  */
139
99
  unlockAchievement(opts: {
@@ -142,11 +102,8 @@ export interface PlayGamesPlugin {
142
102
  /**
143
103
  * Increment a partial (incremental) achievement.
144
104
  *
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.
105
+ * `steps` is a discrete step count toward the achievement's Play Console
106
+ * step total, and must be greater than 0 the call rejects otherwise.
150
107
  * @since 0.1.0
151
108
  */
152
109
  incrementAchievement(opts: {
@@ -154,12 +111,12 @@ export interface PlayGamesPlugin {
154
111
  steps: number;
155
112
  }): Promise<void>;
156
113
  /**
157
- * Show the platform's native achievements UI.
114
+ * Show the native Google Play Games achievements UI.
158
115
  * @since 0.1.0
159
116
  */
160
117
  showAchievements(): Promise<void>;
161
118
  /**
162
- * Submit a score to a leaderboard by its platform id.
119
+ * Submit a score to a leaderboard by its Play Console leaderboard id.
163
120
  * @since 0.1.0
164
121
  */
165
122
  submitScore(opts: {
@@ -214,7 +171,7 @@ export interface PlayGamesPlugin {
214
171
  }): Promise<void>;
215
172
  /**
216
173
  * Listen for sign-in state changes: an interactive sign-in completing, or the
217
- * player signing out of the platform service system-wide.
174
+ * player signing out of Google Play Games system-wide.
218
175
  * @since 0.1.0
219
176
  */
220
177
  addListener(event: "signInStateChanged", listener: (e: SignInStateChangedEvent) => void): Promise<PluginListenerHandle>;
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"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"}
package/dist/esm/web.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WebPlugin } from "@capacitor/core";
2
- import type { IdentityVerificationSignature, PlayerInfo, PlayGamesPlugin, SignInResult, Snapshot, SnapshotMeta } from "./definitions";
2
+ import type { PlayerInfo, PlayGamesPlugin, SignInResult, Snapshot, SnapshotMeta } from "./definitions";
3
3
  /**
4
4
  * Web / non-native fallback: every method resolves to a safe default (signed
5
5
  * out, empty). Gate feature usage behind `isSignedIn()`, which is `false` here.
@@ -14,7 +14,6 @@ export declare class PlayGamesWeb extends WebPlugin implements PlayGamesPlugin {
14
14
  requestServerSideAccess(): Promise<{
15
15
  authCode: string;
16
16
  }>;
17
- fetchIdentityVerificationSignature(): Promise<IdentityVerificationSignature>;
18
17
  unlockAchievement(): Promise<void>;
19
18
  incrementAchievement(): Promise<void>;
20
19
  showAchievements(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,6BAA6B,EAC7B,UAAU,EACV,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACb,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,qBAAa,YAAa,SAAQ,SAAU,YAAW,eAAe;IAC9D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAE9B,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC,CAEpC;IAEK,UAAU,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAEjD;IAEK,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CAErC;IAEK,uBAAuB,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAE7D;IAEK,kCAAkC,IAAI,OAAO,CAAC,6BAA6B,CAAC,CASjF;IAEK,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAErC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAExC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAEpC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAE/B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAEnC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAEvC,YAAY,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,CAAC,CAE3D;IAEK,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAEhC,aAAa,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC,CAE5D;IAEK,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;CACzC"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACb,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,qBAAa,YAAa,SAAQ,SAAU,YAAW,eAAe;IAC9D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAE9B,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC,CAEpC;IAEK,UAAU,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAEjD;IAEK,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CAErC;IAEK,uBAAuB,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAE7D;IAEK,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAErC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAExC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAEpC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAE/B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAEnC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAEvC,YAAY,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,CAAC,CAE3D;IAEK,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAEhC,aAAa,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC,CAE5D;IAEK,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;CACzC"}
package/dist/esm/web.js CHANGED
@@ -17,16 +17,6 @@ export class PlayGamesWeb extends WebPlugin {
17
17
  async requestServerSideAccess() {
18
18
  return { authCode: "" };
19
19
  }
20
- async fetchIdentityVerificationSignature() {
21
- return {
22
- publicKeyUrl: "",
23
- signature: "",
24
- salt: "",
25
- timestamp: 0,
26
- playerId: "",
27
- bundleId: "",
28
- };
29
- }
30
20
  async unlockAchievement() { }
31
21
  async incrementAchievement() { }
32
22
  async showAchievements() { }
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAW5C;;;GAGG;AACH,MAAM,OAAO,YAAa,SAAQ,SAAS;IACzC,KAAK,CAAC,UAAU,KAAmB,CAAC;IAEpC,KAAK,CAAC,MAAM;QACV,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,uBAAuB;QAC3B,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,kCAAkC;QACtC,OAAO;YACL,YAAY,EAAE,EAAE;YAChB,SAAS,EAAE,EAAE;YACb,IAAI,EAAE,EAAE;YACR,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE,EAAE;SACb,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iBAAiB,KAAmB,CAAC;IAE3C,KAAK,CAAC,oBAAoB,KAAmB,CAAC;IAE9C,KAAK,CAAC,gBAAgB,KAAmB,CAAC;IAE1C,KAAK,CAAC,WAAW,KAAmB,CAAC;IAErC,KAAK,CAAC,eAAe,KAAmB,CAAC;IAEzC,KAAK,CAAC,mBAAmB,KAAmB,CAAC;IAE7C,KAAK,CAAC,YAAY;QAChB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,YAAY,KAAmB,CAAC;IAEtC,KAAK,CAAC,aAAa;QACjB,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,cAAc,KAAmB,CAAC;CACzC"}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAU5C;;;GAGG;AACH,MAAM,OAAO,YAAa,SAAQ,SAAS;IACzC,KAAK,CAAC,UAAU,KAAmB,CAAC;IAEpC,KAAK,CAAC,MAAM;QACV,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,uBAAuB;QAC3B,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,iBAAiB,KAAmB,CAAC;IAE3C,KAAK,CAAC,oBAAoB,KAAmB,CAAC;IAE9C,KAAK,CAAC,gBAAgB,KAAmB,CAAC;IAE1C,KAAK,CAAC,WAAW,KAAmB,CAAC;IAErC,KAAK,CAAC,eAAe,KAAmB,CAAC;IAEzC,KAAK,CAAC,mBAAmB,KAAmB,CAAC;IAE7C,KAAK,CAAC,YAAY;QAChB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,YAAY,KAAmB,CAAC;IAEtC,KAAK,CAAC,aAAa;QACjB,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,cAAc,KAAmB,CAAC;CACzC"}
@@ -24,16 +24,6 @@ class PlayGamesWeb extends core.WebPlugin {
24
24
  async requestServerSideAccess() {
25
25
  return { authCode: "" };
26
26
  }
27
- async fetchIdentityVerificationSignature() {
28
- return {
29
- publicKeyUrl: "",
30
- signature: "",
31
- salt: "",
32
- timestamp: 0,
33
- playerId: "",
34
- bundleId: "",
35
- };
36
- }
37
27
  async unlockAchievement() { }
38
28
  async incrementAchievement() { }
39
29
  async showAchievements() { }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nconst PlayGames = registerPlugin(\"PlayGames\", {\n web: () => import(\"./web\").then((m) => new m.PlayGamesWeb()),\n});\nexport * from \"./definitions\";\nexport { PlayGames };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web / non-native fallback: every method resolves to a safe default (signed\n * out, empty). Gate feature usage behind `isSignedIn()`, which is `false` here.\n */\nexport class PlayGamesWeb extends WebPlugin {\n async initialize() { }\n async signIn() {\n return { signedIn: false };\n }\n async isSignedIn() {\n return { signedIn: false };\n }\n async getPlayer() {\n return { playerId: \"\", displayName: \"\" };\n }\n async requestServerSideAccess() {\n return { authCode: \"\" };\n }\n async fetchIdentityVerificationSignature() {\n return {\n publicKeyUrl: \"\",\n signature: \"\",\n salt: \"\",\n timestamp: 0,\n playerId: \"\",\n bundleId: \"\",\n };\n }\n async unlockAchievement() { }\n async incrementAchievement() { }\n async showAchievements() { }\n async submitScore() { }\n async showLeaderboard() { }\n async showAllLeaderboards() { }\n async loadSnapshot() {\n return { snapshot: null };\n }\n async saveSnapshot() { }\n async listSnapshots() {\n return { snapshots: [] };\n }\n async deleteSnapshot() { }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,SAAS,GAAGA,mBAAc,CAAC,WAAW,EAAE;AAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;AAChE,CAAC;;ACFD;AACA;AACA;AACA;AACO,MAAM,YAAY,SAASC,cAAS,CAAC;AAC5C,IAAI,MAAM,UAAU,GAAG,EAAE;AACzB,IAAI,MAAM,MAAM,GAAG;AACnB,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;AAClC,IAAI;AACJ,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;AAClC,IAAI;AACJ,IAAI,MAAM,SAAS,GAAG;AACtB,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;AAChD,IAAI;AACJ,IAAI,MAAM,uBAAuB,GAAG;AACpC,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;AAC/B,IAAI;AACJ,IAAI,MAAM,kCAAkC,GAAG;AAC/C,QAAQ,OAAO;AACf,YAAY,YAAY,EAAE,EAAE;AAC5B,YAAY,SAAS,EAAE,EAAE;AACzB,YAAY,IAAI,EAAE,EAAE;AACpB,YAAY,SAAS,EAAE,CAAC;AACxB,YAAY,QAAQ,EAAE,EAAE;AACxB,YAAY,QAAQ,EAAE,EAAE;AACxB,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,iBAAiB,GAAG,EAAE;AAChC,IAAI,MAAM,oBAAoB,GAAG,EAAE;AACnC,IAAI,MAAM,gBAAgB,GAAG,EAAE;AAC/B,IAAI,MAAM,WAAW,GAAG,EAAE;AAC1B,IAAI,MAAM,eAAe,GAAG,EAAE;AAC9B,IAAI,MAAM,mBAAmB,GAAG,EAAE;AAClC,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE;AACjC,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG,EAAE;AAC3B,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;AAChC,IAAI;AACJ,IAAI,MAAM,cAAc,GAAG,EAAE;AAC7B;;;;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nconst PlayGames = registerPlugin(\"PlayGames\", {\n web: () => import(\"./web\").then((m) => new m.PlayGamesWeb()),\n});\nexport * from \"./definitions\";\nexport { PlayGames };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web / non-native fallback: every method resolves to a safe default (signed\n * out, empty). Gate feature usage behind `isSignedIn()`, which is `false` here.\n */\nexport class PlayGamesWeb extends WebPlugin {\n async initialize() { }\n async signIn() {\n return { signedIn: false };\n }\n async isSignedIn() {\n return { signedIn: false };\n }\n async getPlayer() {\n return { playerId: \"\", displayName: \"\" };\n }\n async requestServerSideAccess() {\n return { authCode: \"\" };\n }\n async unlockAchievement() { }\n async incrementAchievement() { }\n async showAchievements() { }\n async submitScore() { }\n async showLeaderboard() { }\n async showAllLeaderboards() { }\n async loadSnapshot() {\n return { snapshot: null };\n }\n async saveSnapshot() { }\n async listSnapshots() {\n return { snapshots: [] };\n }\n async deleteSnapshot() { }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,SAAS,GAAGA,mBAAc,CAAC,WAAW,EAAE;AAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;AAChE,CAAC;;ACFD;AACA;AACA;AACA;AACO,MAAM,YAAY,SAASC,cAAS,CAAC;AAC5C,IAAI,MAAM,UAAU,GAAG,EAAE;AACzB,IAAI,MAAM,MAAM,GAAG;AACnB,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;AAClC,IAAI;AACJ,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;AAClC,IAAI;AACJ,IAAI,MAAM,SAAS,GAAG;AACtB,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;AAChD,IAAI;AACJ,IAAI,MAAM,uBAAuB,GAAG;AACpC,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;AAC/B,IAAI;AACJ,IAAI,MAAM,iBAAiB,GAAG,EAAE;AAChC,IAAI,MAAM,oBAAoB,GAAG,EAAE;AACnC,IAAI,MAAM,gBAAgB,GAAG,EAAE;AAC/B,IAAI,MAAM,WAAW,GAAG,EAAE;AAC1B,IAAI,MAAM,eAAe,GAAG,EAAE;AAC9B,IAAI,MAAM,mBAAmB,GAAG,EAAE;AAClC,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE;AACjC,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG,EAAE;AAC3B,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;AAChC,IAAI;AACJ,IAAI,MAAM,cAAc,GAAG,EAAE;AAC7B;;;;;;;"}
package/dist/plugin.js CHANGED
@@ -23,16 +23,6 @@ var capacitorPlayGames = (function (exports, core) {
23
23
  async requestServerSideAccess() {
24
24
  return { authCode: "" };
25
25
  }
26
- async fetchIdentityVerificationSignature() {
27
- return {
28
- publicKeyUrl: "",
29
- signature: "",
30
- salt: "",
31
- timestamp: 0,
32
- playerId: "",
33
- bundleId: "",
34
- };
35
- }
36
26
  async unlockAchievement() { }
37
27
  async incrementAchievement() { }
38
28
  async showAchievements() { }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nconst PlayGames = registerPlugin(\"PlayGames\", {\n web: () => import(\"./web\").then((m) => new m.PlayGamesWeb()),\n});\nexport * from \"./definitions\";\nexport { PlayGames };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web / non-native fallback: every method resolves to a safe default (signed\n * out, empty). Gate feature usage behind `isSignedIn()`, which is `false` here.\n */\nexport class PlayGamesWeb extends WebPlugin {\n async initialize() { }\n async signIn() {\n return { signedIn: false };\n }\n async isSignedIn() {\n return { signedIn: false };\n }\n async getPlayer() {\n return { playerId: \"\", displayName: \"\" };\n }\n async requestServerSideAccess() {\n return { authCode: \"\" };\n }\n async fetchIdentityVerificationSignature() {\n return {\n publicKeyUrl: \"\",\n signature: \"\",\n salt: \"\",\n timestamp: 0,\n playerId: \"\",\n bundleId: \"\",\n };\n }\n async unlockAchievement() { }\n async incrementAchievement() { }\n async showAchievements() { }\n async submitScore() { }\n async showLeaderboard() { }\n async showAllLeaderboards() { }\n async loadSnapshot() {\n return { snapshot: null };\n }\n async saveSnapshot() { }\n async listSnapshots() {\n return { snapshots: [] };\n }\n async deleteSnapshot() { }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,SAAS,GAAGA,mBAAc,CAAC,WAAW,EAAE;IAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;IAChE,CAAC;;ICFD;IACA;IACA;IACA;IACO,MAAM,YAAY,SAASC,cAAS,CAAC;IAC5C,IAAI,MAAM,UAAU,GAAG,EAAE;IACzB,IAAI,MAAM,MAAM,GAAG;IACnB,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;IAClC,IAAI;IACJ,IAAI,MAAM,UAAU,GAAG;IACvB,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;IAClC,IAAI;IACJ,IAAI,MAAM,SAAS,GAAG;IACtB,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;IAChD,IAAI;IACJ,IAAI,MAAM,uBAAuB,GAAG;IACpC,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC/B,IAAI;IACJ,IAAI,MAAM,kCAAkC,GAAG;IAC/C,QAAQ,OAAO;IACf,YAAY,YAAY,EAAE,EAAE;IAC5B,YAAY,SAAS,EAAE,EAAE;IACzB,YAAY,IAAI,EAAE,EAAE;IACpB,YAAY,SAAS,EAAE,CAAC;IACxB,YAAY,QAAQ,EAAE,EAAE;IACxB,YAAY,QAAQ,EAAE,EAAE;IACxB,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,iBAAiB,GAAG,EAAE;IAChC,IAAI,MAAM,oBAAoB,GAAG,EAAE;IACnC,IAAI,MAAM,gBAAgB,GAAG,EAAE;IAC/B,IAAI,MAAM,WAAW,GAAG,EAAE;IAC1B,IAAI,MAAM,eAAe,GAAG,EAAE;IAC9B,IAAI,MAAM,mBAAmB,GAAG,EAAE;IAClC,IAAI,MAAM,YAAY,GAAG;IACzB,QAAQ,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjC,IAAI;IACJ,IAAI,MAAM,YAAY,GAAG,EAAE;IAC3B,IAAI,MAAM,aAAa,GAAG;IAC1B,QAAQ,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;IAChC,IAAI;IACJ,IAAI,MAAM,cAAc,GAAG,EAAE;IAC7B;;;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nconst PlayGames = registerPlugin(\"PlayGames\", {\n web: () => import(\"./web\").then((m) => new m.PlayGamesWeb()),\n});\nexport * from \"./definitions\";\nexport { PlayGames };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web / non-native fallback: every method resolves to a safe default (signed\n * out, empty). Gate feature usage behind `isSignedIn()`, which is `false` here.\n */\nexport class PlayGamesWeb extends WebPlugin {\n async initialize() { }\n async signIn() {\n return { signedIn: false };\n }\n async isSignedIn() {\n return { signedIn: false };\n }\n async getPlayer() {\n return { playerId: \"\", displayName: \"\" };\n }\n async requestServerSideAccess() {\n return { authCode: \"\" };\n }\n async unlockAchievement() { }\n async incrementAchievement() { }\n async showAchievements() { }\n async submitScore() { }\n async showLeaderboard() { }\n async showAllLeaderboards() { }\n async loadSnapshot() {\n return { snapshot: null };\n }\n async saveSnapshot() { }\n async listSnapshots() {\n return { snapshots: [] };\n }\n async deleteSnapshot() { }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,SAAS,GAAGA,mBAAc,CAAC,WAAW,EAAE;IAC9C,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;IAChE,CAAC;;ICFD;IACA;IACA;IACA;IACO,MAAM,YAAY,SAASC,cAAS,CAAC;IAC5C,IAAI,MAAM,UAAU,GAAG,EAAE;IACzB,IAAI,MAAM,MAAM,GAAG;IACnB,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;IAClC,IAAI;IACJ,IAAI,MAAM,UAAU,GAAG;IACvB,QAAQ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;IAClC,IAAI;IACJ,IAAI,MAAM,SAAS,GAAG;IACtB,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;IAChD,IAAI;IACJ,IAAI,MAAM,uBAAuB,GAAG;IACpC,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC/B,IAAI;IACJ,IAAI,MAAM,iBAAiB,GAAG,EAAE;IAChC,IAAI,MAAM,oBAAoB,GAAG,EAAE;IACnC,IAAI,MAAM,gBAAgB,GAAG,EAAE;IAC/B,IAAI,MAAM,WAAW,GAAG,EAAE;IAC1B,IAAI,MAAM,eAAe,GAAG,EAAE;IAC9B,IAAI,MAAM,mBAAmB,GAAG,EAAE;IAClC,IAAI,MAAM,YAAY,GAAG;IACzB,QAAQ,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjC,IAAI;IACJ,IAAI,MAAM,YAAY,GAAG,EAAE;IAC3B,IAAI,MAAM,aAAa,GAAG;IAC1B,QAAQ,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;IAChC,IAAI;IACJ,IAAI,MAAM,cAAc,GAAG,EAAE;IAC7B;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@modbender/capacitor-play-games",
3
- "version": "0.3.0",
4
- "description": "Capacitor 8 plugin for Google Play Games Services (Android) and Apple GameKit (iOS): sign-in, achievements, leaderboards, and saved games.",
3
+ "version": "0.4.0",
4
+ "description": "Capacitor 8 plugin for Google Play Games Services (Android): sign-in, achievements, leaderboards, and saved games, with a safe no-op web fallback.",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.cjs.js",
7
7
  "module": "dist/esm/index.js",
@@ -13,9 +13,6 @@
13
13
  "android/consumer-rules.pro",
14
14
  "android/proguard-rules.pro",
15
15
  "dist/",
16
- "ios/Plugin/",
17
- "CapacitorPlayGames.podspec",
18
- "Package.swift",
19
16
  "CHANGELOG.md"
20
17
  ],
21
18
  "author": "modbender",
@@ -32,21 +29,15 @@
32
29
  "capacitor",
33
30
  "plugin",
34
31
  "native",
35
- "ios",
36
32
  "android",
37
33
  "play-games",
38
34
  "google-play-games",
39
35
  "pgs",
40
- "gamekit",
41
- "game-center",
42
36
  "achievements",
43
37
  "leaderboards",
44
38
  "saved-games"
45
39
  ],
46
40
  "capacitor": {
47
- "ios": {
48
- "src": "ios"
49
- },
50
41
  "android": {
51
42
  "src": "android"
52
43
  }
@@ -73,8 +64,9 @@
73
64
  "clean": "rimraf dist",
74
65
  "build": "rimraf dist && tsc && rollup -c rollup.config.mjs",
75
66
  "docgen": "docgen --api PlayGamesPlugin --output-readme README.md",
67
+ "check-docs": "bun scripts/check-docs.ts",
76
68
  "typecheck": "tsc --noEmit",
77
- "verify": "bun run typecheck && bun run build",
69
+ "verify": "bun run typecheck && bun run check-docs && bun run build",
78
70
  "prepublishOnly": "bun run verify"
79
71
  }
80
72
  }
@@ -1,17 +0,0 @@
1
- require 'json'
2
-
3
- package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
-
5
- Pod::Spec.new do |s|
6
- s.name = 'CapacitorPlayGames'
7
- s.version = package['version']
8
- s.summary = package['description']
9
- s.license = package['license']
10
- s.homepage = 'https://github.com/modbender/capacitor-play-games'
11
- s.author = 'modbender'
12
- s.source = { :git => 'https://github.com/modbender/capacitor-play-games.git', :tag => s.version.to_s }
13
- s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
14
- s.ios.deployment_target = '14.0'
15
- s.dependency 'Capacitor'
16
- s.swift_version = '5.1'
17
- end
package/Package.swift DELETED
@@ -1,36 +0,0 @@
1
- // swift-tools-version: 5.9
2
- import PackageDescription
3
-
4
- // Package/product/target names carry the npm scope ("Modbender…") because
5
- // Capacitor's `cap sync ios` derives the SwiftPM product name from the FULL
6
- // scoped package name (@modbender/capacitor-play-games →
7
- // ModbenderCapacitorPlayGames, PascalCased scope+name, same as
8
- // @capacitor-community/admob → CapacitorCommunityAdmob). The consuming app's
9
- // generated Package.swift references that derived name, so the product here must
10
- // match it exactly or `xcodebuild -resolvePackageDependencies` fails with
11
- // "product 'ModbenderCapacitorPlayGames' not found". The Swift module is
12
- // renamed with it; nothing imports it by name and Capacitor registers the
13
- // plugin via the Objective-C runtime, so the rename is source-compatible.
14
- let package = Package(
15
- name: "ModbenderCapacitorPlayGames",
16
- platforms: [.iOS(.v14)],
17
- products: [
18
- .library(
19
- name: "ModbenderCapacitorPlayGames",
20
- targets: ["ModbenderCapacitorPlayGames"]
21
- )
22
- ],
23
- dependencies: [
24
- .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.4.2")
25
- ],
26
- targets: [
27
- .target(
28
- name: "ModbenderCapacitorPlayGames",
29
- dependencies: [
30
- .product(name: "Capacitor", package: "capacitor-swift-pm"),
31
- .product(name: "Cordova", package: "capacitor-swift-pm")
32
- ],
33
- path: "ios/Plugin"
34
- )
35
- ]
36
- )
@@ -1,73 +0,0 @@
1
- import Capacitor
2
- import GameKit
3
- import UIKit
4
-
5
- /// GameKit has no increment API (report overwrites percentComplete), so
6
- /// increment() loads current progress, adds the steps (percentage points),
7
- /// then reports the new total.
8
- internal class AchievementsModule: PgsModule, GKGameCenterControllerDelegate {
9
- func unlock(_ call: CAPPluginCall) {
10
- guard let id = call.getString("id") else {
11
- call.reject("missing id"); return
12
- }
13
- let achievement = GKAchievement(identifier: id)
14
- achievement.percentComplete = 100
15
- achievement.showsCompletionBanner = true
16
- GKAchievement.report([achievement]) { error in
17
- if let error = error {
18
- call.reject(error.localizedDescription, nil, error)
19
- } else {
20
- call.resolve()
21
- }
22
- }
23
- }
24
-
25
- func increment(_ call: CAPPluginCall) {
26
- guard let id = call.getString("id") else {
27
- call.reject("missing id"); return
28
- }
29
- let steps = call.getDouble("steps") ?? 0
30
-
31
- GKAchievement.loadAchievements { existing, error in
32
- if let error = error {
33
- call.reject(error.localizedDescription, nil, error)
34
- return
35
- }
36
- let current = existing?.first(where: { $0.identifier == id })
37
- let achievement = current ?? GKAchievement(identifier: id)
38
- let next = min(100, (achievement.percentComplete) + steps)
39
- achievement.percentComplete = next
40
- achievement.showsCompletionBanner = next >= 100
41
- GKAchievement.report([achievement]) { reportError in
42
- if let reportError = reportError {
43
- call.reject(reportError.localizedDescription, nil, reportError)
44
- } else {
45
- call.resolve()
46
- }
47
- }
48
- }
49
- }
50
-
51
- func show(_ call: CAPPluginCall) {
52
- DispatchQueue.main.async {
53
- guard let presenter = self.topViewController() else {
54
- call.reject("no presenter available"); return
55
- }
56
- let vc: GKGameCenterViewController
57
- if #available(iOS 14.0, *) {
58
- vc = GKGameCenterViewController(state: .achievements)
59
- } else {
60
- vc = GKGameCenterViewController()
61
- vc.viewState = .achievements
62
- }
63
- vc.gameCenterDelegate = self
64
- presenter.present(vc, animated: true) { call.resolve() }
65
- }
66
- }
67
-
68
- // MARK: - GKGameCenterControllerDelegate
69
-
70
- func gameCenterViewControllerDidFinish(_ controller: GKGameCenterViewController) {
71
- controller.dismiss(animated: true)
72
- }
73
- }
@@ -1,75 +0,0 @@
1
- import Capacitor
2
- import GameKit
3
- import UIKit
4
-
5
- /// GameKit leaderboards: score submission + the native leaderboard overlay.
6
- internal class LeaderboardsModule: PgsModule, GKGameCenterControllerDelegate {
7
- func submit(_ call: CAPPluginCall) {
8
- guard let leaderboardID = call.getString("leaderboardId") else {
9
- call.reject("missing leaderboardId"); return
10
- }
11
- let scoreDouble = call.getDouble("score") ?? 0
12
- let score = Int(scoreDouble)
13
-
14
- GKLeaderboard.submitScore(
15
- score,
16
- context: 0,
17
- player: GKLocalPlayer.local,
18
- leaderboardIDs: [leaderboardID]
19
- ) { error in
20
- if let error = error {
21
- call.reject(error.localizedDescription, nil, error)
22
- } else {
23
- call.resolve()
24
- }
25
- }
26
- }
27
-
28
- func show(_ call: CAPPluginCall) {
29
- guard let leaderboardID = call.getString("leaderboardId") else {
30
- call.reject("missing leaderboardId"); return
31
- }
32
- DispatchQueue.main.async {
33
- guard let presenter = self.topViewController() else {
34
- call.reject("no presenter available"); return
35
- }
36
- let vc: GKGameCenterViewController
37
- if #available(iOS 14.0, *) {
38
- vc = GKGameCenterViewController(
39
- leaderboardID: leaderboardID,
40
- playerScope: .global,
41
- timeScope: .allTime
42
- )
43
- } else {
44
- vc = GKGameCenterViewController()
45
- vc.viewState = .leaderboards
46
- vc.leaderboardIdentifier = leaderboardID
47
- }
48
- vc.gameCenterDelegate = self
49
- presenter.present(vc, animated: true) { call.resolve() }
50
- }
51
- }
52
-
53
- func showAll(_ call: CAPPluginCall) {
54
- DispatchQueue.main.async {
55
- guard let presenter = self.topViewController() else {
56
- call.reject("no presenter available"); return
57
- }
58
- let vc: GKGameCenterViewController
59
- if #available(iOS 14.0, *) {
60
- vc = GKGameCenterViewController(state: .leaderboards)
61
- } else {
62
- vc = GKGameCenterViewController()
63
- vc.viewState = .leaderboards
64
- }
65
- vc.gameCenterDelegate = self
66
- presenter.present(vc, animated: true) { call.resolve() }
67
- }
68
- }
69
-
70
- // MARK: - GKGameCenterControllerDelegate
71
-
72
- func gameCenterViewControllerDidFinish(_ controller: GKGameCenterViewController) {
73
- controller.dismiss(animated: true)
74
- }
75
- }
@@ -1,40 +0,0 @@
1
- import Capacitor
2
- import Foundation
3
- import GameKit
4
- import UIKit
5
-
6
- /// Shared base for per-feature modules. Inherits `NSObject` so subclasses can
7
- /// adopt @objc protocols (e.g. `GKGameCenterControllerDelegate`).
8
- internal class PgsModule: NSObject {
9
- unowned let plugin: PlayGamesPlugin
10
- init(_ plugin: PlayGamesPlugin) {
11
- self.plugin = plugin
12
- super.init()
13
- }
14
-
15
- /// Top-most presented view controller. Callers must be on the main queue.
16
- func topViewController() -> UIViewController? {
17
- guard let scene = UIApplication.shared.connectedScenes
18
- .compactMap({ $0 as? UIWindowScene })
19
- .first(where: { $0.activationState == .foregroundActive })
20
- ?? UIApplication.shared.connectedScenes
21
- .compactMap({ $0 as? UIWindowScene }).first,
22
- let rootVC = scene.windows.first(where: { $0.isKeyWindow })?.rootViewController
23
- ?? scene.windows.first?.rootViewController
24
- else { return nil }
25
-
26
- var top = rootVC
27
- while let presented = top.presentedViewController { top = presented }
28
- return top
29
- }
30
- }
31
-
32
- /// Serialise a GameKit player as the JS-side `PlayerInfo`. Uses the stable
33
- /// cross-device `gamePlayerID` (not the per-team `teamPlayerID`).
34
- internal func playerInfo(from player: GKLocalPlayer) -> [String: Any] {
35
- let info: [String: Any] = [
36
- "playerId": player.gamePlayerID,
37
- "displayName": player.displayName,
38
- ]
39
- return info
40
- }
@@ -1,74 +0,0 @@
1
- import Capacitor
2
- import Foundation
3
- import GameKit
4
-
5
- /// Capacitor 8 plugin wrapping Apple GameKit (sign-in, achievements,
6
- /// leaderboards, saved games). Thin dispatcher to four per-feature modules.
7
- @objc(PlayGamesPlugin)
8
- public class PlayGamesPlugin: CAPPlugin, CAPBridgedPlugin {
9
- // CAPBridgedPlugin self-registers the plugin on iOS (Capacitor 8). `jsName`
10
- // must match registerPlugin("PlayGames"); addListener/removeAllListeners
11
- // come from CAPPlugin and aren't listed here.
12
- public let identifier = "PlayGamesPlugin"
13
- public let jsName = "PlayGames"
14
- public let pluginMethods: [CAPPluginMethod] = [
15
- CAPPluginMethod(name: "initialize", returnType: CAPPluginReturnPromise),
16
- CAPPluginMethod(name: "signIn", returnType: CAPPluginReturnPromise),
17
- CAPPluginMethod(name: "isSignedIn", returnType: CAPPluginReturnPromise),
18
- CAPPluginMethod(name: "getPlayer", returnType: CAPPluginReturnPromise),
19
- CAPPluginMethod(name: "fetchIdentityVerificationSignature", returnType: CAPPluginReturnPromise),
20
- CAPPluginMethod(name: "unlockAchievement", returnType: CAPPluginReturnPromise),
21
- CAPPluginMethod(name: "incrementAchievement", returnType: CAPPluginReturnPromise),
22
- CAPPluginMethod(name: "showAchievements", returnType: CAPPluginReturnPromise),
23
- CAPPluginMethod(name: "submitScore", returnType: CAPPluginReturnPromise),
24
- CAPPluginMethod(name: "showLeaderboard", returnType: CAPPluginReturnPromise),
25
- CAPPluginMethod(name: "showAllLeaderboards", returnType: CAPPluginReturnPromise),
26
- CAPPluginMethod(name: "loadSnapshot", returnType: CAPPluginReturnPromise),
27
- CAPPluginMethod(name: "saveSnapshot", returnType: CAPPluginReturnPromise),
28
- CAPPluginMethod(name: "listSnapshots", returnType: CAPPluginReturnPromise),
29
- CAPPluginMethod(name: "deleteSnapshot", returnType: CAPPluginReturnPromise),
30
- ]
31
-
32
- private lazy var signInModule = SignInModule(self)
33
- private lazy var achievementsModule = AchievementsModule(self)
34
- private lazy var leaderboardsModule = LeaderboardsModule(self)
35
- private lazy var savedGamesModule = SavedGamesModule(self)
36
-
37
- // The GameKit authenticateHandler is installed in initialize(), NOT load():
38
- // see initialize() for the ATT-ordering reason.
39
-
40
- /// Expose listener emission to the modules.
41
- internal func emit(event: String, data: [String: Any]) {
42
- notifyListeners(event, data: data)
43
- }
44
-
45
- // MARK: - JS-callable surface
46
-
47
- @objc func initialize(_ call: CAPPluginCall) {
48
- // Setting the handler can auto-present GameKit's "Welcome back" banner,
49
- // which suppresses an ATT prompt shown while it's on screen, so call
50
- // initialize() only after the app has requested ATT.
51
- signInModule.installAuthHandlerIfNeeded()
52
- call.resolve()
53
- }
54
-
55
- @objc func signIn(_ call: CAPPluginCall) { signInModule.signIn(call) }
56
- @objc func isSignedIn(_ call: CAPPluginCall) { signInModule.isSignedIn(call) }
57
- @objc func getPlayer(_ call: CAPPluginCall) { signInModule.getPlayer(call) }
58
- @objc func fetchIdentityVerificationSignature(_ call: CAPPluginCall) {
59
- signInModule.fetchIdentityVerificationSignature(call)
60
- }
61
-
62
- @objc func unlockAchievement(_ call: CAPPluginCall) { achievementsModule.unlock(call) }
63
- @objc func incrementAchievement(_ call: CAPPluginCall) { achievementsModule.increment(call) }
64
- @objc func showAchievements(_ call: CAPPluginCall) { achievementsModule.show(call) }
65
-
66
- @objc func submitScore(_ call: CAPPluginCall) { leaderboardsModule.submit(call) }
67
- @objc func showLeaderboard(_ call: CAPPluginCall) { leaderboardsModule.show(call) }
68
- @objc func showAllLeaderboards(_ call: CAPPluginCall) { leaderboardsModule.showAll(call) }
69
-
70
- @objc func loadSnapshot(_ call: CAPPluginCall) { savedGamesModule.load(call) }
71
- @objc func saveSnapshot(_ call: CAPPluginCall) { savedGamesModule.save(call) }
72
- @objc func listSnapshots(_ call: CAPPluginCall) { savedGamesModule.list(call) }
73
- @objc func deleteSnapshot(_ call: CAPPluginCall) { savedGamesModule.delete(call) }
74
- }
@@ -1,102 +0,0 @@
1
- import Capacitor
2
- import GameKit
3
-
4
- /// GameKit Saved Games: load/save/list/delete by stable name. Conflicts resolve
5
- /// most-recently-modified-wins. Requires Game Center auth; otherwise GKLocalPlayer
6
- /// fails with `GKErrorNotAuthenticated`, forwarded to the caller.
7
- internal class SavedGamesModule: PgsModule {
8
- private var player: GKLocalPlayer { GKLocalPlayer.local }
9
-
10
- func load(_ call: CAPPluginCall) {
11
- guard let name = call.getString("name") else {
12
- call.reject("missing name"); return
13
- }
14
- player.fetchSavedGames { saved, error in
15
- if let error = error {
16
- call.reject(error.localizedDescription, nil, error)
17
- return
18
- }
19
- let matches = (saved ?? []).filter { $0.name == name }
20
- guard let pick = matches.max(by: { ($0.modificationDate ?? .distantPast) < ($1.modificationDate ?? .distantPast) }) else {
21
- call.resolve(["snapshot": NSNull()])
22
- return
23
- }
24
- if matches.count > 1 {
25
- self.player.resolveConflictingSavedGames(matches, with: Data()) { _, _ in }
26
- }
27
- pick.loadData { data, dataError in
28
- if let dataError = dataError {
29
- call.reject(dataError.localizedDescription, nil, dataError)
30
- return
31
- }
32
- let bytes = data ?? Data()
33
- let payload: [String: Any] = [
34
- "name": pick.name ?? name,
35
- // GKSavedGame has no description field; empty for API parity.
36
- "description": "",
37
- "modifiedAt": Int((pick.modificationDate ?? Date()).timeIntervalSince1970 * 1000),
38
- "data": String(data: bytes, encoding: .utf8) ?? "",
39
- ]
40
- call.resolve(["snapshot": payload])
41
- }
42
- }
43
- }
44
-
45
- func save(_ call: CAPPluginCall) {
46
- guard let name = call.getString("name") else {
47
- call.reject("missing name"); return
48
- }
49
- guard let data = call.getString("data") else {
50
- call.reject("missing data"); return
51
- }
52
- let bytes = Data(data.utf8)
53
- player.saveGameData(bytes, withName: name) { _, error in
54
- if let error = error {
55
- call.reject(error.localizedDescription, nil, error)
56
- } else {
57
- call.resolve()
58
- }
59
- }
60
- }
61
-
62
- func list(_ call: CAPPluginCall) {
63
- player.fetchSavedGames { saved, error in
64
- if let error = error {
65
- call.reject(error.localizedDescription, nil, error)
66
- return
67
- }
68
- // Collapse cross-device conflicts to one entry per name.
69
- var byName: [String: GKSavedGame] = [:]
70
- for s in saved ?? [] {
71
- let key = s.name ?? ""
72
- if key.isEmpty { continue }
73
- if let existing = byName[key],
74
- (existing.modificationDate ?? .distantPast) >= (s.modificationDate ?? .distantPast) {
75
- continue
76
- }
77
- byName[key] = s
78
- }
79
- let snapshots = byName.values.map { s -> [String: Any] in
80
- [
81
- "name": s.name ?? "",
82
- "description": "",
83
- "modifiedAt": Int((s.modificationDate ?? Date()).timeIntervalSince1970 * 1000),
84
- ]
85
- }
86
- call.resolve(["snapshots": snapshots])
87
- }
88
- }
89
-
90
- func delete(_ call: CAPPluginCall) {
91
- guard let name = call.getString("name") else {
92
- call.reject("missing name"); return
93
- }
94
- player.deleteSavedGames(withName: name) { error in
95
- if let error = error {
96
- call.reject(error.localizedDescription, nil, error)
97
- } else {
98
- call.resolve()
99
- }
100
- }
101
- }
102
- }
@@ -1,139 +0,0 @@
1
- import Capacitor
2
- import GameKit
3
-
4
- /// Wraps `GKLocalPlayer.authenticateHandler` (callback-driven; fires on every
5
- /// auth state change). `silent=true` only inspects `isAuthenticated`;
6
- /// `silent=false` presents the system sign-in UI when GameKit offers it.
7
- internal class SignInModule: PgsModule {
8
- private var handlerInstalled = false
9
-
10
- /// Idempotent. NOT installed in load(): setting the handler can auto-present
11
- /// GameKit's "Welcome back" banner, which would suppress an ATT prompt racing
12
- /// boot, so it is held until the app has requested ATT and called initialize().
13
- func installAuthHandlerIfNeeded() {
14
- if handlerInstalled { return }
15
- handlerInstalled = true
16
-
17
- GKLocalPlayer.local.authenticateHandler = { [weak self] viewController, _ in
18
- guard let self = self else { return }
19
- if let vc = viewController {
20
- // Stash the sign-in VC for the next interactive signIn(); don't auto-present.
21
- self.pendingSignInVC = vc
22
- } else {
23
- self.pendingSignInVC = nil
24
- // No UI offered: re-emit current auth state (also fires on sign-out).
25
- self.emitState()
26
- }
27
- }
28
- }
29
-
30
- private var pendingSignInVC: UIViewController?
31
-
32
- func signIn(_ call: CAPPluginCall) {
33
- let silent = call.getBool("silent", true)
34
- installAuthHandlerIfNeeded()
35
-
36
- if GKLocalPlayer.local.isAuthenticated {
37
- resolveSignedIn(call)
38
- return
39
- }
40
-
41
- if silent {
42
- resolveSignedOut(call)
43
- return
44
- }
45
-
46
- // Interactive: present the pending GameKit sign-in VC, if any.
47
- DispatchQueue.main.async {
48
- if let vc = self.pendingSignInVC, let presenter = self.topViewController() {
49
- self.pendingSignInVC = nil
50
- presenter.present(vc, animated: true) {
51
- if GKLocalPlayer.local.isAuthenticated {
52
- self.resolveSignedIn(call)
53
- } else {
54
- self.resolveSignedOut(call)
55
- }
56
- }
57
- } else if GKLocalPlayer.local.isAuthenticated {
58
- self.resolveSignedIn(call)
59
- } else {
60
- // No sign-in UI to present (device signed out of Game Center, or
61
- // the app isn't recognised by Game Center yet).
62
- self.resolveSignedOut(call)
63
- }
64
- }
65
- }
66
-
67
- func isSignedIn(_ call: CAPPluginCall) {
68
- call.resolve(["signedIn": GKLocalPlayer.local.isAuthenticated])
69
- }
70
-
71
- func getPlayer(_ call: CAPPluginCall) {
72
- guard GKLocalPlayer.local.isAuthenticated else {
73
- call.reject("not signed in")
74
- return
75
- }
76
- call.resolve(playerInfo(from: GKLocalPlayer.local))
77
- }
78
-
79
- func fetchIdentityVerificationSignature(_ call: CAPPluginCall) {
80
- let localPlayer = GKLocalPlayer.local
81
- guard localPlayer.isAuthenticated else {
82
- call.reject("not signed in")
83
- return
84
- }
85
- localPlayer.fetchItems(forIdentityVerificationSignature: {
86
- publicKeyURL, signature, salt, timestamp, error in
87
- if let error = error {
88
- call.reject(error.localizedDescription, nil, error)
89
- return
90
- }
91
- guard let publicKeyURL = publicKeyURL,
92
- let signature = signature,
93
- let salt = salt
94
- else {
95
- call.reject("identity verification signature unavailable")
96
- return
97
- }
98
- call.resolve([
99
- "publicKeyUrl": publicKeyURL.absoluteString,
100
- "signature": signature.base64EncodedString(),
101
- "salt": salt.base64EncodedString(),
102
- "timestamp": timestamp,
103
- "playerId": localPlayer.gamePlayerID,
104
- "bundleId": Bundle.main.bundleIdentifier ?? "",
105
- "teamPlayerId": localPlayer.teamPlayerID,
106
- "gamePlayerId": localPlayer.gamePlayerID,
107
- ])
108
- })
109
- }
110
-
111
- private func resolveSignedIn(_ call: CAPPluginCall) {
112
- let body: [String: Any] = [
113
- "signedIn": true,
114
- "player": playerInfo(from: GKLocalPlayer.local),
115
- ]
116
- plugin.emit(event: "signInStateChanged", data: body)
117
- call.resolve(body)
118
- }
119
-
120
- private func resolveSignedOut(_ call: CAPPluginCall) {
121
- let body: [String: Any] = ["signedIn": false]
122
- plugin.emit(event: "signInStateChanged", data: body)
123
- call.resolve(body)
124
- }
125
-
126
- /// Re-emit current auth state on a handler-driven change (e.g. signed out via Settings).
127
- private func emitState() {
128
- let body: [String: Any]
129
- if GKLocalPlayer.local.isAuthenticated {
130
- body = [
131
- "signedIn": true,
132
- "player": playerInfo(from: GKLocalPlayer.local),
133
- ]
134
- } else {
135
- body = ["signedIn": false]
136
- }
137
- plugin.emit(event: "signInStateChanged", data: body)
138
- }
139
- }