@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.
- package/CHANGELOG.md +86 -0
- package/CapacitorPlayGames.podspec +17 -0
- package/LICENSE +22 -0
- package/Package.swift +36 -0
- package/README.md +611 -0
- package/android/build.gradle +76 -0
- package/android/consumer-rules.pro +4 -0
- package/android/proguard-rules.pro +2 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/idleflowgames/playgames/AchievementsModule.kt +26 -0
- package/android/src/main/java/com/idleflowgames/playgames/LeaderboardsModule.kt +27 -0
- package/android/src/main/java/com/idleflowgames/playgames/Pgs.kt +48 -0
- package/android/src/main/java/com/idleflowgames/playgames/PlayGamesPlugin.kt +88 -0
- package/android/src/main/java/com/idleflowgames/playgames/SavedGamesModule.kt +119 -0
- package/android/src/main/java/com/idleflowgames/playgames/SignInModule.kt +83 -0
- package/dist/esm/definitions.d.ts +227 -0
- package/dist/esm/definitions.d.ts.map +1 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +33 -0
- package/dist/esm/web.d.ts.map +1 -0
- package/dist/esm/web.js +45 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +59 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +62 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/AchievementsModule.swift +73 -0
- package/ios/Plugin/LeaderboardsModule.swift +75 -0
- package/ios/Plugin/Pgs.swift +40 -0
- package/ios/Plugin/Plugin.swift +74 -0
- package/ios/Plugin/SavedGamesModule.swift +102 -0
- package/ios/Plugin/SignInModule.swift +139 -0
- package/package.json +80 -0
|
@@ -0,0 +1,139 @@
|
|
|
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
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
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.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/plugin.cjs.js",
|
|
7
|
+
"module": "dist/esm/index.js",
|
|
8
|
+
"types": "dist/esm/index.d.ts",
|
|
9
|
+
"unpkg": "dist/plugin.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"android/src/main/",
|
|
12
|
+
"android/build.gradle",
|
|
13
|
+
"android/consumer-rules.pro",
|
|
14
|
+
"android/proguard-rules.pro",
|
|
15
|
+
"dist/",
|
|
16
|
+
"ios/Plugin/",
|
|
17
|
+
"CapacitorPlayGames.podspec",
|
|
18
|
+
"Package.swift",
|
|
19
|
+
"CHANGELOG.md"
|
|
20
|
+
],
|
|
21
|
+
"author": "modbender",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"homepage": "https://github.com/modbender/capacitor-play-games#readme",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/modbender/capacitor-play-games.git"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/modbender/capacitor-play-games/issues"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"capacitor",
|
|
33
|
+
"plugin",
|
|
34
|
+
"native",
|
|
35
|
+
"ios",
|
|
36
|
+
"android",
|
|
37
|
+
"play-games",
|
|
38
|
+
"google-play-games",
|
|
39
|
+
"pgs",
|
|
40
|
+
"gamekit",
|
|
41
|
+
"game-center",
|
|
42
|
+
"achievements",
|
|
43
|
+
"leaderboards",
|
|
44
|
+
"saved-games"
|
|
45
|
+
],
|
|
46
|
+
"capacitor": {
|
|
47
|
+
"ios": {
|
|
48
|
+
"src": "ios"
|
|
49
|
+
},
|
|
50
|
+
"android": {
|
|
51
|
+
"src": "android"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@capacitor/core": "^8.0.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@capacitor/cli": "^8.5.1",
|
|
59
|
+
"@capacitor/core": "^8.5.1",
|
|
60
|
+
"@capacitor/docgen": "^0.3.1",
|
|
61
|
+
"rimraf": "^6.1.3",
|
|
62
|
+
"rollup": "^4.63.1",
|
|
63
|
+
"typescript": "^7.0.2"
|
|
64
|
+
},
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public",
|
|
67
|
+
"registry": "https://registry.npmjs.org/"
|
|
68
|
+
},
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=22"
|
|
71
|
+
},
|
|
72
|
+
"scripts": {
|
|
73
|
+
"clean": "rimraf dist",
|
|
74
|
+
"build": "rimraf dist && tsc && rollup -c rollup.config.mjs",
|
|
75
|
+
"docgen": "docgen --api PlayGamesPlugin --output-readme README.md",
|
|
76
|
+
"typecheck": "tsc --noEmit",
|
|
77
|
+
"verify": "bun run typecheck && bun run build",
|
|
78
|
+
"prepublishOnly": "bun run verify"
|
|
79
|
+
}
|
|
80
|
+
}
|