halo-sdk-react-native 1.0.1 → 1.0.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/CHANGELOG.md +27 -0
- package/README.md +72 -91
- package/android/build.gradle +2 -2
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `halo-sdk-react-native` will be documented here.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## [1.0.2] - 2026-03-03
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Changed Halo SDK dependency declaration from `compileOnly` to `api` in `build.gradle` so it is exposed transitively to host apps. This prevents a `NoClassDefFoundError: HaloSDK` crash on launch, host apps no longer need to add the Halo SDK as a direct dependency.
|
|
11
|
+
|
|
12
|
+
### Documentation
|
|
13
|
+
- Updated README to remove the now-unnecessary manual Halo SDK runtime dependency step
|
|
14
|
+
- Fixed incorrect `resultType` check in code examples (`'success'`-> `'Initialized'`)
|
|
15
|
+
- Added Result Types reference table for `HaloInitializationResult` and `HaloTransactionResult`
|
|
16
|
+
- Added FAQ entries for common setup issues (Metro bundler `SyntaxError`, `JWTExpired` on init)
|
|
17
|
+
- Corrected the JWT section to reference official Halo documentation
|
|
18
|
+
- Fixed Full Example to use `requestHaloPermissions()` from `src/permissions.ts`
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## [1.0.1] - Initial release
|
|
23
|
+
|
|
24
|
+
- Initial React Native plugin wrapping the Halo Dot Android SDK
|
|
25
|
+
- Supports `initialize`, `startTransaction`, `cardRefundTransaction`, and `cancelTransaction`
|
|
26
|
+
- Event-driven callbacks via `NativeEventEmitter`: initialization, transaction result, UI messages, JWT requests, attestation errors, security errors, and camera events
|
|
27
|
+
- Scheme animations (Visa / Mastercard / Amex) on approved transactions via `AnimationActivity`
|
package/README.md
CHANGED
|
@@ -19,8 +19,6 @@ The diagram below shows the SDK boundary and how it interacts with your app, the
|
|
|
19
19
|
- [Native Module Setup](#native-module-setup)
|
|
20
20
|
- [AndroidManifest Permissions](#androidmanifest-permissions)
|
|
21
21
|
- [JWT — What It Is and How to Set It Up](#jwt--what-it-is-and-how-to-set-it-up)
|
|
22
|
-
- [JWT Lifetime](#jwt-lifetime)
|
|
23
|
-
- [JWT Claims](#jwt-claims)
|
|
24
22
|
- [Usage](#usage)
|
|
25
23
|
- [Step 1 — Request Permissions](#step-1--request-permissions)
|
|
26
24
|
- [Step 2 — Set Up Callbacks](#step-2--set-up-callbacks)
|
|
@@ -28,6 +26,7 @@ The diagram below shows the SDK boundary and how it interacts with your app, the
|
|
|
28
26
|
- [Step 4 — Run a Transaction](#step-4--run-a-transaction)
|
|
29
27
|
- [Full Example](#full-example)
|
|
30
28
|
- [API Reference](#api-reference)
|
|
29
|
+
- [Result Types](#result-types)
|
|
31
30
|
- [Documentation](#documentation)
|
|
32
31
|
- [Testing](#testing)
|
|
33
32
|
- [FAQ](#faq)
|
|
@@ -50,10 +49,7 @@ You will also need:
|
|
|
50
49
|
- A signed Non-Disclosure Agreement (NDA), available on the portal
|
|
51
50
|
- A JWT — generated via the developer portal or your own backend (see [JWT section](#jwt--what-it-is-and-how-to-set-it-up))
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
- [`react-native-permissions`](https://www.npmjs.com/package/react-native-permissions) `^4.0.0` — runtime permission handling
|
|
55
|
-
|
|
56
|
-
> **Note:** Android is the only supported platform.
|
|
52
|
+
> **Note:** Android is the only supported platform for now.
|
|
57
53
|
|
|
58
54
|
---
|
|
59
55
|
|
|
@@ -80,7 +76,7 @@ You must register on the QA (UAT) environment before going to production.
|
|
|
80
76
|
If you don't already have a React Native project, create one:
|
|
81
77
|
|
|
82
78
|
```bash
|
|
83
|
-
npx react-native init MyHaloApp
|
|
79
|
+
npx react-native init MyHaloApp
|
|
84
80
|
cd MyHaloApp
|
|
85
81
|
```
|
|
86
82
|
|
|
@@ -114,13 +110,7 @@ npm install halo-sdk-react-native
|
|
|
114
110
|
yarn add halo-sdk-react-native
|
|
115
111
|
```
|
|
116
112
|
|
|
117
|
-
**2.**
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
npm install react-native-permissions
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
**3.** The plugin downloads the Halo SDK binaries from an S3-backed Maven repo. Add your credentials (from the [developer portal](#developer-portal-registration)) to `android/local.properties` (create the file if it doesn't exist):
|
|
113
|
+
**2.** The plugin downloads the Halo SDK binaries from an S3-backed Maven repo. Add your credentials (from the [developer portal](#developer-portal-registration)) to `android/local.properties` (create the file if it doesn't exist):
|
|
124
114
|
|
|
125
115
|
```properties
|
|
126
116
|
aws.accesskey=YOUR_ACCESS_KEY
|
|
@@ -129,7 +119,7 @@ aws.secretkey=YOUR_SECRET_KEY
|
|
|
129
119
|
|
|
130
120
|
> **Important:** Never commit `local.properties` to source control. Add it to your `.gitignore`
|
|
131
121
|
|
|
132
|
-
**
|
|
122
|
+
**3.** Add the following snippet to `android/app/build.gradle` so Gradle can read `local.properties` (it may already be there in newer RN templates):
|
|
133
123
|
|
|
134
124
|
```gradle
|
|
135
125
|
def localProperties = new Properties()
|
|
@@ -143,7 +133,7 @@ if (localPropertiesFile.exists()) {
|
|
|
143
133
|
|
|
144
134
|
### Native Module Setup
|
|
145
135
|
|
|
146
|
-
**
|
|
136
|
+
**4.** Open `android/app/src/main/kotlin/.../MainActivity.kt` and extend `HaloReactActivity` instead of `ReactActivity`:
|
|
147
137
|
|
|
148
138
|
```kotlin
|
|
149
139
|
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
|
|
@@ -161,7 +151,7 @@ class MainActivity : HaloReactActivity() {
|
|
|
161
151
|
|
|
162
152
|
This replaces `ReactActivity` so that NFC foreground dispatch and the Halo SDK lifecycle are managed automatically.
|
|
163
153
|
|
|
164
|
-
**
|
|
154
|
+
**5.** Open `android/app/src/main/kotlin/.../MainApplication.kt` and register `HaloSdkPackage`:
|
|
165
155
|
|
|
166
156
|
```kotlin
|
|
167
157
|
import android.app.Application
|
|
@@ -197,7 +187,7 @@ class MainApplication : Application(), ReactApplication {
|
|
|
197
187
|
|
|
198
188
|
### AndroidManifest Permissions
|
|
199
189
|
|
|
200
|
-
**
|
|
190
|
+
**6.** Add the required permissions to `android/app/src/main/AndroidManifest.xml`:
|
|
201
191
|
|
|
202
192
|
```xml
|
|
203
193
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
@@ -251,25 +241,21 @@ class MainApplication : Application(), ReactApplication {
|
|
|
251
241
|
|
|
252
242
|
## JWT — What It Is and How to Set It Up
|
|
253
243
|
|
|
254
|
-
Every call to the Halo SDK must include a valid JWT.
|
|
255
|
-
|
|
256
|
-
The JWT is issued either by the [developer portal](https://go.developerportal.qa.haloplus.io/) (for testing) or by your own backend server (for production). The portal verifies it using the RSA **public key** you submitted during registration.
|
|
244
|
+
Every call to the Halo SDK must include a valid JWT. The SDK requests one via the `onRequestJWT` callback whenever it needs to authenticate.
|
|
257
245
|
|
|
258
|
-
|
|
246
|
+
A JWT must be obtained from your backend or generated using your RSA private key and the credentials from the [developer portal](https://go.developerportal.qa.haloplus.io/). See the [Halo developer documentation](https://halo-dot-developer-docs.gitbook.io/halo-dot/sdk) for the required claims. For testing, paste a valid token directly into `Config.tempJwt` as shown below.
|
|
259
247
|
|
|
260
|
-
|
|
248
|
+
Split your config and JWT supply into two files:
|
|
261
249
|
|
|
262
|
-
**`src/config.ts`** — stores your app
|
|
250
|
+
**`src/config.ts`** — stores your app settings (never commit real values to source control):
|
|
263
251
|
|
|
264
252
|
```typescript
|
|
265
|
-
// Copy this file to config.ts and fill in your values.
|
|
266
|
-
// config.ts should be added to .gitignore.
|
|
267
253
|
export const Config = {
|
|
268
|
-
// Paste a JWT
|
|
269
|
-
//
|
|
254
|
+
// Paste a valid JWT here for testing.
|
|
255
|
+
// Regenerate it if the SDK reports JWTExpired on startup.
|
|
270
256
|
tempJwt: 'eyJ...',
|
|
271
257
|
|
|
272
|
-
//
|
|
258
|
+
// Obtained from the developer portal
|
|
273
259
|
applicationPackageName: 'com.yourcompany.myapp',
|
|
274
260
|
applicationVersion: '1.0.0',
|
|
275
261
|
onStartTransactionTimeOut: 300000, // ms before "tap card" times out
|
|
@@ -277,46 +263,20 @@ export const Config = {
|
|
|
277
263
|
} as const;
|
|
278
264
|
```
|
|
279
265
|
|
|
280
|
-
**`src/jwt/JwtToken.ts
|
|
266
|
+
**`src/jwt/JwtToken.ts`**: supplies the JWT when the SDK asks for one:
|
|
281
267
|
|
|
282
268
|
```typescript
|
|
283
269
|
import { Config } from '../config';
|
|
284
270
|
|
|
285
|
-
/**
|
|
286
|
-
* Returns the JWT for the Halo SDK's onRequestJWT callback.
|
|
287
|
-
*
|
|
288
|
-
* For testing: set Config.tempJwt to a token from the developer portal.
|
|
289
|
-
* For production: replace this with a fetch from your backend server.
|
|
290
|
-
*/
|
|
291
271
|
export function getJwt(): string {
|
|
292
272
|
if (Config.tempJwt) {
|
|
293
273
|
return Config.tempJwt;
|
|
294
274
|
}
|
|
295
|
-
throw new Error(
|
|
296
|
-
'No JWT configured. Set Config.tempJwt in src/config.ts, ' +
|
|
297
|
-
'or implement a backend fetch here.',
|
|
298
|
-
);
|
|
275
|
+
throw new Error('No JWT configured. Set Config.tempJwt in src/config.ts.');
|
|
299
276
|
}
|
|
300
277
|
```
|
|
301
278
|
|
|
302
|
-
> **
|
|
303
|
-
|
|
304
|
-
### JWT Lifetime
|
|
305
|
-
|
|
306
|
-
Keep the lifetime short — 15 minutes is the recommended maximum. A stolen JWT can only be abused for as long as it remains valid.
|
|
307
|
-
|
|
308
|
-
### JWT Claims
|
|
309
|
-
|
|
310
|
-
| Field | Type | Description |
|
|
311
|
-
|---|---|---|
|
|
312
|
-
| `alg` | String | `RS512` — RSA + SHA-512. Asymmetric signing is required so the server can verify without being able to forge tokens. |
|
|
313
|
-
| `iss` | String | Your issuer name, registered on the developer portal (e.g. `authserver.haloplus.io`). |
|
|
314
|
-
| `sub` | String | Your merchant or application ID. |
|
|
315
|
-
| `aud` | String | The Halo kernel server URL (e.g. `kernelserver.qa.haloplus.io`). |
|
|
316
|
-
| `usr` | String | The signed-in operator/user identifier. |
|
|
317
|
-
| `iat` | NumericDate | UTC timestamp of when the token was created. |
|
|
318
|
-
| `exp` | NumericDate | UTC expiry timestamp. |
|
|
319
|
-
| `aud_fingerprints` | String | CSV of SHA-256 TLS fingerprints for the kernel server. Supports multiple values for certificate rotation. |
|
|
279
|
+
> **Important:** Add `config.ts` to `.gitignore` so you never accidentally commit a real token to source control.
|
|
320
280
|
|
|
321
281
|
---
|
|
322
282
|
|
|
@@ -376,12 +336,13 @@ export function buildCallbacks(options: {
|
|
|
376
336
|
onTransactionResult: (result: HaloTransactionResult) => void;
|
|
377
337
|
}): IHaloCallbacks {
|
|
378
338
|
return {
|
|
379
|
-
// Called when the SDK finishes starting up
|
|
339
|
+
// Called when the SDK finishes starting up.
|
|
340
|
+
// Check resultType === 'Initialized' for successful init.
|
|
380
341
|
onInitializationResult(result: HaloInitializationResult) {
|
|
381
|
-
if (result.resultType === '
|
|
342
|
+
if (result.resultType === 'Initialized') {
|
|
382
343
|
options.onStatusChange('SDK ready — present a card to pay');
|
|
383
344
|
} else {
|
|
384
|
-
options.onError(`Initialisation failed: ${result.errorCode}`);
|
|
345
|
+
options.onError(`Initialisation failed: ${result.resultType} (${result.errorCode})`);
|
|
385
346
|
}
|
|
386
347
|
},
|
|
387
348
|
|
|
@@ -471,7 +432,7 @@ const refund = await HaloSdk.cardRefundTransaction(10.50, 'ORDER-001', 'ZAR');
|
|
|
471
432
|
await HaloSdk.cancelTransaction();
|
|
472
433
|
```
|
|
473
434
|
|
|
474
|
-
`startTransaction` and `cardRefundTransaction` resolve immediately once the tap is registered
|
|
435
|
+
`startTransaction` and `cardRefundTransaction` resolve immediately once the tap is registered, the final payment outcome arrives through `onHaloTransactionResult`.
|
|
475
436
|
|
|
476
437
|
### Full Example
|
|
477
438
|
|
|
@@ -482,8 +443,6 @@ Below is a minimal but complete payment screen taken directly from the example a
|
|
|
482
443
|
import React, { useEffect, useState } from 'react';
|
|
483
444
|
import {
|
|
484
445
|
ActivityIndicator,
|
|
485
|
-
PermissionsAndroid,
|
|
486
|
-
Platform,
|
|
487
446
|
Text,
|
|
488
447
|
TextInput,
|
|
489
448
|
TouchableOpacity,
|
|
@@ -496,6 +455,7 @@ import {
|
|
|
496
455
|
} from 'halo-sdk-react-native';
|
|
497
456
|
import { getJwt } from './src/jwt/JwtToken';
|
|
498
457
|
import { Config } from './src/config';
|
|
458
|
+
import { requestHaloPermissions } from './src/permissions';
|
|
499
459
|
|
|
500
460
|
export default function App() {
|
|
501
461
|
const [amount, setAmount] = useState('');
|
|
@@ -508,33 +468,15 @@ export default function App() {
|
|
|
508
468
|
}, []);
|
|
509
469
|
|
|
510
470
|
async function initSdk() {
|
|
511
|
-
|
|
512
|
-
if (Platform.OS === 'android') {
|
|
513
|
-
const sdkVersion =
|
|
514
|
-
typeof Platform.Version === 'number'
|
|
515
|
-
? Platform.Version
|
|
516
|
-
: parseInt(Platform.Version, 10);
|
|
517
|
-
|
|
518
|
-
const perms: string[] = [
|
|
519
|
-
PermissionsAndroid.PERMISSIONS.CAMERA,
|
|
520
|
-
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
|
|
521
|
-
];
|
|
522
|
-
if (sdkVersion >= 31) {
|
|
523
|
-
perms.push(
|
|
524
|
-
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
|
|
525
|
-
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
|
|
526
|
-
);
|
|
527
|
-
}
|
|
528
|
-
await PermissionsAndroid.requestMultiple(perms);
|
|
529
|
-
}
|
|
471
|
+
await requestHaloPermissions();
|
|
530
472
|
|
|
531
473
|
const callbacks: IHaloCallbacks = {
|
|
532
474
|
onInitializationResult(result) {
|
|
533
|
-
setIsReady(result.resultType === '
|
|
475
|
+
setIsReady(result.resultType === 'Initialized');
|
|
534
476
|
setStatus(
|
|
535
|
-
result.resultType === '
|
|
477
|
+
result.resultType === 'Initialized'
|
|
536
478
|
? 'Ready — enter amount and tap Charge'
|
|
537
|
-
: `Init failed: ${result.errorCode}`,
|
|
479
|
+
: `Init failed: ${result.resultType} (${result.errorCode})`,
|
|
538
480
|
);
|
|
539
481
|
},
|
|
540
482
|
onHaloTransactionResult(result: HaloTransactionResult) {
|
|
@@ -656,13 +598,42 @@ Cancels the current in-progress transaction (e.g. if the user presses Cancel whi
|
|
|
656
598
|
| Callback | When it fires |
|
|
657
599
|
|---|---|
|
|
658
600
|
| `onInitializationResult(result)` | SDK startup complete (success or failure) |
|
|
659
|
-
| `onHaloTransactionResult(result)` | Final payment outcome
|
|
601
|
+
| `onHaloTransactionResult(result)` | Final payment outcome; approved, declined, or error |
|
|
660
602
|
| `onHaloUIMessage(message)` | Prompt to show the user during a tap: `PRESENT_CARD`, `PROCESSING`, `APPROVED`, etc. |
|
|
661
|
-
| `onRequestJWT(jwtCallback)` | SDK needs a fresh JWT
|
|
603
|
+
| `onRequestJWT(jwtCallback)` | SDK needs a fresh JWT; call `jwtCallback(yourJwtString)` |
|
|
662
604
|
| `onAttestationError(details)` | Device integrity check failed (rooted device, emulator, etc.) |
|
|
663
605
|
| `onSecurityError(errorCode)` | JWT invalid, merchant revoked, or other security failure |
|
|
664
606
|
| `onCameraControlLost()` | SDK has finished using the camera |
|
|
665
607
|
|
|
608
|
+
### Result Types
|
|
609
|
+
|
|
610
|
+
`resultType` and `errorCode` are plain strings serialised from native Android enums. Use these known values in your conditional logic.
|
|
611
|
+
|
|
612
|
+
**`HaloInitializationResult.resultType`**
|
|
613
|
+
|
|
614
|
+
| Value | Meaning |
|
|
615
|
+
|---|---|
|
|
616
|
+
| `'Initialized'` | SDK ready; safe to call `startTransaction` |
|
|
617
|
+
| `'RemoteAttestationFailure'` | Cloud attestation failed; inspect `errorCode` for the reason |
|
|
618
|
+
| `'LocalAttestationFailure'` | Device integrity check failed (rooted device, emulator, etc.) |
|
|
619
|
+
|
|
620
|
+
**`HaloInitializationResult.errorCode`** (when `resultType !== 'Initialized'`)
|
|
621
|
+
|
|
622
|
+
| Value | Meaning |
|
|
623
|
+
|---|---|
|
|
624
|
+
| `'OK'` | No error — accompanies `resultType: 'Initialized'` |
|
|
625
|
+
| `'JWTExpired'` | The JWT has expired — generate a fresh one |
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
**`HaloTransactionResult.resultType`**
|
|
629
|
+
|
|
630
|
+
| Value | Meaning |
|
|
631
|
+
|---|---|
|
|
632
|
+
| `'Approved'` | Transaction approved by the payment network |
|
|
633
|
+
| `'Declined'` | Card declined |
|
|
634
|
+
| `'Cancelled'` | Transaction cancelled (e.g. via `cancelTransaction()`) |
|
|
635
|
+
| `'Error'` | An error occurred — inspect `errorCode` and `errorDetails` |
|
|
636
|
+
|
|
666
637
|
---
|
|
667
638
|
|
|
668
639
|
## Documentation
|
|
@@ -686,7 +657,7 @@ You can simulate card taps using a virtual NFC card app such as [Visa Mobile CDE
|
|
|
686
657
|
You can define them in `android/local.properties` and read them in Gradle:
|
|
687
658
|
|
|
688
659
|
```properties
|
|
689
|
-
sdk.dir
|
|
660
|
+
sdk.dir=C\:\\Users\\yourname\\Library\\Android/Sdk
|
|
690
661
|
aws.accesskey=YOUR_ACCESS_KEY
|
|
691
662
|
aws.secretkey=YOUR_SECRET_KEY
|
|
692
663
|
compileSdkVersion=34
|
|
@@ -726,6 +697,16 @@ compileSdkVersion localProperties.getProperty('compileSdkVersion').toInteger()
|
|
|
726
697
|
|
|
727
698
|
---
|
|
728
699
|
|
|
729
|
-
**Q: How do I get a
|
|
700
|
+
**Q: How do I get a JWT for testing?**
|
|
701
|
+
|
|
702
|
+
A JWT must be generated using your RSA private key and the credentials from the [developer portal](https://go.developerportal.qa.haloplus.io/). See the [Halo developer documentation](https://halo-dot-developer-docs.gitbook.io/halo-dot/sdk) for the required claims and signing algorithm. Once you have a valid token, paste it into `Config.tempJwt` in your `config.ts`.
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
**Q: `onInitializationResult` fires with `resultType: 'RemoteAttestationFailure'` and `errorCode: 'JWTExpired'`.**
|
|
707
|
+
|
|
708
|
+
Your temp JWT has expired. Developer-portal tokens are short-lived (typically 15 minutes). This is expected behaviour — the SDK fires a failure callback with the cached/expired token, then automatically requests a new JWT via `onRequestJWT` and retries. If `onInitializationResult` fires a **second time** shortly after with `resultType: 'Initialized'`, everything is working correctly.
|
|
730
709
|
|
|
731
|
-
|
|
710
|
+
If the second successful callback never arrives:
|
|
711
|
+
1. Generate a fresh token and update `Config.tempJwt`
|
|
712
|
+
2. Make sure your `onRequestJWT` callback calls `jwtCallback(yourJwt)` synchronously — async calls are not supported without extra handling
|
package/android/build.gradle
CHANGED
|
@@ -81,8 +81,8 @@ dependencies {
|
|
|
81
81
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
82
82
|
|
|
83
83
|
// Halo SDK
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
releaseApi group: "za.co.synthesis.halo", name: "sdk", version: "$sdkVersion", changing: true
|
|
85
|
+
debugApi group: "za.co.synthesis.halo", name: "sdk", version: "$sdkVersion-debug", changing: true
|
|
86
86
|
|
|
87
87
|
implementation(name: 'VisaSensoryBranding', ext: 'aar')
|
|
88
88
|
implementation(name: 'sonic-sdk-release-1.5.0', ext: 'aar')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halo-sdk-react-native",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "React Native plugin for Halo SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"android/libs",
|
|
11
11
|
"android/build.gradle",
|
|
12
12
|
"android/settings.gradle",
|
|
13
|
-
"README.md"
|
|
13
|
+
"README.md",
|
|
14
|
+
"CHANGELOG.md"
|
|
14
15
|
],
|
|
15
16
|
"scripts": {
|
|
16
17
|
"build": "tsc"
|