@capawesome/capacitor-age-signals 0.3.0 โ 0.3.2
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 +246 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/agesignals/AgeSignals.java +58 -1
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/agesignals/AgeSignalsPlugin.java +86 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/agesignals/classes/CustomExceptions.java +2 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/agesignals/classes/options/SetNextAgeSignalsExceptionOptions.java +53 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/agesignals/classes/options/SetNextAgeSignalsResultOptions.java +109 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/agesignals/classes/options/SetUseFakeManagerOptions.java +16 -0
- package/dist/docs.json +386 -0
- package/dist/esm/definitions.d.ts +119 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +5 -1
- package/dist/esm/web.js +12 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +12 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +12 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/AgeSignals.swift +20 -0
- package/ios/Plugin/AgeSignalsPlugin.swift +12 -1
- package/ios/Plugin/Classes/Results/CheckEligibilityResult.swift +16 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,20 @@ Capacitor plugin to use the [Play Age Signals API](https://developer.android.com
|
|
|
12
12
|
|
|
13
13
|
The **Play Age Signals API** is returning "Not yet implemented" because its live functionality is scheduled to begin on January 1, 2026.
|
|
14
14
|
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
We are proud to offer one of the most complete and feature-rich Capacitor plugins for age verification. Here are some of the key features:
|
|
18
|
+
|
|
19
|
+
- ๐ฅ๏ธ **Cross-platform**: Supports Android and iOS.
|
|
20
|
+
- ๐ **Age Verification**: Request user age signals using Play Age Signals API (Android) and DeclaredAgeRange (iOS).
|
|
21
|
+
- ๐จโ๐ฉโ๐งโ๐ฆ **Parental Controls**: Support for supervised accounts with parental approval status.
|
|
22
|
+
- ๐งช **Testing Support**: Built-in `FakeAgeSignalsManager` integration for testing different age verification scenarios (Android).
|
|
23
|
+
- ๐ **Compliance Ready**: Built for US state age verification requirements (effective January 1, 2026).
|
|
24
|
+
- ๐ฆ **SPM**: Supports Swift Package Manager for iOS.
|
|
25
|
+
- ๐ **Up-to-date**: Always supports the latest Capacitor version.
|
|
26
|
+
|
|
27
|
+
Missing a feature? Just [open an issue](https://github.com/capawesome-team/capacitor-plugins/issues) and we'll take a look!
|
|
28
|
+
|
|
15
29
|
## Compatibility
|
|
16
30
|
|
|
17
31
|
| Plugin Version | Capacitor Version | Status |
|
|
@@ -36,6 +50,8 @@ If needed, you can define the following project variable in your app's `variable
|
|
|
36
50
|
|
|
37
51
|
This can be useful if you encounter dependency conflicts with other plugins in your project.
|
|
38
52
|
|
|
53
|
+
**Note**: The `FakeAgeSignalsManager` testing API is included in the main `age-signals` library, so no additional dependency is required for testing.
|
|
54
|
+
|
|
39
55
|
### iOS
|
|
40
56
|
|
|
41
57
|
#### Entitlements
|
|
@@ -64,6 +80,110 @@ const checkAgeSignals = async () => {
|
|
|
64
80
|
console.log('Age Lower:', result.ageLower);
|
|
65
81
|
console.log('Age Upper:', result.ageUpper);
|
|
66
82
|
};
|
|
83
|
+
|
|
84
|
+
const checkEligibility = async () => {
|
|
85
|
+
const result = await AgeSignals.checkEligibility();
|
|
86
|
+
console.log('Is Eligible:', result.isEligible);
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Testing
|
|
91
|
+
|
|
92
|
+
The plugin includes support for the `FakeAgeSignalsManager` API on Android, which allows you to simulate different age signals scenarios in your tests without requiring live responses from Google Play.
|
|
93
|
+
|
|
94
|
+
### Android Testing
|
|
95
|
+
|
|
96
|
+
**Important**: Due to a known issue in versions 0.0.1 and 0.0.2 of the Age Signals API, you may encounter a `java.lang.VerifyError` when calling the builder method of `AgeSignalsResult` in unit tests. As a workaround, run your tests as Android instrumented tests within the `androidTest` source set.
|
|
97
|
+
|
|
98
|
+
#### Example: Testing a Verified Adult User
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { AgeSignals, UserStatus } from '@capawesome/capacitor-age-signals';
|
|
102
|
+
|
|
103
|
+
// Enable the fake manager
|
|
104
|
+
await AgeSignals.setUseFakeManager({ useFake: true });
|
|
105
|
+
|
|
106
|
+
// Set up a verified adult user
|
|
107
|
+
await AgeSignals.setNextAgeSignalsResult({
|
|
108
|
+
userStatus: UserStatus.Verified,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Check age signals - will return the fake result
|
|
112
|
+
const result = await AgeSignals.checkAgeSignals();
|
|
113
|
+
console.log(result.userStatus); // 'VERIFIED'
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Example: Testing a Supervised User (13-17 years old)
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { AgeSignals, UserStatus } from '@capawesome/capacitor-age-signals';
|
|
120
|
+
|
|
121
|
+
await AgeSignals.setUseFakeManager({ useFake: true });
|
|
122
|
+
|
|
123
|
+
await AgeSignals.setNextAgeSignalsResult({
|
|
124
|
+
userStatus: UserStatus.Supervised,
|
|
125
|
+
ageLower: 13,
|
|
126
|
+
ageUpper: 17,
|
|
127
|
+
installId: 'fake_install_id',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const result = await AgeSignals.checkAgeSignals();
|
|
131
|
+
console.log(result.userStatus); // 'SUPERVISED'
|
|
132
|
+
console.log(result.ageLower); // 13
|
|
133
|
+
console.log(result.ageUpper); // 17
|
|
134
|
+
console.log(result.installId); // 'fake_install_id'
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Example: Testing Parental Approval Scenarios
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { AgeSignals, UserStatus } from '@capawesome/capacitor-age-signals';
|
|
141
|
+
|
|
142
|
+
await AgeSignals.setUseFakeManager({ useFake: true });
|
|
143
|
+
|
|
144
|
+
// Test pending approval
|
|
145
|
+
await AgeSignals.setNextAgeSignalsResult({
|
|
146
|
+
userStatus: UserStatus.SupervisedApprovalPending,
|
|
147
|
+
ageLower: 13,
|
|
148
|
+
ageUpper: 17,
|
|
149
|
+
mostRecentApprovalDate: '2025-02-01',
|
|
150
|
+
installId: 'fake_install_id',
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const result = await AgeSignals.checkAgeSignals();
|
|
154
|
+
console.log(result.userStatus); // 'SUPERVISED_APPROVAL_PENDING'
|
|
155
|
+
console.log(result.mostRecentApprovalDate); // '2025-02-01'
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### Example: Testing Error Scenarios
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { AgeSignals, ErrorCode } from '@capawesome/capacitor-age-signals';
|
|
162
|
+
|
|
163
|
+
await AgeSignals.setUseFakeManager({ useFake: true });
|
|
164
|
+
|
|
165
|
+
// Simulate a network error
|
|
166
|
+
await AgeSignals.setNextAgeSignalsException({
|
|
167
|
+
errorCode: ErrorCode.NetworkError,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
await AgeSignals.checkAgeSignals();
|
|
172
|
+
} catch (error) {
|
|
173
|
+
console.log('Caught network error:', error);
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Disabling the Fake Manager
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { AgeSignals } from '@capawesome/capacitor-age-signals';
|
|
181
|
+
|
|
182
|
+
// Switch back to the production manager
|
|
183
|
+
await AgeSignals.setUseFakeManager({ useFake: false });
|
|
184
|
+
|
|
185
|
+
// This will now use the real Age Signals API
|
|
186
|
+
const result = await AgeSignals.checkAgeSignals();
|
|
67
187
|
```
|
|
68
188
|
|
|
69
189
|
## API
|
|
@@ -71,6 +191,10 @@ const checkAgeSignals = async () => {
|
|
|
71
191
|
<docgen-index>
|
|
72
192
|
|
|
73
193
|
* [`checkAgeSignals(...)`](#checkagesignals)
|
|
194
|
+
* [`checkEligibility()`](#checkeligibility)
|
|
195
|
+
* [`setUseFakeManager(...)`](#setusefakemanager)
|
|
196
|
+
* [`setNextAgeSignalsResult(...)`](#setnextagesignalsresult)
|
|
197
|
+
* [`setNextAgeSignalsException(...)`](#setnextagesignalsexception)
|
|
74
198
|
* [Interfaces](#interfaces)
|
|
75
199
|
* [Enums](#enums)
|
|
76
200
|
|
|
@@ -98,6 +222,80 @@ Request the user's age signals.
|
|
|
98
222
|
--------------------
|
|
99
223
|
|
|
100
224
|
|
|
225
|
+
### checkEligibility()
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
checkEligibility() => Promise<CheckEligibilityResult>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Check if the user is eligible for age-gated features.
|
|
232
|
+
|
|
233
|
+
Only available on iOS.
|
|
234
|
+
|
|
235
|
+
**Returns:** <code>Promise<<a href="#checkeligibilityresult">CheckEligibilityResult</a>></code>
|
|
236
|
+
|
|
237
|
+
**Since:** 0.3.1
|
|
238
|
+
|
|
239
|
+
--------------------
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
### setUseFakeManager(...)
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
setUseFakeManager(options: SetUseFakeManagerOptions) => Promise<void>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Enable or disable the fake age signals manager for testing.
|
|
249
|
+
|
|
250
|
+
Only available on Android.
|
|
251
|
+
|
|
252
|
+
| Param | Type |
|
|
253
|
+
| ------------- | ----------------------------------------------------------------------------- |
|
|
254
|
+
| **`options`** | <code><a href="#setusefakemanageroptions">SetUseFakeManagerOptions</a></code> |
|
|
255
|
+
|
|
256
|
+
**Since:** 0.3.1
|
|
257
|
+
|
|
258
|
+
--------------------
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
### setNextAgeSignalsResult(...)
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
setNextAgeSignalsResult(options: SetNextAgeSignalsResultOptions) => Promise<void>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Set the next age signals result to be returned by the fake manager.
|
|
268
|
+
|
|
269
|
+
Only available on Android.
|
|
270
|
+
|
|
271
|
+
| Param | Type |
|
|
272
|
+
| ------------- | ----------------------------------------------------------------------------------------- |
|
|
273
|
+
| **`options`** | <code><a href="#setnextagesignalsresultoptions">SetNextAgeSignalsResultOptions</a></code> |
|
|
274
|
+
|
|
275
|
+
**Since:** 0.3.1
|
|
276
|
+
|
|
277
|
+
--------------------
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
### setNextAgeSignalsException(...)
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
setNextAgeSignalsException(options: SetNextAgeSignalsExceptionOptions) => Promise<void>
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Set the next exception to be thrown by the fake manager.
|
|
287
|
+
|
|
288
|
+
Only available on Android.
|
|
289
|
+
|
|
290
|
+
| Param | Type |
|
|
291
|
+
| ------------- | ----------------------------------------------------------------------------------------------- |
|
|
292
|
+
| **`options`** | <code><a href="#setnextagesignalsexceptionoptions">SetNextAgeSignalsExceptionOptions</a></code> |
|
|
293
|
+
|
|
294
|
+
**Since:** 0.3.1
|
|
295
|
+
|
|
296
|
+
--------------------
|
|
297
|
+
|
|
298
|
+
|
|
101
299
|
### Interfaces
|
|
102
300
|
|
|
103
301
|
|
|
@@ -119,6 +317,38 @@ Request the user's age signals.
|
|
|
119
317
|
| **`ageGates`** | <code>number[]</code> | The age ranges that the user falls into. The provided array must contain at least 2 and at most 3 ages. Only available on iOS. | <code>[13, 15, 18]</code> | 0.0.2 |
|
|
120
318
|
|
|
121
319
|
|
|
320
|
+
#### CheckEligibilityResult
|
|
321
|
+
|
|
322
|
+
| Prop | Type | Description | Since |
|
|
323
|
+
| ---------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
324
|
+
| **`isEligible`** | <code>boolean</code> | Whether the user is eligible for age-gated features. Returns `true` if the user is in an applicable region that requires additional age-related obligations. Always returns `false` on macOS. | 0.3.1 |
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
#### SetUseFakeManagerOptions
|
|
328
|
+
|
|
329
|
+
| Prop | Type | Description | Default | Since |
|
|
330
|
+
| ------------- | -------------------- | -------------------------------------------------------- | ------------------ | ----- |
|
|
331
|
+
| **`useFake`** | <code>boolean</code> | Whether to use the fake age signals manager for testing. | <code>false</code> | 0.3.1 |
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
#### SetNextAgeSignalsResultOptions
|
|
335
|
+
|
|
336
|
+
| Prop | Type | Description | Since |
|
|
337
|
+
| ---------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
338
|
+
| **`userStatus`** | <code><a href="#userstatus">UserStatus</a></code> | The user's verification status. | 0.3.1 |
|
|
339
|
+
| **`ageLower`** | <code>number</code> | The (inclusive) lower bound of a supervised user's age range. Only available when `userStatus` is `SUPERVISED`, `SUPERVISED_APPROVAL_PENDING`, or `SUPERVISED_APPROVAL_DENIED`. | 0.3.1 |
|
|
340
|
+
| **`ageUpper`** | <code>number</code> | The (inclusive) upper bound of a supervised user's age range. Only available when `userStatus` is `SUPERVISED`, `SUPERVISED_APPROVAL_PENDING`, or `SUPERVISED_APPROVAL_DENIED` and the user's age is under 18. | 0.3.1 |
|
|
341
|
+
| **`mostRecentApprovalDate`** | <code>string</code> | The effective from date of the most recent significant change that was approved. When an app is installed, the date of the most recent significant change prior to install is used. Only available when `userStatus` is `SUPERVISED_APPROVAL_PENDING` or `SUPERVISED_APPROVAL_DENIED`. | 0.3.1 |
|
|
342
|
+
| **`installId`** | <code>string</code> | An ID assigned to supervised user installs by Google Play, used for the purposes of notifying you of revoked app approval. Only available when `userStatus` is `SUPERVISED`, `SUPERVISED_APPROVAL_PENDING`, or `SUPERVISED_APPROVAL_DENIED`. | 0.3.1 |
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
#### SetNextAgeSignalsExceptionOptions
|
|
346
|
+
|
|
347
|
+
| Prop | Type | Description | Since |
|
|
348
|
+
| --------------- | ----------------------------------------------- | ------------------------------------------------ | ----- |
|
|
349
|
+
| **`errorCode`** | <code><a href="#errorcode">ErrorCode</a></code> | The error code to be thrown by the fake manager. | 0.3.1 |
|
|
350
|
+
|
|
351
|
+
|
|
122
352
|
### Enums
|
|
123
353
|
|
|
124
354
|
|
|
@@ -133,6 +363,22 @@ Request the user's age signals.
|
|
|
133
363
|
| **`Unknown`** | <code>'UNKNOWN'</code> | The user is not verified or supervised in applicable jurisdictions and regions. These users could be over or under 18. To obtain an age signal from Google Play, ask the user to visit the Play Store to resolve their status. | 0.0.1 |
|
|
134
364
|
| **`Empty`** | <code>'EMPTY'</code> | All other users return this value. | 0.0.1 |
|
|
135
365
|
|
|
366
|
+
|
|
367
|
+
#### ErrorCode
|
|
368
|
+
|
|
369
|
+
| Members | Value | Description | Since |
|
|
370
|
+
| --------------------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
371
|
+
| **`ApiNotAvailable`** | <code>'API_NOT_AVAILABLE'</code> | The Play Age Signals API is not available. The Play Store app version installed on the device might be old. | 0.0.1 |
|
|
372
|
+
| **`PlayStoreNotFound`** | <code>'PLAY_STORE_NOT_FOUND'</code> | No Play Store app is found on the device. | 0.0.1 |
|
|
373
|
+
| **`NetworkError`** | <code>'NETWORK_ERROR'</code> | No available network is found. | 0.0.1 |
|
|
374
|
+
| **`PlayServicesNotFound`** | <code>'PLAY_SERVICES_NOT_FOUND'</code> | Play Services is not available or its version is too old. | 0.0.1 |
|
|
375
|
+
| **`CannotBindToService`** | <code>'CANNOT_BIND_TO_SERVICE'</code> | Binding to the service in the Play Store has failed. This can be due to having an old Play Store version installed on the device or device memory is overloaded. | 0.0.1 |
|
|
376
|
+
| **`PlayStoreVersionOutdated`** | <code>'PLAY_STORE_VERSION_OUTDATED'</code> | The Play Store app needs to be updated. | 0.0.1 |
|
|
377
|
+
| **`PlayServicesVersionOutdated`** | <code>'PLAY_SERVICES_VERSION_OUTDATED'</code> | Play Services needs to be updated. | 0.0.1 |
|
|
378
|
+
| **`ClientTransientError`** | <code>'CLIENT_TRANSIENT_ERROR'</code> | There was a transient error in the client device. | 0.0.1 |
|
|
379
|
+
| **`AppNotOwned`** | <code>'APP_NOT_OWNED'</code> | The app was not installed by Google Play. | 0.0.1 |
|
|
380
|
+
| **`InternalError`** | <code>'INTERNAL_ERROR'</code> | Unknown internal error. | 0.0.1 |
|
|
381
|
+
|
|
136
382
|
</docgen-api>
|
|
137
383
|
|
|
138
384
|
## Changelog
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
package io.capawesome.capacitorjs.plugins.agesignals;
|
|
2
2
|
|
|
3
3
|
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
4
5
|
import com.google.android.gms.tasks.Task;
|
|
5
6
|
import com.google.android.play.agesignals.AgeSignalsManager;
|
|
6
7
|
import com.google.android.play.agesignals.AgeSignalsManagerFactory;
|
|
7
8
|
import com.google.android.play.agesignals.AgeSignalsRequest;
|
|
8
9
|
import com.google.android.play.agesignals.AgeSignalsResult;
|
|
10
|
+
import com.google.android.play.agesignals.testing.FakeAgeSignalsManager;
|
|
9
11
|
import io.capawesome.capacitorjs.plugins.agesignals.classes.CustomExceptions;
|
|
12
|
+
import io.capawesome.capacitorjs.plugins.agesignals.classes.options.SetNextAgeSignalsExceptionOptions;
|
|
13
|
+
import io.capawesome.capacitorjs.plugins.agesignals.classes.options.SetNextAgeSignalsResultOptions;
|
|
14
|
+
import io.capawesome.capacitorjs.plugins.agesignals.classes.options.SetUseFakeManagerOptions;
|
|
10
15
|
import io.capawesome.capacitorjs.plugins.agesignals.classes.results.CheckAgeSignalsResult;
|
|
16
|
+
import io.capawesome.capacitorjs.plugins.agesignals.interfaces.EmptyCallback;
|
|
11
17
|
import io.capawesome.capacitorjs.plugins.agesignals.interfaces.NonEmptyResultCallback;
|
|
12
18
|
|
|
13
19
|
public class AgeSignals {
|
|
@@ -15,12 +21,23 @@ public class AgeSignals {
|
|
|
15
21
|
@NonNull
|
|
16
22
|
private final AgeSignalsPlugin plugin;
|
|
17
23
|
|
|
24
|
+
private boolean useFakeManager = false;
|
|
25
|
+
|
|
26
|
+
@Nullable
|
|
27
|
+
private FakeAgeSignalsManager fakeManager = null;
|
|
28
|
+
|
|
18
29
|
public AgeSignals(@NonNull AgeSignalsPlugin plugin) {
|
|
19
30
|
this.plugin = plugin;
|
|
20
31
|
}
|
|
21
32
|
|
|
22
33
|
public void checkAgeSignals(@NonNull NonEmptyResultCallback<CheckAgeSignalsResult> callback) {
|
|
23
|
-
AgeSignalsManager manager
|
|
34
|
+
AgeSignalsManager manager;
|
|
35
|
+
if (useFakeManager && fakeManager != null) {
|
|
36
|
+
manager = fakeManager;
|
|
37
|
+
} else {
|
|
38
|
+
manager = AgeSignalsManagerFactory.create(plugin.getActivity());
|
|
39
|
+
}
|
|
40
|
+
|
|
24
41
|
AgeSignalsRequest request = AgeSignalsRequest.builder().build();
|
|
25
42
|
|
|
26
43
|
Task<AgeSignalsResult> task = manager.checkAgeSignals(request);
|
|
@@ -38,6 +55,46 @@ public class AgeSignals {
|
|
|
38
55
|
});
|
|
39
56
|
}
|
|
40
57
|
|
|
58
|
+
public void setUseFakeManager(@NonNull SetUseFakeManagerOptions options, @NonNull EmptyCallback callback) {
|
|
59
|
+
try {
|
|
60
|
+
this.useFakeManager = options.getUseFake();
|
|
61
|
+
if (this.useFakeManager) {
|
|
62
|
+
this.fakeManager = new FakeAgeSignalsManager();
|
|
63
|
+
} else {
|
|
64
|
+
this.fakeManager = null;
|
|
65
|
+
}
|
|
66
|
+
callback.success();
|
|
67
|
+
} catch (Exception exception) {
|
|
68
|
+
callback.error(exception);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public void setNextAgeSignalsResult(@NonNull SetNextAgeSignalsResultOptions options, @NonNull EmptyCallback callback) {
|
|
73
|
+
try {
|
|
74
|
+
if (!useFakeManager || fakeManager == null) {
|
|
75
|
+
throw CustomExceptions.FAKE_MANAGER_NOT_ENABLED;
|
|
76
|
+
}
|
|
77
|
+
com.google.android.play.agesignals.AgeSignalsResult result = options.buildAgeSignalsResult();
|
|
78
|
+
fakeManager.setNextAgeSignalsResult(result);
|
|
79
|
+
callback.success();
|
|
80
|
+
} catch (Exception exception) {
|
|
81
|
+
callback.error(exception);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public void setNextAgeSignalsException(@NonNull SetNextAgeSignalsExceptionOptions options, @NonNull EmptyCallback callback) {
|
|
86
|
+
try {
|
|
87
|
+
if (!useFakeManager || fakeManager == null) {
|
|
88
|
+
throw CustomExceptions.FAKE_MANAGER_NOT_ENABLED;
|
|
89
|
+
}
|
|
90
|
+
com.google.android.play.agesignals.AgeSignalsException exception = options.buildAgeSignalsException();
|
|
91
|
+
fakeManager.setNextAgeSignalsException(exception);
|
|
92
|
+
callback.success();
|
|
93
|
+
} catch (Exception exception) {
|
|
94
|
+
callback.error(exception);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
41
98
|
@NonNull
|
|
42
99
|
private Exception mapErrorCodeToException(@NonNull Exception exception) {
|
|
43
100
|
if (!(exception instanceof com.google.android.gms.common.api.ApiException)) {
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/agesignals/AgeSignalsPlugin.java
CHANGED
|
@@ -8,7 +8,11 @@ import com.getcapacitor.Plugin;
|
|
|
8
8
|
import com.getcapacitor.PluginCall;
|
|
9
9
|
import com.getcapacitor.PluginMethod;
|
|
10
10
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
11
|
+
import io.capawesome.capacitorjs.plugins.agesignals.classes.options.SetNextAgeSignalsExceptionOptions;
|
|
12
|
+
import io.capawesome.capacitorjs.plugins.agesignals.classes.options.SetNextAgeSignalsResultOptions;
|
|
13
|
+
import io.capawesome.capacitorjs.plugins.agesignals.classes.options.SetUseFakeManagerOptions;
|
|
11
14
|
import io.capawesome.capacitorjs.plugins.agesignals.classes.results.CheckAgeSignalsResult;
|
|
15
|
+
import io.capawesome.capacitorjs.plugins.agesignals.interfaces.EmptyCallback;
|
|
12
16
|
import io.capawesome.capacitorjs.plugins.agesignals.interfaces.NonEmptyResultCallback;
|
|
13
17
|
import io.capawesome.capacitorjs.plugins.agesignals.interfaces.Result;
|
|
14
18
|
|
|
@@ -50,6 +54,80 @@ public class AgeSignalsPlugin extends Plugin {
|
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
@PluginMethod
|
|
58
|
+
public void checkEligibility(PluginCall call) {
|
|
59
|
+
rejectCallAsUnimplemented(call);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@PluginMethod
|
|
63
|
+
public void setUseFakeManager(PluginCall call) {
|
|
64
|
+
try {
|
|
65
|
+
SetUseFakeManagerOptions options = new SetUseFakeManagerOptions(call);
|
|
66
|
+
EmptyCallback callback = new EmptyCallback() {
|
|
67
|
+
@Override
|
|
68
|
+
public void success() {
|
|
69
|
+
resolveCall(call);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@Override
|
|
73
|
+
public void error(@NonNull Exception exception) {
|
|
74
|
+
rejectCall(call, exception);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
assert implementation != null;
|
|
79
|
+
implementation.setUseFakeManager(options, callback);
|
|
80
|
+
} catch (Exception exception) {
|
|
81
|
+
rejectCall(call, exception);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@PluginMethod
|
|
86
|
+
public void setNextAgeSignalsResult(PluginCall call) {
|
|
87
|
+
try {
|
|
88
|
+
SetNextAgeSignalsResultOptions options = new SetNextAgeSignalsResultOptions(call);
|
|
89
|
+
EmptyCallback callback = new EmptyCallback() {
|
|
90
|
+
@Override
|
|
91
|
+
public void success() {
|
|
92
|
+
resolveCall(call);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@Override
|
|
96
|
+
public void error(@NonNull Exception exception) {
|
|
97
|
+
rejectCall(call, exception);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
assert implementation != null;
|
|
102
|
+
implementation.setNextAgeSignalsResult(options, callback);
|
|
103
|
+
} catch (Exception exception) {
|
|
104
|
+
rejectCall(call, exception);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@PluginMethod
|
|
109
|
+
public void setNextAgeSignalsException(PluginCall call) {
|
|
110
|
+
try {
|
|
111
|
+
SetNextAgeSignalsExceptionOptions options = new SetNextAgeSignalsExceptionOptions(call);
|
|
112
|
+
EmptyCallback callback = new EmptyCallback() {
|
|
113
|
+
@Override
|
|
114
|
+
public void success() {
|
|
115
|
+
resolveCall(call);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@Override
|
|
119
|
+
public void error(@NonNull Exception exception) {
|
|
120
|
+
rejectCall(call, exception);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
assert implementation != null;
|
|
125
|
+
implementation.setNextAgeSignalsException(options, callback);
|
|
126
|
+
} catch (Exception exception) {
|
|
127
|
+
rejectCall(call, exception);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
53
131
|
private void rejectCall(@NonNull PluginCall call, @NonNull Exception exception) {
|
|
54
132
|
String message = exception.getMessage();
|
|
55
133
|
if (message == null) {
|
|
@@ -59,6 +137,14 @@ public class AgeSignalsPlugin extends Plugin {
|
|
|
59
137
|
call.reject(message);
|
|
60
138
|
}
|
|
61
139
|
|
|
140
|
+
private void rejectCallAsUnimplemented(@NonNull PluginCall call) {
|
|
141
|
+
call.unimplemented("This method is not available on this platform.");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private void resolveCall(@NonNull PluginCall call) {
|
|
145
|
+
call.resolve();
|
|
146
|
+
}
|
|
147
|
+
|
|
62
148
|
private void resolveCall(@NonNull PluginCall call, @Nullable Result result) {
|
|
63
149
|
if (result == null) {
|
|
64
150
|
call.resolve();
|
|
@@ -33,4 +33,6 @@ public class CustomExceptions {
|
|
|
33
33
|
);
|
|
34
34
|
public static final CustomException APP_NOT_OWNED = new CustomException("APP_NOT_OWNED", "The app was not installed by Google Play.");
|
|
35
35
|
public static final CustomException INTERNAL_ERROR = new CustomException("INTERNAL_ERROR", "Unknown internal error.");
|
|
36
|
+
public static final CustomException USER_STATUS_MISSING = new CustomException(null, "userStatus must be provided.");
|
|
37
|
+
public static final CustomException FAKE_MANAGER_NOT_ENABLED = new CustomException(null, "Fake manager is not enabled.");
|
|
36
38
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.agesignals.classes.options;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import com.getcapacitor.PluginCall;
|
|
5
|
+
import com.google.android.play.agesignals.AgeSignalsException;
|
|
6
|
+
import com.google.android.play.agesignals.model.AgeSignalsErrorCode;
|
|
7
|
+
|
|
8
|
+
public class SetNextAgeSignalsExceptionOptions {
|
|
9
|
+
|
|
10
|
+
@NonNull
|
|
11
|
+
private final String errorCode;
|
|
12
|
+
|
|
13
|
+
public SetNextAgeSignalsExceptionOptions(@NonNull PluginCall call) throws Exception {
|
|
14
|
+
String errorCode = call.getString("errorCode");
|
|
15
|
+
if (errorCode == null) {
|
|
16
|
+
throw new Exception("errorCode must be provided.");
|
|
17
|
+
}
|
|
18
|
+
this.errorCode = errorCode;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@NonNull
|
|
22
|
+
public AgeSignalsException buildAgeSignalsException() throws Exception {
|
|
23
|
+
int errorCodeInt = mapErrorCodeToAgeSignalsErrorCode(this.errorCode);
|
|
24
|
+
return new AgeSignalsException(errorCodeInt);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private int mapErrorCodeToAgeSignalsErrorCode(@NonNull String errorCode) throws Exception {
|
|
28
|
+
switch (errorCode) {
|
|
29
|
+
case "API_NOT_AVAILABLE":
|
|
30
|
+
return AgeSignalsErrorCode.API_NOT_AVAILABLE;
|
|
31
|
+
case "PLAY_STORE_NOT_FOUND":
|
|
32
|
+
return AgeSignalsErrorCode.PLAY_STORE_NOT_FOUND;
|
|
33
|
+
case "NETWORK_ERROR":
|
|
34
|
+
return AgeSignalsErrorCode.NETWORK_ERROR;
|
|
35
|
+
case "PLAY_SERVICES_NOT_FOUND":
|
|
36
|
+
return AgeSignalsErrorCode.PLAY_SERVICES_NOT_FOUND;
|
|
37
|
+
case "CANNOT_BIND_TO_SERVICE":
|
|
38
|
+
return AgeSignalsErrorCode.CANNOT_BIND_TO_SERVICE;
|
|
39
|
+
case "PLAY_STORE_VERSION_OUTDATED":
|
|
40
|
+
return AgeSignalsErrorCode.PLAY_STORE_VERSION_OUTDATED;
|
|
41
|
+
case "PLAY_SERVICES_VERSION_OUTDATED":
|
|
42
|
+
return AgeSignalsErrorCode.PLAY_SERVICES_VERSION_OUTDATED;
|
|
43
|
+
case "CLIENT_TRANSIENT_ERROR":
|
|
44
|
+
return AgeSignalsErrorCode.CLIENT_TRANSIENT_ERROR;
|
|
45
|
+
case "APP_NOT_OWNED":
|
|
46
|
+
return AgeSignalsErrorCode.APP_NOT_OWNED;
|
|
47
|
+
case "INTERNAL_ERROR":
|
|
48
|
+
return AgeSignalsErrorCode.INTERNAL_ERROR;
|
|
49
|
+
default:
|
|
50
|
+
throw new Exception("Invalid errorCode: " + errorCode);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.agesignals.classes.options;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
import com.getcapacitor.PluginCall;
|
|
6
|
+
import com.google.android.play.agesignals.AgeSignalsResult;
|
|
7
|
+
import com.google.android.play.agesignals.model.AgeSignalsVerificationStatus;
|
|
8
|
+
import io.capawesome.capacitorjs.plugins.agesignals.classes.CustomExceptions;
|
|
9
|
+
import io.capawesome.capacitorjs.plugins.agesignals.enums.UserStatus;
|
|
10
|
+
import java.text.SimpleDateFormat;
|
|
11
|
+
import java.util.Date;
|
|
12
|
+
import java.util.Locale;
|
|
13
|
+
|
|
14
|
+
public class SetNextAgeSignalsResultOptions {
|
|
15
|
+
|
|
16
|
+
@NonNull
|
|
17
|
+
private final UserStatus userStatus;
|
|
18
|
+
|
|
19
|
+
@Nullable
|
|
20
|
+
private final Integer ageLower;
|
|
21
|
+
|
|
22
|
+
@Nullable
|
|
23
|
+
private final Integer ageUpper;
|
|
24
|
+
|
|
25
|
+
@Nullable
|
|
26
|
+
private final String mostRecentApprovalDate;
|
|
27
|
+
|
|
28
|
+
@Nullable
|
|
29
|
+
private final String installId;
|
|
30
|
+
|
|
31
|
+
public SetNextAgeSignalsResultOptions(@NonNull PluginCall call) throws Exception {
|
|
32
|
+
this.userStatus = SetNextAgeSignalsResultOptions.getUserStatusFromCall(call);
|
|
33
|
+
this.ageLower = call.getInt("ageLower");
|
|
34
|
+
this.ageUpper = call.getInt("ageUpper");
|
|
35
|
+
this.mostRecentApprovalDate = call.getString("mostRecentApprovalDate");
|
|
36
|
+
this.installId = call.getString("installId");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@NonNull
|
|
40
|
+
public AgeSignalsResult buildAgeSignalsResult() throws Exception {
|
|
41
|
+
AgeSignalsResult.Builder builder = AgeSignalsResult.builder();
|
|
42
|
+
|
|
43
|
+
// Set user status as integer
|
|
44
|
+
Integer verificationStatus = mapUserStatusToVerificationStatus(this.userStatus);
|
|
45
|
+
builder.setUserStatus(verificationStatus);
|
|
46
|
+
|
|
47
|
+
// Set optional fields
|
|
48
|
+
if (this.ageLower != null) {
|
|
49
|
+
builder.setAgeLower(this.ageLower);
|
|
50
|
+
}
|
|
51
|
+
if (this.ageUpper != null) {
|
|
52
|
+
builder.setAgeUpper(this.ageUpper);
|
|
53
|
+
}
|
|
54
|
+
if (this.mostRecentApprovalDate != null) {
|
|
55
|
+
Date date = parseDateString(this.mostRecentApprovalDate);
|
|
56
|
+
builder.setMostRecentApprovalDate(date);
|
|
57
|
+
}
|
|
58
|
+
if (this.installId != null) {
|
|
59
|
+
builder.setInstallId(this.installId);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return builder.build();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@NonNull
|
|
66
|
+
private static UserStatus getUserStatusFromCall(@NonNull PluginCall call) throws Exception {
|
|
67
|
+
String userStatusString = call.getString("userStatus");
|
|
68
|
+
if (userStatusString == null) {
|
|
69
|
+
throw new Exception(CustomExceptions.USER_STATUS_MISSING.getMessage());
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
return UserStatus.valueOf(userStatusString);
|
|
73
|
+
} catch (IllegalArgumentException exception) {
|
|
74
|
+
throw new Exception("Invalid userStatus: " + userStatusString);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@NonNull
|
|
79
|
+
private Integer mapUserStatusToVerificationStatus(@NonNull UserStatus userStatus) {
|
|
80
|
+
switch (userStatus) {
|
|
81
|
+
case VERIFIED:
|
|
82
|
+
return AgeSignalsVerificationStatus.VERIFIED;
|
|
83
|
+
case SUPERVISED:
|
|
84
|
+
return AgeSignalsVerificationStatus.SUPERVISED;
|
|
85
|
+
case SUPERVISED_APPROVAL_PENDING:
|
|
86
|
+
return AgeSignalsVerificationStatus.SUPERVISED_APPROVAL_PENDING;
|
|
87
|
+
case SUPERVISED_APPROVAL_DENIED:
|
|
88
|
+
return AgeSignalsVerificationStatus.SUPERVISED_APPROVAL_DENIED;
|
|
89
|
+
case UNKNOWN:
|
|
90
|
+
return AgeSignalsVerificationStatus.UNKNOWN;
|
|
91
|
+
default:
|
|
92
|
+
return AgeSignalsVerificationStatus.UNKNOWN;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@NonNull
|
|
97
|
+
private Date parseDateString(@NonNull String dateString) throws Exception {
|
|
98
|
+
try {
|
|
99
|
+
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
|
100
|
+
Date date = format.parse(dateString);
|
|
101
|
+
if (date == null) {
|
|
102
|
+
throw new Exception("Failed to parse date: " + dateString);
|
|
103
|
+
}
|
|
104
|
+
return date;
|
|
105
|
+
} catch (Exception exception) {
|
|
106
|
+
throw new Exception("Invalid date format. Expected yyyy-MM-dd, got: " + dateString);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.agesignals.classes.options;
|
|
2
|
+
|
|
3
|
+
import com.getcapacitor.PluginCall;
|
|
4
|
+
|
|
5
|
+
public class SetUseFakeManagerOptions {
|
|
6
|
+
|
|
7
|
+
private final boolean useFake;
|
|
8
|
+
|
|
9
|
+
public SetUseFakeManagerOptions(PluginCall call) {
|
|
10
|
+
this.useFake = call.getBoolean("useFake", false);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public boolean getUseFake() {
|
|
14
|
+
return useFake;
|
|
15
|
+
}
|
|
16
|
+
}
|