react-native-sdk-pianoio 0.3.4 → 0.3.6
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/README.md +92 -167
- package/android/src/main/java/com/sdkpianoio/ComposerPianoImpl.kt +44 -145
- package/android/src/main/java/com/sdkpianoio/TokenService.kt +0 -25
- package/ios/ComposerPianoImpl.swift +72 -52
- package/ios/SdkPianoio.swift +89 -16
- package/ios/SdkPianoioBridge.m +23 -5
- package/ios/TokenService.swift +5 -35
- package/package.json +1 -1
package/README.md
CHANGED
@@ -1,28 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# React Native SDK for Piano.io
|
2
2
|
|
3
|
-
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
5
|
-
|
6
|
-
A React Native SDK for integrating Piano.io's digital monetization platform into your mobile applications. This SDK provides seamless integration with Piano's paywall, subscription, and content monetization features.
|
3
|
+
A React Native SDK for integrating Piano.io's digital monetization platform into your mobile applications. This SDK provides seamless, cross-platform integration with Piano's paywall, subscription, and content monetization features.
|
7
4
|
|
8
5
|
## ✨ Features
|
9
6
|
|
10
|
-
|
11
|
-
- **Piano
|
12
|
-
- **
|
13
|
-
- **
|
14
|
-
- **Cross-Platform**: Works on both iOS and Android (Android fully implemented)
|
15
|
-
|
16
|
-
### 📱 Platform Support
|
17
|
-
- ✅ **Android**: Fully implemented and tested (91% test coverage)
|
18
|
-
- 🚧 **iOS**: Basic implementation (needs feature parity)
|
19
|
-
|
20
|
-
### 🔧 Configuration Options
|
21
|
-
- **Tags Management**: Add/remove tags for content categorization
|
22
|
-
- **Zone Configuration**: Set zone IDs for targeted experiences
|
23
|
-
- **Custom Variables**: Add custom data to experiences
|
24
|
-
- **User Tokens**: Manage user authentication tokens
|
25
|
-
- **URL Configuration**: Set referrer and target URLs
|
7
|
+
- **Full Piano Composer Integration**: Execute experiences, manage content access, and handle paywalls
|
8
|
+
- **Piano ID Authentication**: Complete user authentication and token management for both platforms
|
9
|
+
- **Cross-Platform Parity**: A single, unified API for both iOS and Android
|
10
|
+
- **Flexible Configuration**: Manage tags, zone IDs, custom variables, user tokens, and more
|
26
11
|
|
27
12
|
## 📦 Installation
|
28
13
|
|
@@ -36,7 +21,7 @@ yarn add react-native-sdk-pianoio
|
|
36
21
|
|
37
22
|
### 1. Initialize the SDK
|
38
23
|
|
39
|
-
```
|
24
|
+
```javascript
|
40
25
|
import { PianoComposer } from 'react-native-sdk-pianoio';
|
41
26
|
|
42
27
|
// Initialize with your Piano Application ID
|
@@ -45,44 +30,42 @@ const composer = await PianoComposer.create('YOUR_PIANO_AID');
|
|
45
30
|
|
46
31
|
### 2. Configure the Experience
|
47
32
|
|
48
|
-
```
|
49
|
-
//
|
50
|
-
await composer.
|
51
|
-
await composer.
|
33
|
+
```javascript
|
34
|
+
// Set the required parameters for the experience
|
35
|
+
await composer.setUrl('https://www.your-website.com/premium-article');
|
36
|
+
await composer.setZoneId('your_zone_id'); // e.g., 'default'
|
37
|
+
await composer.setReferrer('https://www.your-website.com/');
|
52
38
|
|
53
|
-
//
|
54
|
-
await composer.
|
55
|
-
|
56
|
-
// Add custom variables
|
39
|
+
// Add optional parameters
|
40
|
+
await composer.addTag('premium-content');
|
57
41
|
await composer.setCustomVariable('article_id', '12345');
|
58
|
-
|
59
|
-
// Set user token for authentication
|
60
|
-
await composer.setUserToken('user_token_123');
|
61
42
|
```
|
62
43
|
|
63
44
|
### 3. Execute the Experience
|
64
45
|
|
65
|
-
```
|
66
|
-
|
67
|
-
const result = await composer.executeExperience();
|
68
|
-
|
69
|
-
//
|
70
|
-
|
46
|
+
```javascript
|
47
|
+
try {
|
48
|
+
const result = await composer.executeExperience();
|
49
|
+
console.log('Experience result:', result);
|
50
|
+
// Handle the event data from the Piano backend
|
51
|
+
} catch (error) {
|
52
|
+
console.error('Failed to execute experience:', error);
|
53
|
+
}
|
71
54
|
```
|
72
55
|
|
73
56
|
### 4. Handle Authentication
|
74
57
|
|
75
|
-
```
|
76
|
-
// Sign in user
|
58
|
+
```javascript
|
59
|
+
// Sign in a user
|
77
60
|
const user = await composer.signIn();
|
78
61
|
|
79
|
-
// Check
|
62
|
+
// Check if a user is authenticated
|
80
63
|
const isAuthenticated = await composer.isAuthenticated();
|
81
64
|
|
82
|
-
// Get current user
|
65
|
+
// Get the current user's details
|
83
66
|
const currentUser = await composer.getCurrentUser();
|
84
67
|
|
85
|
-
// Sign out user
|
68
|
+
// Sign out the user
|
86
69
|
await composer.signOut();
|
87
70
|
```
|
88
71
|
|
@@ -90,95 +73,48 @@ await composer.signOut();
|
|
90
73
|
|
91
74
|
### Core Methods
|
92
75
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
#### `composer.getCurrentUser()`
|
120
|
-
Gets information about the current authenticated user.
|
121
|
-
|
122
|
-
#### `composer.isAuthenticated()`
|
123
|
-
Checks if a user is currently authenticated.
|
124
|
-
|
125
|
-
### Advanced Methods
|
126
|
-
|
127
|
-
#### `composer.executeExperienceWithConfig(includeUserData: boolean, debug: boolean)`
|
128
|
-
Executes experience with advanced configuration options.
|
129
|
-
|
130
|
-
#### `composer.createExperienceRequest(includeUserData?: boolean, debug?: boolean)`
|
131
|
-
Creates an experience request with custom parameters.
|
132
|
-
|
133
|
-
#### `composer.getStatus()`
|
134
|
-
Gets the current status of the composer.
|
135
|
-
|
136
|
-
#### `composer.testExecutionFlow()`
|
137
|
-
Tests the complete execution flow.
|
138
|
-
|
139
|
-
## 🧪 Testing
|
140
|
-
|
141
|
-
The SDK includes comprehensive test coverage:
|
142
|
-
|
143
|
-
```bash
|
144
|
-
# Run all tests
|
145
|
-
npm test
|
146
|
-
|
147
|
-
# Run tests with coverage
|
148
|
-
npm run test:coverage
|
149
|
-
|
150
|
-
# Run Android-specific tests
|
151
|
-
cd android && ./test.sh
|
152
|
-
```
|
153
|
-
|
154
|
-
### Test Results
|
155
|
-
- ✅ **91% Test Coverage** on Android implementation
|
156
|
-
- ✅ **67/73 tests passing**
|
157
|
-
- ✅ **All core functionality tested**
|
76
|
+
- `PianoComposer.create(aid: string)` - Creates and initializes a new PianoComposer instance
|
77
|
+
- `composer.executeExperience()` - Executes the Piano experience with the current configuration
|
78
|
+
- `composer.signIn()` - Initiates the user sign-in flow
|
79
|
+
- `composer.signOut()` - Signs out the current user
|
80
|
+
|
81
|
+
### Configuration Methods
|
82
|
+
|
83
|
+
- `addTag(tag: string)`
|
84
|
+
- `addTags(tags: string[])`
|
85
|
+
- `setZoneId(zoneId: string)`
|
86
|
+
- `setReferrer(referrer: string)`
|
87
|
+
- `setUrl(url: string)`
|
88
|
+
- `setUserToken(token: string)`
|
89
|
+
- `addCustomVariable(key: string, value: string)`
|
90
|
+
- `setCustomVariables(variables: { [key: string]: string })`
|
91
|
+
|
92
|
+
### Utility Methods
|
93
|
+
|
94
|
+
- `getCurrentUser()`
|
95
|
+
- `isAuthenticated()`
|
96
|
+
- `getStatus()`
|
97
|
+
- `clearConfiguration()`
|
98
|
+
- `removeTag(tag: string)`
|
99
|
+
- `removeCustomVariable(key: string)`
|
100
|
+
- `clearTags()`
|
101
|
+
- `clearCustomVariables()`
|
158
102
|
|
159
103
|
## 📱 Platform Status
|
160
104
|
|
161
|
-
|
162
|
-
- **
|
163
|
-
- **Coverage**: 91% test coverage
|
164
|
-
- **Features**: All core features implemented
|
165
|
-
- **Dependencies**: React Native 0.78.1 compatible
|
166
|
-
|
167
|
-
### iOS 🚧
|
168
|
-
- **Status**: Basic implementation
|
169
|
-
- **Coverage**: Needs feature parity with Android
|
170
|
-
- **Features**: Core methods implemented
|
171
|
-
- **Next Steps**: Implement advanced features and authentication
|
105
|
+
- ✅ **Android**: Fully implemented and aligned with the official Piano Android SDK
|
106
|
+
- ✅ **iOS**: Fully implemented and aligned with the official Piano iOS SDK
|
172
107
|
|
173
108
|
## 🔧 Development
|
174
109
|
|
175
110
|
### Prerequisites
|
111
|
+
|
176
112
|
- Node.js 18+
|
177
|
-
- React Native
|
113
|
+
- React Native
|
178
114
|
- Android Studio (for Android development)
|
179
|
-
- Xcode (for iOS development)
|
115
|
+
- Xcode & CocoaPods (for iOS development)
|
180
116
|
|
181
|
-
### Setup
|
117
|
+
### Setup
|
182
118
|
|
183
119
|
```bash
|
184
120
|
# Clone the repository
|
@@ -187,67 +123,60 @@ git clone https://github.com/HexagonSwiss/hex-react-native-sdk-pianoio.git
|
|
187
123
|
# Install dependencies
|
188
124
|
npm install
|
189
125
|
|
190
|
-
# Run tests
|
191
|
-
npm test
|
192
|
-
|
193
126
|
# Build the library
|
194
127
|
npm run build
|
195
128
|
```
|
196
129
|
|
197
130
|
### Project Structure
|
131
|
+
|
198
132
|
```
|
199
|
-
├── android/
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
├── src/ # TypeScript source
|
204
|
-
│ ├── index.tsx # Main entry point
|
205
|
-
│ ├── PianoComposer.tsx # Main SDK class
|
206
|
-
│ └── NativeSdkPianoio.ts # Native module interface
|
207
|
-
├── example/ # Example React Native app
|
208
|
-
└── lib/ # Built library files
|
133
|
+
├── android/ # Android native implementation
|
134
|
+
├── ios/ # iOS native implementation
|
135
|
+
├── src/ # TypeScript source (JS bridge)
|
136
|
+
└── ...
|
209
137
|
```
|
210
138
|
|
211
|
-
## 🎯
|
212
|
-
|
213
|
-
The repository includes a comprehensive example app demonstrating all SDK features:
|
139
|
+
## 🎯 How to install
|
214
140
|
|
215
|
-
```
|
216
|
-
#
|
217
|
-
|
141
|
+
```
|
142
|
+
# In your expo projet's app.json file, make sure to have:
|
143
|
+
|
144
|
+
"plugins": [
|
145
|
+
[
|
146
|
+
"expo-build-properties",
|
147
|
+
{
|
148
|
+
"android": {
|
149
|
+
"buildToolsVersion": "35.0.0",
|
150
|
+
"compileSdkVersion": 34,
|
151
|
+
"minSdkVersion": 24,
|
152
|
+
"targetSdkVersion": 34
|
153
|
+
},
|
154
|
+
"ios": {
|
155
|
+
"deploymentTarget": "15.1",
|
156
|
+
"useFrameworks": "static"
|
157
|
+
}
|
158
|
+
}
|
159
|
+
]
|
160
|
+
...other plugins...
|
161
|
+
],
|
218
162
|
|
219
163
|
# Install dependencies
|
220
|
-
npm install
|
164
|
+
npm install react-native-sdk-pianoio
|
221
165
|
|
222
166
|
# Run on Android
|
223
|
-
npx
|
167
|
+
npx expo run:android
|
224
168
|
|
225
169
|
# Run on iOS
|
226
|
-
npx
|
170
|
+
npx expo run:ios
|
227
171
|
```
|
228
172
|
|
229
|
-
The example app includes:
|
230
|
-
- ✅ Basic configuration testing
|
231
|
-
- ✅ Authentication flow testing
|
232
|
-
- ✅ Advanced configuration options
|
233
|
-
- ✅ Experience execution
|
234
|
-
- ✅ Real-time logging
|
235
|
-
|
236
173
|
## 🤝 Contributing
|
237
174
|
|
238
|
-
We welcome contributions! Please see our
|
239
|
-
|
240
|
-
### Development Workflow
|
241
|
-
1. Fork the repository
|
242
|
-
2. Create a feature branch
|
243
|
-
3. Make your changes
|
244
|
-
4. Add tests for new functionality
|
245
|
-
5. Ensure all tests pass
|
246
|
-
6. Submit a pull request
|
175
|
+
We welcome contributions! Please see our Contributing Guide for details.
|
247
176
|
|
248
177
|
## 📄 License
|
249
178
|
|
250
|
-
This project is licensed under the MIT License - see the
|
179
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
251
180
|
|
252
181
|
## 🆘 Support
|
253
182
|
|
@@ -255,10 +184,6 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
255
184
|
- 🐛 **Issues**: [GitHub Issues](https://github.com/HexagonSwiss/hex-react-native-sdk-pianoio/issues)
|
256
185
|
- 📖 **Documentation**: [Piano.io Documentation](https://docs.piano.io/)
|
257
186
|
|
258
|
-
## 🔄 Changelog
|
259
|
-
|
260
|
-
See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes.
|
261
|
-
|
262
187
|
---
|
263
188
|
|
264
|
-
|
189
|
+
Made with ❤️ by HexagonSwiss
|
@@ -26,40 +26,24 @@ class ComposerPianoImpl {
|
|
26
26
|
|
27
27
|
// MARK: - Properties
|
28
28
|
|
29
|
-
/** The Piano SDK's Composer instance */
|
30
29
|
private var composer: Composer? = null
|
31
|
-
|
32
|
-
/** The Piano ID Token Service instance */
|
33
30
|
internal var tokenService: TokenService? = null
|
34
31
|
|
35
|
-
/** The Piano Application ID */
|
36
32
|
companion object {
|
37
33
|
var aid: String = ""
|
38
34
|
}
|
39
35
|
|
40
36
|
// MARK: - Configuration Properties
|
41
37
|
|
42
|
-
/** Configured tags for the composer */
|
43
38
|
private val tags = mutableListOf<String>()
|
44
|
-
|
45
|
-
/** Configured Zone ID */
|
46
39
|
private var zoneId: String? = null
|
47
|
-
|
48
|
-
/** Configured referrer */
|
49
40
|
private var referrer: String? = null
|
50
|
-
|
51
|
-
/** Configured URL */
|
52
41
|
private var url: String? = null
|
53
|
-
|
54
|
-
/** Configured user token */
|
55
42
|
private var userToken: String? = null
|
56
|
-
|
57
|
-
/** Configured custom variables */
|
58
43
|
private val customVariables = mutableMapOf<String, String>()
|
59
44
|
|
60
45
|
// MARK: - Initialization
|
61
46
|
|
62
|
-
/** Public class constructor Initializes the instance with default values */
|
63
47
|
constructor() {
|
64
48
|
println("ComposerPianoImpl: Constructor initialized")
|
65
49
|
}
|
@@ -103,24 +87,48 @@ class ComposerPianoImpl {
|
|
103
87
|
}
|
104
88
|
}
|
105
89
|
|
106
|
-
// MARK: -
|
90
|
+
// MARK: - State Methods (Getters)
|
91
|
+
|
92
|
+
fun getAid(): String {
|
93
|
+
return ComposerPianoImpl.aid
|
94
|
+
}
|
95
|
+
|
96
|
+
fun getTags(): List<String> {
|
97
|
+
return this.tags.toList()
|
98
|
+
}
|
99
|
+
|
100
|
+
fun getZoneId(): String {
|
101
|
+
return this.zoneId ?: ""
|
102
|
+
}
|
103
|
+
|
104
|
+
fun getReferrer(): String {
|
105
|
+
return referrer ?: ""
|
106
|
+
}
|
107
|
+
|
108
|
+
fun getUrl(): String {
|
109
|
+
return url ?: ""
|
110
|
+
}
|
111
|
+
|
112
|
+
fun getUserToken(): String {
|
113
|
+
return userToken ?: ""
|
114
|
+
}
|
115
|
+
|
116
|
+
fun getComposer(): Composer? {
|
117
|
+
return composer
|
118
|
+
}
|
119
|
+
|
120
|
+
fun getCustomVariables(): Map<String, String> {
|
121
|
+
return customVariables.toMap()
|
122
|
+
}
|
123
|
+
|
124
|
+
// MARK: - Configuration Methods (Setters)
|
107
125
|
|
108
|
-
/**
|
109
|
-
* Adds a tag to the composer
|
110
|
-
*
|
111
|
-
* @param tag The tag to be added
|
112
|
-
*/
|
113
126
|
fun addTag(tag: String) {
|
114
127
|
if (!this.tags.contains(tag)) {
|
115
128
|
this.tags.add(tag)
|
116
129
|
}
|
117
130
|
}
|
118
131
|
|
119
|
-
/**
|
120
|
-
* Adds multiple tags to the composer
|
121
|
-
*
|
122
|
-
* @param tags The list of tags to be added
|
123
|
-
*/
|
124
132
|
fun addTags(tags: List<String>) {
|
125
133
|
for (tag in tags) {
|
126
134
|
if (!this.tags.contains(tag)) {
|
@@ -129,166 +137,57 @@ class ComposerPianoImpl {
|
|
129
137
|
}
|
130
138
|
}
|
131
139
|
|
132
|
-
/**
|
133
|
-
* Sets the Zone ID for the composer
|
134
|
-
*
|
135
|
-
* @param zoneId The Zone ID to be configured
|
136
|
-
*/
|
137
140
|
fun setZoneId(zoneId: String) {
|
138
141
|
this.zoneId = zoneId
|
139
142
|
}
|
140
143
|
|
141
|
-
/**
|
142
|
-
* Sets the referrer for the composer
|
143
|
-
*
|
144
|
-
* @param referrer The referrer to be configured
|
145
|
-
*/
|
146
144
|
fun setReferrer(referrer: String) {
|
147
145
|
this.referrer = referrer
|
148
146
|
}
|
149
147
|
|
150
|
-
/**
|
151
|
-
* Sets the URL for the composer
|
152
|
-
*
|
153
|
-
* @param url The URL to be configured
|
154
|
-
*/
|
155
148
|
fun setUrl(url: String) {
|
156
149
|
this.url = url
|
157
150
|
}
|
158
151
|
|
159
|
-
/**
|
160
|
-
* Sets the user token on the Composer instance.
|
161
|
-
*
|
162
|
-
* @param token The user's access token.
|
163
|
-
*/
|
164
152
|
fun setUserToken(token: String) {
|
165
153
|
this.userToken = token
|
166
|
-
// Call the official SDK method to set the token
|
167
154
|
composer?.userToken(token)
|
168
155
|
}
|
169
156
|
|
170
|
-
/**
|
171
|
-
* Adds a custom variable.
|
172
|
-
*
|
173
|
-
* @param key The variable's key
|
174
|
-
* @param value The variable's value
|
175
|
-
*/
|
176
157
|
fun addCustomVariable(key: String, value: String) {
|
177
158
|
this.customVariables[key] = value
|
178
159
|
}
|
179
160
|
|
180
|
-
// MARK: - Advanced Configuration Methods
|
181
|
-
|
182
|
-
/**
|
183
|
-
* Sets multiple custom variables at once.
|
184
|
-
*
|
185
|
-
* @param variables A map of custom variables.
|
186
|
-
*/
|
187
161
|
fun setCustomVariables(variables: Map<String, String>) {
|
188
162
|
this.customVariables.clear()
|
189
163
|
this.customVariables.putAll(variables)
|
190
164
|
}
|
191
165
|
|
192
|
-
|
166
|
+
// MARK: - Cleanup Methods
|
167
|
+
|
193
168
|
fun clearTags() {
|
194
169
|
this.tags.clear()
|
195
170
|
}
|
196
171
|
|
197
|
-
/** Removes all custom variables. */
|
198
172
|
fun clearCustomVariables() {
|
199
173
|
this.customVariables.clear()
|
200
174
|
}
|
201
175
|
|
202
|
-
/**
|
203
|
-
* Removes a specific tag.
|
204
|
-
*
|
205
|
-
* @param tag The tag to be removed.
|
206
|
-
*/
|
207
176
|
fun removeTag(tag: String) {
|
208
177
|
this.tags.remove(tag)
|
209
178
|
}
|
210
179
|
|
211
|
-
/**
|
212
|
-
* Removes a specific custom variable.
|
213
|
-
*
|
214
|
-
* @param key The key of the variable to be removed.
|
215
|
-
*/
|
216
180
|
fun removeCustomVariable(key: String) {
|
217
181
|
this.customVariables.remove(key)
|
218
182
|
}
|
219
183
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
fun getAid(): String {
|
228
|
-
return ComposerPianoImpl.aid
|
229
|
-
}
|
230
|
-
|
231
|
-
/**
|
232
|
-
* Gets the configured tags.
|
233
|
-
*
|
234
|
-
* @return A list of configured tags.
|
235
|
-
*/
|
236
|
-
fun getTags(): List<String> {
|
237
|
-
return this.tags.toList()
|
238
|
-
}
|
239
|
-
|
240
|
-
/**
|
241
|
-
* Gets the configured Zone ID.
|
242
|
-
*
|
243
|
-
* @return The current Zone ID.
|
244
|
-
*/
|
245
|
-
fun getZoneId(): String {
|
246
|
-
return this.zoneId ?: ""
|
247
|
-
}
|
248
|
-
|
249
|
-
/**
|
250
|
-
* Gets the configured referrer.
|
251
|
-
*
|
252
|
-
* @return The current referrer.
|
253
|
-
*/
|
254
|
-
fun getReferrer(): String {
|
255
|
-
return referrer ?: ""
|
256
|
-
}
|
257
|
-
|
258
|
-
/**
|
259
|
-
* Gets the configured URL.
|
260
|
-
*
|
261
|
-
* @return The current URL.
|
262
|
-
*/
|
263
|
-
fun getUrl(): String {
|
264
|
-
return url ?: ""
|
265
|
-
}
|
266
|
-
|
267
|
-
/**
|
268
|
-
* Gets the user token.
|
269
|
-
*
|
270
|
-
* @return The current user token.
|
271
|
-
*/
|
272
|
-
fun getUserToken(): String {
|
273
|
-
return userToken ?: ""
|
274
|
-
}
|
275
|
-
|
276
|
-
/**
|
277
|
-
* Gets the composer instance.
|
278
|
-
*
|
279
|
-
* @return The Composer instance, or null if not initialized.
|
280
|
-
*/
|
281
|
-
fun getComposer(): Composer? {
|
282
|
-
return composer
|
283
|
-
}
|
284
|
-
|
285
|
-
/**
|
286
|
-
* Gets the configured custom variables.
|
287
|
-
*
|
288
|
-
* @return A map of the custom variables.
|
289
|
-
*/
|
290
|
-
fun getCustomVariables(): Map<String, String> {
|
291
|
-
return customVariables.toMap()
|
184
|
+
fun clearConfiguration() {
|
185
|
+
this.clearTags()
|
186
|
+
this.clearCustomVariables()
|
187
|
+
this.zoneId = null
|
188
|
+
this.referrer = null
|
189
|
+
this.url = null
|
190
|
+
this.userToken = null
|
292
191
|
}
|
293
192
|
|
294
193
|
// MARK: - Execution Methods
|
@@ -54,20 +54,10 @@ class TokenService {
|
|
54
54
|
|
55
55
|
// MARK: - Authentication Methods
|
56
56
|
|
57
|
-
/**
|
58
|
-
* Caches the token received from a successful sign-in.
|
59
|
-
*
|
60
|
-
* @param token The token to cache. Can be null to clear it.
|
61
|
-
*/
|
62
57
|
fun setToken(token: PianoIdToken?) {
|
63
58
|
this.cachedToken = token
|
64
59
|
}
|
65
60
|
|
66
|
-
/**
|
67
|
-
* Launches the Piano ID sign-in flow.
|
68
|
-
*
|
69
|
-
* @param authResultLauncher The ActivityResultLauncher from the calling Activity/Fragment.
|
70
|
-
*/
|
71
61
|
fun signIn(authResultLauncher: ActivityResultLauncher<PianoIdClient.SignInContext>) {
|
72
62
|
val localClient = client
|
73
63
|
if (localClient == null) {
|
@@ -79,11 +69,6 @@ class TokenService {
|
|
79
69
|
authResultLauncher.launch(request)
|
80
70
|
}
|
81
71
|
|
82
|
-
/**
|
83
|
-
* Signs the user out.
|
84
|
-
*
|
85
|
-
* @param callback The callback to be invoked with the result (true for success, false for failure).
|
86
|
-
*/
|
87
72
|
fun signOut(callback: (Boolean) -> Unit) {
|
88
73
|
val localClient = client
|
89
74
|
if (localClient == null) {
|
@@ -113,11 +98,6 @@ class TokenService {
|
|
113
98
|
|
114
99
|
// MARK: - User Information Methods
|
115
100
|
|
116
|
-
/**
|
117
|
-
* Gets the current user's information.
|
118
|
-
*
|
119
|
-
* @return A User object if authenticated, otherwise null.
|
120
|
-
*/
|
121
101
|
fun getCurrentUser(): User? {
|
122
102
|
val token = this.cachedToken ?: return null
|
123
103
|
// Construct a user from the token information using the getInfoField method.
|
@@ -128,11 +108,6 @@ class TokenService {
|
|
128
108
|
)
|
129
109
|
}
|
130
110
|
|
131
|
-
/**
|
132
|
-
* Checks if a user is currently authenticated.
|
133
|
-
*
|
134
|
-
* @return true if a valid token exists, false otherwise.
|
135
|
-
*/
|
136
111
|
fun isAuthenticated(): Boolean {
|
137
112
|
return this.cachedToken != null
|
138
113
|
}
|
@@ -3,15 +3,13 @@ import PianoComposer
|
|
3
3
|
import PianoOAuth
|
4
4
|
import React
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
* - Managing React Native promises across asynchronous callbacks.
|
14
|
-
*/
|
6
|
+
/// ComposerPianoImpl - Main implementation class for the Piano SDK on iOS.
|
7
|
+
///
|
8
|
+
/// This class is responsible for:
|
9
|
+
/// - Managing the Piano SDK's Composer instance.
|
10
|
+
/// - Configuring the experience request using a fluent builder pattern.
|
11
|
+
/// - Executing Piano experiences and handling results via a delegate.
|
12
|
+
/// - Managing React Native promises across asynchronous callbacks.
|
15
13
|
@objcMembers public class ComposerPianoImpl: NSObject {
|
16
14
|
|
17
15
|
// MARK: - Properties
|
@@ -20,15 +18,14 @@ import React
|
|
20
18
|
private var tokenService: TokenService?
|
21
19
|
private var delegate: MyComposerDelegate?
|
22
20
|
|
23
|
-
// Promises to communicate results of async operations back to React Native
|
24
21
|
var experienceResolver: RCTPromiseResolveBlock?
|
25
22
|
var experienceRejecter: RCTPromiseRejectBlock?
|
26
23
|
|
27
|
-
// Stored configuration properties
|
28
24
|
private var tags: [String] = []
|
29
25
|
private var zoneId: String?
|
30
26
|
private var referrer: String?
|
31
27
|
private var url: String?
|
28
|
+
private var userToken: String?
|
32
29
|
private var customVariables: [String: String] = [:]
|
33
30
|
|
34
31
|
// MARK: - Initialization
|
@@ -56,7 +53,33 @@ import React
|
|
56
53
|
print("ComposerPianoImpl: Delegate initialized and set")
|
57
54
|
}
|
58
55
|
|
59
|
-
// MARK: -
|
56
|
+
// MARK: - State Methods (Getters)
|
57
|
+
|
58
|
+
public func getTags() -> [String] {
|
59
|
+
return self.tags
|
60
|
+
}
|
61
|
+
|
62
|
+
public func getZoneId() -> String {
|
63
|
+
return self.zoneId ?? ""
|
64
|
+
}
|
65
|
+
|
66
|
+
public func getReferrer() -> String {
|
67
|
+
return self.referrer ?? ""
|
68
|
+
}
|
69
|
+
|
70
|
+
public func getUrl() -> String {
|
71
|
+
return self.url ?? ""
|
72
|
+
}
|
73
|
+
|
74
|
+
public func getUserToken() -> String {
|
75
|
+
return self.composer?.userToken ?? ""
|
76
|
+
}
|
77
|
+
|
78
|
+
public func getCustomVariables() -> [String: String] {
|
79
|
+
return self.customVariables
|
80
|
+
}
|
81
|
+
|
82
|
+
// MARK: - Configuration Methods (Setters)
|
60
83
|
|
61
84
|
public func addTag(_ tag: String) {
|
62
85
|
self.tags.append(tag)
|
@@ -78,23 +101,47 @@ import React
|
|
78
101
|
self.url = url
|
79
102
|
}
|
80
103
|
|
81
|
-
public func
|
104
|
+
public func setCustomVariables(_ variables: [String: String]) {
|
105
|
+
self.customVariables = variables
|
106
|
+
}
|
107
|
+
|
108
|
+
public func addCustomVariable(_ name: String, value: String) {
|
82
109
|
self.customVariables[name] = value
|
83
110
|
}
|
84
111
|
|
85
112
|
public func setUserToken(_ token: String) {
|
86
|
-
// The iOS SDK requires setting the user token on the composer instance directly
|
87
113
|
_ = self.composer?.userToken(token)
|
88
114
|
}
|
89
115
|
|
116
|
+
// MARK: - Cleanup Methods
|
117
|
+
|
118
|
+
public func clearTags() {
|
119
|
+
self.tags.removeAll()
|
120
|
+
}
|
121
|
+
|
122
|
+
public func clearCustomVariables() {
|
123
|
+
self.customVariables.removeAll()
|
124
|
+
}
|
125
|
+
|
126
|
+
public func removeTag(_ tag: String) {
|
127
|
+
self.tags.removeAll { $0 == tag }
|
128
|
+
}
|
129
|
+
|
130
|
+
public func removeCustomVariable(key: String) {
|
131
|
+
self.customVariables.removeValue(forKey: key)
|
132
|
+
}
|
133
|
+
|
134
|
+
public func clearConfiguration() {
|
135
|
+
self.clearTags()
|
136
|
+
self.clearCustomVariables()
|
137
|
+
self.zoneId = nil
|
138
|
+
self.referrer = nil
|
139
|
+
self.url = nil
|
140
|
+
self.userToken = nil
|
141
|
+
}
|
142
|
+
|
90
143
|
// MARK: - Execution Method
|
91
144
|
|
92
|
-
/**
|
93
|
-
* Executes the Piano experience with the current configuration.
|
94
|
-
*
|
95
|
-
* @param resolver The promise resolver from React Native.
|
96
|
-
* @param rejecter The promise rejecter from React Native.
|
97
|
-
*/
|
98
145
|
public func executeExperience(
|
99
146
|
resolver: @escaping RCTPromiseResolveBlock,
|
100
147
|
rejecter: @escaping RCTPromiseRejectBlock
|
@@ -104,47 +151,20 @@ import React
|
|
104
151
|
return
|
105
152
|
}
|
106
153
|
|
107
|
-
print("ComposerPianoImpl: Executing experience")
|
108
|
-
|
109
|
-
// Store the promise functions to be called by the delegate later
|
110
154
|
self.experienceResolver = resolver
|
111
155
|
self.experienceRejecter = rejecter
|
112
156
|
|
113
|
-
|
114
|
-
|
157
|
+
_ =
|
158
|
+
composer
|
115
159
|
.tags(self.tags)
|
116
|
-
.zoneId(self.zoneId ?? "")
|
117
|
-
.referrer(self.referrer ?? "")
|
118
|
-
.url(self.url ?? "")
|
160
|
+
.zoneId(self.zoneId ?? "")
|
161
|
+
.referrer(self.referrer ?? "")
|
162
|
+
.url(self.url ?? "")
|
119
163
|
|
120
164
|
for (key, value) in self.customVariables {
|
121
165
|
_ = composer.customVariable(name: key, value: value)
|
122
166
|
}
|
123
167
|
|
124
|
-
// Execute the experience. The result will be handled by the delegate.
|
125
168
|
composer.execute()
|
126
169
|
}
|
127
|
-
|
128
|
-
// MARK: - State Methods (Getters)
|
129
|
-
|
130
|
-
public func getTags() -> [String] {
|
131
|
-
return self.tags
|
132
|
-
}
|
133
|
-
|
134
|
-
public func getZoneId() -> String {
|
135
|
-
return self.zoneId ?? ""
|
136
|
-
}
|
137
|
-
|
138
|
-
public func getReferrer() -> String {
|
139
|
-
return self.referrer ?? ""
|
140
|
-
}
|
141
|
-
|
142
|
-
public func getUrl() -> String {
|
143
|
-
return self.url ?? ""
|
144
|
-
}
|
145
|
-
|
146
|
-
public func getUserToken() -> String {
|
147
|
-
// User token is write-only to the composer instance, so we return the stored value if needed.
|
148
|
-
return self.composer?.userToken ?? ""
|
149
|
-
}
|
150
170
|
}
|
package/ios/SdkPianoio.swift
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
import Foundation
|
2
2
|
import React
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
* This class exposes the functionality of the ComposerPianoImpl to JavaScript.
|
8
|
-
*/
|
4
|
+
/// SdkPianoio - The main React Native bridge module for the Piano SDK.
|
5
|
+
///
|
6
|
+
/// This class exposes the functionality of the ComposerPianoImpl to JavaScript.
|
9
7
|
@objc(SdkPianoio)
|
10
8
|
class SdkPianoio: NSObject {
|
11
9
|
|
@@ -18,7 +16,10 @@ class SdkPianoio: NSObject {
|
|
18
16
|
}
|
19
17
|
|
20
18
|
@objc(initialize:resolver:rejecter:)
|
21
|
-
func initialize(
|
19
|
+
func initialize(
|
20
|
+
aid: String, resolver: @escaping RCTPromiseResolveBlock,
|
21
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
22
|
+
) {
|
22
23
|
moduleImpl?.initialize(aid: aid)
|
23
24
|
resolver(true)
|
24
25
|
}
|
@@ -26,51 +27,123 @@ class SdkPianoio: NSObject {
|
|
26
27
|
// MARK: - Configuration Methods
|
27
28
|
|
28
29
|
@objc(addTag:resolver:rejecter:)
|
29
|
-
func addTag(
|
30
|
+
func addTag(
|
31
|
+
tag: String, resolver: @escaping RCTPromiseResolveBlock,
|
32
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
33
|
+
) {
|
30
34
|
moduleImpl?.addTag(tag)
|
31
35
|
resolver(true)
|
32
36
|
}
|
33
37
|
|
34
38
|
@objc(addTags:resolver:rejecter:)
|
35
|
-
func addTags(
|
39
|
+
func addTags(
|
40
|
+
tags: [String], resolver: @escaping RCTPromiseResolveBlock,
|
41
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
42
|
+
) {
|
36
43
|
moduleImpl?.addTags(tags)
|
37
44
|
resolver(true)
|
38
45
|
}
|
39
46
|
|
40
47
|
@objc(setZoneId:resolver:rejecter:)
|
41
|
-
func setZoneId(
|
48
|
+
func setZoneId(
|
49
|
+
zoneId: String, resolver: @escaping RCTPromiseResolveBlock,
|
50
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
51
|
+
) {
|
42
52
|
moduleImpl?.setZoneId(zoneId)
|
43
53
|
resolver(true)
|
44
54
|
}
|
45
55
|
|
46
56
|
@objc(setReferrer:resolver:rejecter:)
|
47
|
-
func setReferrer(
|
57
|
+
func setReferrer(
|
58
|
+
referrer: String, resolver: @escaping RCTPromiseResolveBlock,
|
59
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
60
|
+
) {
|
48
61
|
moduleImpl?.setReferrer(referrer)
|
49
62
|
resolver(true)
|
50
63
|
}
|
51
64
|
|
52
65
|
@objc(setUrl:resolver:rejecter:)
|
53
|
-
func setUrl(
|
66
|
+
func setUrl(
|
67
|
+
url: String, resolver: @escaping RCTPromiseResolveBlock,
|
68
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
69
|
+
) {
|
54
70
|
moduleImpl?.setUrl(url)
|
55
71
|
resolver(true)
|
56
72
|
}
|
57
73
|
|
58
74
|
@objc(setUserToken:resolver:rejecter:)
|
59
|
-
func setUserToken(
|
75
|
+
func setUserToken(
|
76
|
+
token: String, resolver: @escaping RCTPromiseResolveBlock,
|
77
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
78
|
+
) {
|
60
79
|
moduleImpl?.setUserToken(token)
|
61
80
|
resolver(true)
|
62
81
|
}
|
63
82
|
|
64
|
-
@objc(
|
65
|
-
func
|
66
|
-
|
83
|
+
@objc(addCustomVariable:value:resolver:rejecter:)
|
84
|
+
func addCustomVariable(
|
85
|
+
name: String, value: String, resolver: @escaping RCTPromiseResolveBlock,
|
86
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
87
|
+
) {
|
88
|
+
moduleImpl?.addCustomVariable(name, value: value)
|
89
|
+
resolver(true)
|
90
|
+
}
|
91
|
+
|
92
|
+
@objc(setCustomVariables:resolver:rejecter:)
|
93
|
+
func setCustomVariables(
|
94
|
+
variables: [String: String], resolver: @escaping RCTPromiseResolveBlock,
|
95
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
96
|
+
) {
|
97
|
+
moduleImpl.setCustomVariables(variables)
|
67
98
|
resolver(true)
|
68
99
|
}
|
69
100
|
|
70
101
|
// MARK: - Execution Method
|
71
102
|
|
72
103
|
@objc(executeExperience:rejecter:)
|
73
|
-
func executeExperience(
|
104
|
+
func executeExperience(
|
105
|
+
resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
|
106
|
+
) {
|
74
107
|
moduleImpl?.executeExperience(resolver: resolver, rejecter: rejecter)
|
75
108
|
}
|
109
|
+
|
110
|
+
// MARK: - Authentication Methods
|
111
|
+
|
112
|
+
@objc(signIn:rejecter:)
|
113
|
+
func signIn(
|
114
|
+
resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
|
115
|
+
) {
|
116
|
+
moduleImpl.signIn(resolver: resolver, rejecter: rejecter)
|
117
|
+
}
|
118
|
+
|
119
|
+
@objc(signOut:rejecter:)
|
120
|
+
func signOut(
|
121
|
+
resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
|
122
|
+
) {
|
123
|
+
moduleImpl.signOut(resolver: resolver, rejecter: rejecter)
|
124
|
+
}
|
125
|
+
|
126
|
+
@objc(getCurrentUser:rejecter:)
|
127
|
+
func getCurrentUser(
|
128
|
+
resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
|
129
|
+
) {
|
130
|
+
moduleImpl.getCurrentUser(resolver: resolver, rejecter: rejecter)
|
131
|
+
}
|
132
|
+
|
133
|
+
@objc(isAuthenticated:rejecter:)
|
134
|
+
func isAuthenticated(
|
135
|
+
resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
|
136
|
+
) {
|
137
|
+
moduleImpl.isAuthenticated(resolver: resolver, rejecter: rejecter)
|
138
|
+
}
|
139
|
+
|
140
|
+
// MARK: - Helper and Cleanup Methods
|
141
|
+
|
142
|
+
@objc(clearConfiguration:rejecter:)
|
143
|
+
func clearConfiguration(
|
144
|
+
resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
|
145
|
+
) {
|
146
|
+
moduleImpl.clearConfiguration()
|
147
|
+
resolver(true)
|
148
|
+
}
|
76
149
|
}
|
package/ios/SdkPianoioBridge.m
CHANGED
@@ -35,19 +35,37 @@ RCT_EXTERN_METHOD(setUserToken:(NSString *)token
|
|
35
35
|
resolver:(RCTPromiseResolveBlock)resolve
|
36
36
|
rejecter:(RCTPromiseRejectBlock)reject)
|
37
37
|
|
38
|
-
RCT_EXTERN_METHOD(
|
38
|
+
RCT_EXTERN_METHOD(addCustomVariable:(NSString *)name
|
39
39
|
value:(NSString *)value
|
40
40
|
resolver:(RCTPromiseResolveBlock)resolve
|
41
41
|
rejecter:(RCTPromiseRejectBlock)reject)
|
42
42
|
|
43
|
+
RCT_EXTERN_METHOD(setCustomVariables:(NSDictionary *)variables
|
44
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
45
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
46
|
+
|
43
47
|
// MARK: - Execution Method
|
44
48
|
|
45
49
|
RCT_EXTERN_METHOD(executeExperience:(RCTPromiseResolveBlock)resolve
|
46
50
|
rejecter:(RCTPromiseRejectBlock)reject)
|
47
51
|
|
48
|
-
//
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
+
// MARK: - Authentication Methods
|
53
|
+
|
54
|
+
RCT_EXTERN_METHOD(signIn:(RCTPromiseResolveBlock)resolve
|
55
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
56
|
+
|
57
|
+
RCT_EXTERN_METHOD(signOut:(RCTPromiseResolveBlock)resolve
|
58
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
59
|
+
|
60
|
+
RCT_EXTERN_METHOD(getCurrentUser:(RCTPromiseResolveBlock)resolve
|
61
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
62
|
+
|
63
|
+
RCT_EXTERN_METHOD(isAuthenticated:(RCTPromiseResolveBlock)resolve
|
64
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
65
|
+
|
66
|
+
// MARK: - Helper and Cleanup Methods
|
67
|
+
|
68
|
+
RCT_EXTERN_METHOD(clearConfiguration:(RCTPromiseResolveBlock)resolve
|
69
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
52
70
|
|
53
71
|
@end
|
package/ios/TokenService.swift
CHANGED
@@ -16,7 +16,7 @@ public class User {
|
|
16
16
|
self.accessToken = accessToken
|
17
17
|
}
|
18
18
|
}
|
19
|
-
|
19
|
+
|
20
20
|
/**
|
21
21
|
* TokenService - Manages OAuth tokens and authentication with the Piano ID SDK.
|
22
22
|
*
|
@@ -40,11 +40,6 @@ public class TokenService: NSObject, PianoIDDelegate {
|
|
40
40
|
|
41
41
|
// MARK: - Initialization
|
42
42
|
|
43
|
-
/**
|
44
|
-
* Initializes the TokenService and configures the PianoID singleton.
|
45
|
-
*
|
46
|
-
* @param aid The Piano Application ID.
|
47
|
-
*/
|
48
43
|
public func initialize(aid: String) {
|
49
44
|
if isInitialized {
|
50
45
|
return
|
@@ -61,12 +56,8 @@ public class TokenService: NSObject, PianoIDDelegate {
|
|
61
56
|
|
62
57
|
// MARK: - Authentication Methods
|
63
58
|
|
64
|
-
|
65
|
-
|
66
|
-
*
|
67
|
-
* @param resolver The promise resolver from React Native.
|
68
|
-
* @param rejecter The promise rejecter from React Native.
|
69
|
-
*/
|
59
|
+
// Missing set tokens no?
|
60
|
+
|
70
61
|
public func signIn(resolver: @escaping (Any?) -> Void, rejecter: @escaping (String?, String?, Error?) -> Void) {
|
71
62
|
if !isInitialized {
|
72
63
|
print("TokenService: Not initialized. Call initialize() first.")
|
@@ -79,12 +70,7 @@ public class TokenService: NSObject, PianoIDDelegate {
|
|
79
70
|
PianoID.shared.signIn()
|
80
71
|
}
|
81
72
|
|
82
|
-
|
83
|
-
* Starts the sign-out process.
|
84
|
-
*
|
85
|
-
* @param resolver The promise resolver from React Native.
|
86
|
-
* @param rejecter The promise rejecter from React Native.
|
87
|
-
*/
|
73
|
+
|
88
74
|
public func signOut(resolver: @escaping (Any?) -> Void, rejecter: @escaping (String?, String?, Error?) -> Void) {
|
89
75
|
if !isInitialized {
|
90
76
|
print("TokenService: Not initialized.")
|
@@ -105,11 +91,6 @@ public class TokenService: NSObject, PianoIDDelegate {
|
|
105
91
|
|
106
92
|
// MARK: - User Information Methods
|
107
93
|
|
108
|
-
/**
|
109
|
-
* Gets the current user's information.
|
110
|
-
*
|
111
|
-
* @return A User object if authenticated, otherwise null.
|
112
|
-
*/
|
113
94
|
public func getCurrentUser() -> User? {
|
114
95
|
guard let token = self.cachedToken else {
|
115
96
|
return nil
|
@@ -129,11 +110,6 @@ public class TokenService: NSObject, PianoIDDelegate {
|
|
129
110
|
)
|
130
111
|
}
|
131
112
|
|
132
|
-
/**
|
133
|
-
* Checks if a user is currently authenticated.
|
134
|
-
*
|
135
|
-
* @return true if a valid token exists, false otherwise.
|
136
|
-
*/
|
137
113
|
public func isAuthenticated() -> Bool {
|
138
114
|
return self.cachedToken != nil
|
139
115
|
}
|
@@ -157,7 +133,7 @@ public class TokenService: NSObject, PianoIDDelegate {
|
|
157
133
|
print("TokenService: Sign in failed: \(e.localizedDescription)")
|
158
134
|
self.signInRejecter?("SIGNIN_ERROR", e.localizedDescription, e)
|
159
135
|
}
|
160
|
-
|
136
|
+
|
161
137
|
self.signInResolver = nil
|
162
138
|
self.signInRejecter = nil
|
163
139
|
}
|
@@ -188,12 +164,6 @@ public class TokenService: NSObject, PianoIDDelegate {
|
|
188
164
|
|
189
165
|
// MARK: - Helper Methods
|
190
166
|
|
191
|
-
/**
|
192
|
-
* Decodes the payload of a JWT.
|
193
|
-
*
|
194
|
-
* @param jwt The JSON Web Token string.
|
195
|
-
* @return A dictionary of claims, or nil if decoding fails.
|
196
|
-
*/
|
197
167
|
private func decode(jwtToken jwt: String) -> [String: Any]? {
|
198
168
|
let segments = jwt.components(separatedBy: ".")
|
199
169
|
guard segments.count > 1 else {
|