@json-eval-rs/react-native 0.0.28
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 +455 -0
- package/android/CMakeLists.txt +78 -0
- package/android/build.gradle +90 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/json-eval-rn.cpp +875 -0
- package/android/src/main/java/com/jsonevalrs/JsonEvalRsModule.kt +532 -0
- package/android/src/main/java/com/jsonevalrs/JsonEvalRsPackage.kt +16 -0
- package/android/src/main/jniLibs/arm64-v8a/libjson_eval_rs.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libjson_eval_rs.so +0 -0
- package/android/src/main/jniLibs/x86/libjson_eval_rs.so +0 -0
- package/android/src/main/jniLibs/x86_64/libjson_eval_rs.so +0 -0
- package/cpp/json-eval-bridge.cpp +1366 -0
- package/cpp/json-eval-bridge.h +583 -0
- package/ios/JsonEvalRs.h +5 -0
- package/ios/JsonEvalRs.mm +852 -0
- package/ios/JsonEvalRs.xcframework/Info.plist +44 -0
- package/ios/JsonEvalRs.xcframework/ios-arm64/libjson_eval_rs.a +0 -0
- package/ios/JsonEvalRs.xcframework/ios-arm64_x86_64-simulator/libjson_eval_rs.a +0 -0
- package/json-eval-rs.podspec +33 -0
- package/lib/commonjs/index.js +786 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/module/index.js +778 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/index.d.ts +565 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/package.json +140 -0
- package/src/index.tsx +999 -0
package/README.md
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
# @json-eval-rs/react-native
|
|
2
|
+
|
|
3
|
+
High-performance JSON Logic evaluator with schema validation for React Native.
|
|
4
|
+
|
|
5
|
+
Built with Rust for maximum performance, with native Android (Kotlin + JNI) and iOS (Objective-C++) bindings. All operations run asynchronously on background threads to keep your UI responsive.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🚀 **Native Performance** - Built with Rust for iOS and Android
|
|
10
|
+
- ✅ **Schema Validation** - Validate data against JSON schema rules
|
|
11
|
+
- 🔄 **Dependency Tracking** - Auto-update dependent fields
|
|
12
|
+
- 🎯 **Type Safe** - Full TypeScript support
|
|
13
|
+
- ⚛️ **React Hooks** - Built-in `useJSONEval` hook
|
|
14
|
+
- 📱 **Cross-Platform** - Works on iOS and Android
|
|
15
|
+
- 🔥 **Fast** - Native performance, not JavaScript
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
yarn install @json-eval-rs/react-native
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or with Yarn:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
yarn add @json-eval-rs/react-native
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### iOS
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cd ios && pod install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Android
|
|
36
|
+
|
|
37
|
+
No additional steps required. The library uses autolinking.
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
### Basic Usage
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { JSONEval } from '@json-eval-rs/react-native';
|
|
45
|
+
|
|
46
|
+
const schema = {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
user: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
name: {
|
|
53
|
+
type: 'string',
|
|
54
|
+
rules: {
|
|
55
|
+
required: { value: true, message: 'Name is required' },
|
|
56
|
+
minLength: { value: 3, message: 'Min 3 characters' }
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
age: {
|
|
60
|
+
type: 'number',
|
|
61
|
+
rules: {
|
|
62
|
+
minValue: { value: 18, message: 'Must be 18+' }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Create evaluator
|
|
71
|
+
const eval = new JSONEval({ schema });
|
|
72
|
+
|
|
73
|
+
// Evaluate
|
|
74
|
+
const data = { user: { name: 'John', age: 25 } };
|
|
75
|
+
const result = await eval.evaluate({ data });
|
|
76
|
+
console.log('Evaluated:', result);
|
|
77
|
+
|
|
78
|
+
// Validate
|
|
79
|
+
const validation = await eval.validate({ data });
|
|
80
|
+
if (validation.hasError) {
|
|
81
|
+
validation.errors.forEach(error => {
|
|
82
|
+
console.error(`${error.path}: ${error.message}`);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Clean up
|
|
87
|
+
await eval.dispose();
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Using React Hook
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import React, { useState } from 'react';
|
|
94
|
+
import { View, TextInput, Button, Text } from 'react-native';
|
|
95
|
+
import { useJSONEval } from '@json-eval-rs/react-native';
|
|
96
|
+
|
|
97
|
+
const schema = {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
user: {
|
|
101
|
+
type: 'object',
|
|
102
|
+
properties: {
|
|
103
|
+
name: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
rules: {
|
|
106
|
+
required: { value: true, message: 'Name is required' },
|
|
107
|
+
minLength: { value: 3, message: 'Min 3 characters' }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
function MyForm() {
|
|
116
|
+
const eval = useJSONEval({ schema });
|
|
117
|
+
const [name, setName] = useState('');
|
|
118
|
+
const [errors, setErrors] = useState<string[]>([]);
|
|
119
|
+
|
|
120
|
+
const handleValidate = async () => {
|
|
121
|
+
if (!eval) return;
|
|
122
|
+
|
|
123
|
+
const data = { user: { name } };
|
|
124
|
+
const validation = await eval.validate({ data });
|
|
125
|
+
|
|
126
|
+
if (validation.hasError) {
|
|
127
|
+
setErrors(validation.errors.map(e => e.message));
|
|
128
|
+
} else {
|
|
129
|
+
setErrors([]);
|
|
130
|
+
console.log('Valid!');
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<View>
|
|
136
|
+
<TextInput
|
|
137
|
+
value={name}
|
|
138
|
+
onChangeText={setName}
|
|
139
|
+
placeholder="Enter name"
|
|
140
|
+
/>
|
|
141
|
+
<Button title="Validate" onPress={handleValidate} />
|
|
142
|
+
|
|
143
|
+
{errors.map((error, i) => (
|
|
144
|
+
<Text key={i} style={{ color: 'red' }}>{error}</Text>
|
|
145
|
+
))}
|
|
146
|
+
</View>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Advanced: Dependent Fields
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import React, { useState, useEffect } from 'react';
|
|
155
|
+
import { View, TextInput, Text } from 'react-native';
|
|
156
|
+
import { useJSONEval } from '@json-eval-rs/react-native';
|
|
157
|
+
|
|
158
|
+
const schema = {
|
|
159
|
+
type: 'object',
|
|
160
|
+
properties: {
|
|
161
|
+
quantity: { type: 'number' },
|
|
162
|
+
price: { type: 'number' },
|
|
163
|
+
total: {
|
|
164
|
+
type: 'number',
|
|
165
|
+
$evaluation: {
|
|
166
|
+
'*': [{ var: 'quantity' }, { var: 'price' }]
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
function Calculator() {
|
|
173
|
+
const eval = useJSONEval({ schema });
|
|
174
|
+
const [quantity, setQuantity] = useState(1);
|
|
175
|
+
const [price, setPrice] = useState(10);
|
|
176
|
+
const [total, setTotal] = useState(0);
|
|
177
|
+
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (!eval) return;
|
|
180
|
+
|
|
181
|
+
const updateTotal = async () => {
|
|
182
|
+
const data = { quantity, price };
|
|
183
|
+
const result = await eval.evaluateDependents({
|
|
184
|
+
changedPaths: ['quantity'], // Array of changed field paths
|
|
185
|
+
data,
|
|
186
|
+
reEvaluate: false // Optional: re-evaluate entire schema after dependents
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
setTotal(result.total);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
updateTotal();
|
|
193
|
+
}, [eval, quantity, price]);
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<View>
|
|
197
|
+
<TextInput
|
|
198
|
+
value={String(quantity)}
|
|
199
|
+
onChangeText={(val) => setQuantity(Number(val))}
|
|
200
|
+
keyboardType="numeric"
|
|
201
|
+
/>
|
|
202
|
+
<TextInput
|
|
203
|
+
value={String(price)}
|
|
204
|
+
onChangeText={(val) => setPrice(Number(val))}
|
|
205
|
+
keyboardType="numeric"
|
|
206
|
+
/>
|
|
207
|
+
<Text>Total: {total}</Text>
|
|
208
|
+
</View>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## API Reference
|
|
214
|
+
|
|
215
|
+
### JSONEval Class
|
|
216
|
+
|
|
217
|
+
#### Constructor
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
constructor(options: {
|
|
221
|
+
schema: string | object;
|
|
222
|
+
context?: string | object;
|
|
223
|
+
data?: string | object;
|
|
224
|
+
})
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Creates a new evaluator instance.
|
|
228
|
+
|
|
229
|
+
#### Methods
|
|
230
|
+
|
|
231
|
+
##### evaluate(options)
|
|
232
|
+
|
|
233
|
+
Evaluates the schema with provided data.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
async evaluate(options: {
|
|
237
|
+
data: string | object;
|
|
238
|
+
context?: string | object;
|
|
239
|
+
}): Promise<any>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
##### validate(options)
|
|
243
|
+
|
|
244
|
+
Validates data against schema rules.
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
async validate(options: {
|
|
248
|
+
data: string | object;
|
|
249
|
+
context?: string | object;
|
|
250
|
+
}): Promise<ValidationResult>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
```typescript
|
|
255
|
+
interface ValidationResult {
|
|
256
|
+
hasError: boolean;
|
|
257
|
+
errors: ValidationError[];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
interface ValidationError {
|
|
261
|
+
path: string;
|
|
262
|
+
ruleType: string;
|
|
263
|
+
message: string;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
##### evaluateDependents(options)
|
|
268
|
+
|
|
269
|
+
Re-evaluates fields that depend on changed paths (processes transitively).
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
async evaluateDependents(options: {
|
|
273
|
+
changedPaths: string[]; // Array of field paths that changed
|
|
274
|
+
data?: string | object; // Optional updated data
|
|
275
|
+
context?: string | object; // Optional context
|
|
276
|
+
reEvaluate?: boolean; // If true, performs full evaluation after dependents
|
|
277
|
+
}): Promise<any[]>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Parameters:**
|
|
281
|
+
- `changedPaths`: Array of field paths that changed (e.g., `['field1', 'nested.field2']`)
|
|
282
|
+
- `data`: Optional JSON data (string or object). If provided, replaces current data
|
|
283
|
+
- `context`: Optional context data
|
|
284
|
+
- `reEvaluate`: If `true`, performs full schema evaluation after processing dependents (default: `false`)
|
|
285
|
+
|
|
286
|
+
**Returns:** Array of dependent field change objects with `$ref`, `value`, `$field`, `$parentField`, and `transitive` properties.
|
|
287
|
+
|
|
288
|
+
**Example:**
|
|
289
|
+
```typescript
|
|
290
|
+
// Update multiple fields and get their dependents
|
|
291
|
+
const result = await eval.evaluateDependents({
|
|
292
|
+
changedPaths: ['illustration.insured.ins_dob', 'illustration.product_code'],
|
|
293
|
+
data: updatedData,
|
|
294
|
+
reEvaluate: true // Re-run full evaluation after dependents
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// Process the changes
|
|
298
|
+
result.forEach(change => {
|
|
299
|
+
console.log(`Field ${change.$ref} changed:`, change.value);
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
##### dispose()
|
|
304
|
+
|
|
305
|
+
Frees native resources. Must be called when done.
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
async dispose(): Promise<void>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
##### static version()
|
|
312
|
+
|
|
313
|
+
Gets the library version.
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
static async version(): Promise<string>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### useJSONEval Hook
|
|
320
|
+
|
|
321
|
+
React hook for automatic lifecycle management.
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
function useJSONEval(options: JSONEvalOptions): JSONEval | null
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Returns `null` until initialized, then returns the `JSONEval` instance.
|
|
328
|
+
Automatically disposes on unmount.
|
|
329
|
+
|
|
330
|
+
## Validation Rules
|
|
331
|
+
|
|
332
|
+
Supported validation rules:
|
|
333
|
+
|
|
334
|
+
- **required** - Field must have a value
|
|
335
|
+
- **minLength** / **maxLength** - String/array length validation
|
|
336
|
+
- **minValue** / **maxValue** - Numeric range validation
|
|
337
|
+
- **pattern** - Regex pattern matching
|
|
338
|
+
|
|
339
|
+
## Platform Support
|
|
340
|
+
|
|
341
|
+
- **iOS**: 11.0+
|
|
342
|
+
- **Android**: API 21+ (Android 5.0)
|
|
343
|
+
- **React Native**: 0.64+
|
|
344
|
+
|
|
345
|
+
## Performance
|
|
346
|
+
|
|
347
|
+
Typical performance on modern devices:
|
|
348
|
+
- Schema parsing: < 5ms
|
|
349
|
+
- Evaluation: < 10ms for complex schemas
|
|
350
|
+
- Validation: < 5ms
|
|
351
|
+
|
|
352
|
+
Native performance beats JavaScript-only solutions by 10-50x.
|
|
353
|
+
|
|
354
|
+
### Sequential Processing
|
|
355
|
+
|
|
356
|
+
This library uses **sequential processing** by default, which is optimal for mobile devices. The Rust core supports an optional `parallel` feature using Rayon, but:
|
|
357
|
+
- Mobile devices have limited cores and power constraints
|
|
358
|
+
- Sequential processing is faster for typical mobile use cases (small to medium datasets)
|
|
359
|
+
- Parallel overhead exceeds benefits for arrays < 1000 items
|
|
360
|
+
- Battery life is better with sequential processing
|
|
361
|
+
|
|
362
|
+
The default configuration is optimized for mobile performance and battery efficiency.
|
|
363
|
+
|
|
364
|
+
## Error Handling
|
|
365
|
+
|
|
366
|
+
All async methods can throw errors:
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
try {
|
|
370
|
+
const result = await eval.evaluate({ data });
|
|
371
|
+
} catch (error) {
|
|
372
|
+
console.error('Evaluation error:', error.message);
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Memory Management
|
|
377
|
+
|
|
378
|
+
Always dispose of instances when done:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
const eval = new JSONEval({ schema });
|
|
382
|
+
try {
|
|
383
|
+
// Use eval
|
|
384
|
+
} finally {
|
|
385
|
+
await eval.dispose(); // Important!
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Or use the hook for automatic management:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
function MyComponent() {
|
|
393
|
+
const eval = useJSONEval({ schema }); // Auto-disposed on unmount
|
|
394
|
+
// Use eval
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## TypeScript
|
|
399
|
+
|
|
400
|
+
Full TypeScript support included. All types are exported:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import type {
|
|
404
|
+
JSONEval,
|
|
405
|
+
ValidationError,
|
|
406
|
+
ValidationResult,
|
|
407
|
+
JSONEvalOptions,
|
|
408
|
+
EvaluateOptions,
|
|
409
|
+
EvaluateDependentsOptions
|
|
410
|
+
} from '@json-eval-rs/react-native';
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Troubleshooting
|
|
414
|
+
|
|
415
|
+
### iOS Build Errors
|
|
416
|
+
|
|
417
|
+
If you encounter build errors on iOS:
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
cd ios
|
|
421
|
+
rm -rf Pods Podfile.lock
|
|
422
|
+
pod install --repo-update
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Android Build Errors
|
|
426
|
+
|
|
427
|
+
If you encounter build errors on Android:
|
|
428
|
+
|
|
429
|
+
```bash
|
|
430
|
+
cd android
|
|
431
|
+
./gradlew clean
|
|
432
|
+
cd ..
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Then rebuild your app.
|
|
436
|
+
|
|
437
|
+
### "Module not found" Error
|
|
438
|
+
|
|
439
|
+
Make sure you've:
|
|
440
|
+
1. Installed the package
|
|
441
|
+
2. Run `pod install` on iOS
|
|
442
|
+
3. Rebuilt the app completely
|
|
443
|
+
|
|
444
|
+
## Contributing
|
|
445
|
+
|
|
446
|
+
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
|
|
447
|
+
|
|
448
|
+
## License
|
|
449
|
+
|
|
450
|
+
MIT
|
|
451
|
+
|
|
452
|
+
## Support
|
|
453
|
+
|
|
454
|
+
- GitHub Issues: https://github.com/byrizki/json-eval-rs/issues
|
|
455
|
+
- Documentation: https://github.com/byrizki/json-eval-rs
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.9.0)
|
|
2
|
+
|
|
3
|
+
project(json-eval-rn)
|
|
4
|
+
|
|
5
|
+
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
6
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
7
|
+
|
|
8
|
+
# Find React Native
|
|
9
|
+
find_package(ReactAndroid REQUIRED CONFIG)
|
|
10
|
+
|
|
11
|
+
# Pre-built Rust library (bundled with npm package)
|
|
12
|
+
# The library is located in src/main/jniLibs/[abi]/libjson_eval_rs.so
|
|
13
|
+
set(RUST_PREBUILT_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
|
|
14
|
+
set(RUST_LIB_PATH ${RUST_PREBUILT_DIR}/libjson_eval_rs.so)
|
|
15
|
+
|
|
16
|
+
message(STATUS "Looking for pre-built Rust library at: ${RUST_LIB_PATH}")
|
|
17
|
+
|
|
18
|
+
# Check if pre-built library exists
|
|
19
|
+
if(NOT EXISTS ${RUST_LIB_PATH})
|
|
20
|
+
message(FATAL_ERROR
|
|
21
|
+
"Pre-built Rust library not found at: ${RUST_LIB_PATH}\n"
|
|
22
|
+
"\nThis package requires pre-built native libraries.\n"
|
|
23
|
+
"If you're developing this package, build the libraries first:\n"
|
|
24
|
+
" cd ${CMAKE_SOURCE_DIR}/../..\n"
|
|
25
|
+
" ./build-android.sh all\n"
|
|
26
|
+
"\nIf you're a user and seeing this error, the package may be corrupted.\n"
|
|
27
|
+
"Try reinstalling: npm install @json-eval-rs/react-native\n"
|
|
28
|
+
"\nCurrent ANDROID_ABI: ${ANDROID_ABI}")
|
|
29
|
+
endif()
|
|
30
|
+
|
|
31
|
+
message(STATUS "Using pre-built Rust library: ${RUST_LIB_PATH}")
|
|
32
|
+
|
|
33
|
+
# Add library search path for the Rust library
|
|
34
|
+
link_directories(${RUST_PREBUILT_DIR})
|
|
35
|
+
|
|
36
|
+
# C++ Bridge files
|
|
37
|
+
add_library(
|
|
38
|
+
json_eval_rn
|
|
39
|
+
SHARED
|
|
40
|
+
src/main/cpp/json-eval-rn.cpp
|
|
41
|
+
../cpp/json-eval-bridge.cpp
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Include directories
|
|
45
|
+
target_include_directories(
|
|
46
|
+
json_eval_rn
|
|
47
|
+
PRIVATE
|
|
48
|
+
../cpp
|
|
49
|
+
src/main/cpp
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Link libraries
|
|
53
|
+
# Note: React Native provides JSI and other libraries at runtime
|
|
54
|
+
# We link against them for compilation, but they should not be packaged
|
|
55
|
+
target_link_libraries(
|
|
56
|
+
json_eval_rn
|
|
57
|
+
json_eval_rs
|
|
58
|
+
android
|
|
59
|
+
log
|
|
60
|
+
ReactAndroid::jsi
|
|
61
|
+
ReactAndroid::reactnativejni
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Modern React Native (0.71+) uses prefab which properly handles shared libraries
|
|
65
|
+
# The libraries are marked as shared dependencies, not to be packaged in our module
|
|
66
|
+
# If you still see duplicate library warnings, ensure your React Native version is up to date
|
|
67
|
+
|
|
68
|
+
# Optimize binary size
|
|
69
|
+
set_target_properties(json_eval_rn PROPERTIES
|
|
70
|
+
CXX_VISIBILITY_PRESET hidden
|
|
71
|
+
C_VISIBILITY_PRESET hidden
|
|
72
|
+
VISIBILITY_INLINES_HIDDEN ON
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Strip debug symbols in release builds
|
|
76
|
+
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
|
77
|
+
target_link_options(json_eval_rn PRIVATE -Wl,--strip-all)
|
|
78
|
+
endif()
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.kotlin_version = '1.8.0'
|
|
3
|
+
repositories {
|
|
4
|
+
google()
|
|
5
|
+
mavenCentral()
|
|
6
|
+
}
|
|
7
|
+
dependencies {
|
|
8
|
+
classpath 'com.android.tools.build:gradle:7.4.0'
|
|
9
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
apply plugin: 'com.android.library'
|
|
14
|
+
apply plugin: 'kotlin-android'
|
|
15
|
+
|
|
16
|
+
def reactNative = rootProject.allprojects
|
|
17
|
+
.find { it.name == 'ReactAndroid' }
|
|
18
|
+
|
|
19
|
+
def safeExtGet(prop, fallback) {
|
|
20
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
android {
|
|
24
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 33)
|
|
25
|
+
|
|
26
|
+
namespace "com.jsonevalrs"
|
|
27
|
+
|
|
28
|
+
defaultConfig {
|
|
29
|
+
minSdkVersion safeExtGet('minSdkVersion', 21)
|
|
30
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 33)
|
|
31
|
+
|
|
32
|
+
externalNativeBuild {
|
|
33
|
+
cmake {
|
|
34
|
+
cppFlags "-std=c++17 -fexceptions -frtti"
|
|
35
|
+
arguments "-DANDROID_STL=c++_shared"
|
|
36
|
+
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
buildFeatures {
|
|
42
|
+
prefab true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
externalNativeBuild {
|
|
46
|
+
cmake {
|
|
47
|
+
path "CMakeLists.txt"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
buildTypes {
|
|
52
|
+
release {
|
|
53
|
+
minifyEnabled false
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
sourceSets {
|
|
58
|
+
main {
|
|
59
|
+
java.srcDirs = ['src/main/java']
|
|
60
|
+
jniLibs.srcDirs = ['src/main/jniLibs']
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
lintOptions {
|
|
65
|
+
abortOnError false
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
packagingOptions {
|
|
69
|
+
// Exclude React Native libraries - they're provided by the app
|
|
70
|
+
// This prevents duplicate .so files and eliminates the need for pickFirst in the app
|
|
71
|
+
exclude 'lib/**/libjsi.so'
|
|
72
|
+
exclude 'lib/**/libc++_shared.so'
|
|
73
|
+
exclude 'lib/**/libreactnativejni.so'
|
|
74
|
+
exclude 'lib/**/libfbjni.so'
|
|
75
|
+
|
|
76
|
+
// Keep only our module's native library
|
|
77
|
+
// pickFirst is used as fallback for any remaining conflicts
|
|
78
|
+
pickFirst 'META-INF/**'
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
repositories {
|
|
83
|
+
google()
|
|
84
|
+
mavenCentral()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
dependencies {
|
|
88
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
89
|
+
implementation 'com.facebook.react:react-native:+'
|
|
90
|
+
}
|