@swiftpatch/react-native 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +430 -0
  2. package/android/build.gradle +105 -0
  3. package/android/src/main/AndroidManifest.xml +6 -0
  4. package/android/src/main/java/com/swiftpatch/BundleManager.kt +107 -0
  5. package/android/src/main/java/com/swiftpatch/CrashDetector.kt +79 -0
  6. package/android/src/main/java/com/swiftpatch/CryptoVerifier.kt +69 -0
  7. package/android/src/main/java/com/swiftpatch/DownloadManager.kt +120 -0
  8. package/android/src/main/java/com/swiftpatch/EventQueue.kt +86 -0
  9. package/android/src/main/java/com/swiftpatch/FileUtils.kt +60 -0
  10. package/android/src/main/java/com/swiftpatch/PatchApplier.kt +60 -0
  11. package/android/src/main/java/com/swiftpatch/SignalCrashHandler.kt +84 -0
  12. package/android/src/main/java/com/swiftpatch/SlotManager.kt +299 -0
  13. package/android/src/main/java/com/swiftpatch/SwiftPatchModule.kt +630 -0
  14. package/android/src/main/java/com/swiftpatch/SwiftPatchPackage.kt +21 -0
  15. package/android/src/main/jni/CMakeLists.txt +12 -0
  16. package/android/src/main/jni/bspatch.c +188 -0
  17. package/android/src/main/jni/bspatch.h +57 -0
  18. package/android/src/main/jni/bspatch_jni.c +28 -0
  19. package/ios/Libraries/bspatch/bspatch.c +188 -0
  20. package/ios/Libraries/bspatch/bspatch.h +50 -0
  21. package/ios/Libraries/bspatch/module.modulemap +4 -0
  22. package/ios/SwiftPatch/BundleManager.swift +113 -0
  23. package/ios/SwiftPatch/CrashDetector.swift +71 -0
  24. package/ios/SwiftPatch/CryptoVerifier.swift +70 -0
  25. package/ios/SwiftPatch/DownloadManager.swift +125 -0
  26. package/ios/SwiftPatch/EventQueue.swift +116 -0
  27. package/ios/SwiftPatch/FileUtils.swift +38 -0
  28. package/ios/SwiftPatch/PatchApplier.swift +41 -0
  29. package/ios/SwiftPatch/SignalCrashHandler.swift +129 -0
  30. package/ios/SwiftPatch/SlotManager.swift +360 -0
  31. package/ios/SwiftPatch/SwiftPatchModule.m +56 -0
  32. package/ios/SwiftPatch/SwiftPatchModule.swift +621 -0
  33. package/lib/commonjs/SwiftPatchCore.js +140 -0
  34. package/lib/commonjs/SwiftPatchCore.js.map +1 -0
  35. package/lib/commonjs/SwiftPatchProvider.js +617 -0
  36. package/lib/commonjs/SwiftPatchProvider.js.map +1 -0
  37. package/lib/commonjs/constants.js +50 -0
  38. package/lib/commonjs/constants.js.map +1 -0
  39. package/lib/commonjs/core/Downloader.js +63 -0
  40. package/lib/commonjs/core/Downloader.js.map +1 -0
  41. package/lib/commonjs/core/Installer.js +46 -0
  42. package/lib/commonjs/core/Installer.js.map +1 -0
  43. package/lib/commonjs/core/Rollback.js +36 -0
  44. package/lib/commonjs/core/Rollback.js.map +1 -0
  45. package/lib/commonjs/core/UpdateChecker.js +57 -0
  46. package/lib/commonjs/core/UpdateChecker.js.map +1 -0
  47. package/lib/commonjs/core/Verifier.js +82 -0
  48. package/lib/commonjs/core/Verifier.js.map +1 -0
  49. package/lib/commonjs/core/index.js +41 -0
  50. package/lib/commonjs/core/index.js.map +1 -0
  51. package/lib/commonjs/index.js +154 -0
  52. package/lib/commonjs/index.js.map +1 -0
  53. package/lib/commonjs/modal/SwiftPatchModal.js +667 -0
  54. package/lib/commonjs/modal/SwiftPatchModal.js.map +1 -0
  55. package/lib/commonjs/modal/useSwiftPatchModal.js +26 -0
  56. package/lib/commonjs/modal/useSwiftPatchModal.js.map +1 -0
  57. package/lib/commonjs/native/NativeSwiftPatch.js +85 -0
  58. package/lib/commonjs/native/NativeSwiftPatch.js.map +1 -0
  59. package/lib/commonjs/native/NativeSwiftPatchSpec.js +15 -0
  60. package/lib/commonjs/native/NativeSwiftPatchSpec.js.map +1 -0
  61. package/lib/commonjs/package.json +1 -0
  62. package/lib/commonjs/types.js +126 -0
  63. package/lib/commonjs/types.js.map +1 -0
  64. package/lib/commonjs/useSwiftPatch.js +31 -0
  65. package/lib/commonjs/useSwiftPatch.js.map +1 -0
  66. package/lib/commonjs/utils/api.js +206 -0
  67. package/lib/commonjs/utils/api.js.map +1 -0
  68. package/lib/commonjs/utils/device.js +23 -0
  69. package/lib/commonjs/utils/device.js.map +1 -0
  70. package/lib/commonjs/utils/logger.js +30 -0
  71. package/lib/commonjs/utils/logger.js.map +1 -0
  72. package/lib/commonjs/utils/storage.js +31 -0
  73. package/lib/commonjs/utils/storage.js.map +1 -0
  74. package/lib/commonjs/withSwiftPatch.js +42 -0
  75. package/lib/commonjs/withSwiftPatch.js.map +1 -0
  76. package/lib/module/SwiftPatchCore.js +135 -0
  77. package/lib/module/SwiftPatchCore.js.map +1 -0
  78. package/lib/module/SwiftPatchProvider.js +611 -0
  79. package/lib/module/SwiftPatchProvider.js.map +1 -0
  80. package/lib/module/constants.js +46 -0
  81. package/lib/module/constants.js.map +1 -0
  82. package/lib/module/core/Downloader.js +57 -0
  83. package/lib/module/core/Downloader.js.map +1 -0
  84. package/lib/module/core/Installer.js +41 -0
  85. package/lib/module/core/Installer.js.map +1 -0
  86. package/lib/module/core/Rollback.js +31 -0
  87. package/lib/module/core/Rollback.js.map +1 -0
  88. package/lib/module/core/UpdateChecker.js +51 -0
  89. package/lib/module/core/UpdateChecker.js.map +1 -0
  90. package/lib/module/core/Verifier.js +76 -0
  91. package/lib/module/core/Verifier.js.map +1 -0
  92. package/lib/module/core/index.js +8 -0
  93. package/lib/module/core/index.js.map +1 -0
  94. package/lib/module/index.js +34 -0
  95. package/lib/module/index.js.map +1 -0
  96. package/lib/module/modal/SwiftPatchModal.js +661 -0
  97. package/lib/module/modal/SwiftPatchModal.js.map +1 -0
  98. package/lib/module/modal/useSwiftPatchModal.js +22 -0
  99. package/lib/module/modal/useSwiftPatchModal.js.map +1 -0
  100. package/lib/module/native/NativeSwiftPatch.js +78 -0
  101. package/lib/module/native/NativeSwiftPatch.js.map +1 -0
  102. package/lib/module/native/NativeSwiftPatchSpec.js +12 -0
  103. package/lib/module/native/NativeSwiftPatchSpec.js.map +1 -0
  104. package/lib/module/types.js +139 -0
  105. package/lib/module/types.js.map +1 -0
  106. package/lib/module/useSwiftPatch.js +26 -0
  107. package/lib/module/useSwiftPatch.js.map +1 -0
  108. package/lib/module/utils/api.js +197 -0
  109. package/lib/module/utils/api.js.map +1 -0
  110. package/lib/module/utils/device.js +18 -0
  111. package/lib/module/utils/device.js.map +1 -0
  112. package/lib/module/utils/logger.js +26 -0
  113. package/lib/module/utils/logger.js.map +1 -0
  114. package/lib/module/utils/storage.js +24 -0
  115. package/lib/module/utils/storage.js.map +1 -0
  116. package/lib/module/withSwiftPatch.js +37 -0
  117. package/lib/module/withSwiftPatch.js.map +1 -0
  118. package/lib/typescript/SwiftPatchCore.d.ts +64 -0
  119. package/lib/typescript/SwiftPatchCore.d.ts.map +1 -0
  120. package/lib/typescript/SwiftPatchProvider.d.ts +22 -0
  121. package/lib/typescript/SwiftPatchProvider.d.ts.map +1 -0
  122. package/lib/typescript/constants.d.ts +33 -0
  123. package/lib/typescript/constants.d.ts.map +1 -0
  124. package/lib/typescript/core/Downloader.d.ts +34 -0
  125. package/lib/typescript/core/Downloader.d.ts.map +1 -0
  126. package/lib/typescript/core/Installer.d.ts +25 -0
  127. package/lib/typescript/core/Installer.d.ts.map +1 -0
  128. package/lib/typescript/core/Rollback.d.ts +18 -0
  129. package/lib/typescript/core/Rollback.d.ts.map +1 -0
  130. package/lib/typescript/core/UpdateChecker.d.ts +27 -0
  131. package/lib/typescript/core/UpdateChecker.d.ts.map +1 -0
  132. package/lib/typescript/core/Verifier.d.ts +31 -0
  133. package/lib/typescript/core/Verifier.d.ts.map +1 -0
  134. package/lib/typescript/core/index.d.ts +8 -0
  135. package/lib/typescript/core/index.d.ts.map +1 -0
  136. package/lib/typescript/index.d.ts +13 -0
  137. package/lib/typescript/index.d.ts.map +1 -0
  138. package/lib/typescript/modal/SwiftPatchModal.d.ts +11 -0
  139. package/lib/typescript/modal/SwiftPatchModal.d.ts.map +1 -0
  140. package/lib/typescript/modal/useSwiftPatchModal.d.ts +7 -0
  141. package/lib/typescript/modal/useSwiftPatchModal.d.ts.map +1 -0
  142. package/lib/typescript/native/NativeSwiftPatch.d.ts +61 -0
  143. package/lib/typescript/native/NativeSwiftPatch.d.ts.map +1 -0
  144. package/lib/typescript/native/NativeSwiftPatchSpec.d.ts +67 -0
  145. package/lib/typescript/native/NativeSwiftPatchSpec.d.ts.map +1 -0
  146. package/lib/typescript/types.d.ts +266 -0
  147. package/lib/typescript/types.d.ts.map +1 -0
  148. package/lib/typescript/useSwiftPatch.d.ts +12 -0
  149. package/lib/typescript/useSwiftPatch.d.ts.map +1 -0
  150. package/lib/typescript/utils/api.d.ts +87 -0
  151. package/lib/typescript/utils/api.d.ts.map +1 -0
  152. package/lib/typescript/utils/device.d.ts +9 -0
  153. package/lib/typescript/utils/device.d.ts.map +1 -0
  154. package/lib/typescript/utils/logger.d.ts +8 -0
  155. package/lib/typescript/utils/logger.d.ts.map +1 -0
  156. package/lib/typescript/utils/storage.d.ts +14 -0
  157. package/lib/typescript/utils/storage.d.ts.map +1 -0
  158. package/lib/typescript/withSwiftPatch.d.ts +12 -0
  159. package/lib/typescript/withSwiftPatch.d.ts.map +1 -0
  160. package/package.json +99 -0
  161. package/react-native-swiftpatch.podspec +50 -0
  162. package/src/SwiftPatchCore.ts +148 -0
  163. package/src/SwiftPatchProvider.tsx +514 -0
  164. package/src/constants.ts +49 -0
  165. package/src/core/Downloader.ts +74 -0
  166. package/src/core/Installer.ts +38 -0
  167. package/src/core/Rollback.ts +28 -0
  168. package/src/core/UpdateChecker.ts +70 -0
  169. package/src/core/Verifier.ts +92 -0
  170. package/src/core/index.ts +11 -0
  171. package/src/index.ts +64 -0
  172. package/src/modal/SwiftPatchModal.tsx +657 -0
  173. package/src/modal/useSwiftPatchModal.ts +24 -0
  174. package/src/native/NativeSwiftPatch.ts +205 -0
  175. package/src/native/NativeSwiftPatchSpec.ts +139 -0
  176. package/src/types.ts +336 -0
  177. package/src/useSwiftPatch.ts +29 -0
  178. package/src/utils/api.ts +244 -0
  179. package/src/utils/device.ts +15 -0
  180. package/src/utils/logger.ts +29 -0
  181. package/src/utils/storage.ts +23 -0
  182. package/src/withSwiftPatch.tsx +41 -0
package/README.md ADDED
@@ -0,0 +1,430 @@
1
+ # SwiftPatch React Native SDK
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@swiftpatch/react-native.svg)](https://www.npmjs.com/package/@swiftpatch/react-native)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![React Native](https://img.shields.io/badge/React%20Native-0.76+-blue.svg)](https://reactnative.dev/)
6
+ [![New Architecture](https://img.shields.io/badge/New%20Architecture-Supported-green.svg)](https://reactnative.dev/architecture/landing-page)
7
+
8
+ Over-the-Air (OTA) update SDK for React Native with **differential patching**, automatic rollback, and cryptographic verification. Optimized for the React Native New Architecture.
9
+
10
+ ## ✨ Features
11
+
12
+ - 🚀 **Differential Patching** - Download only what changed (bsdiff/bspatch)
13
+ - 🔄 **Automatic Rollback** - Crash detection with instant recovery
14
+ - 🔒 **Bundle Signing** - RSA signature verification for security
15
+ - ⚡ **New Architecture** - TurboModules for 40% faster performance
16
+ - 🎯 **Dual-Slot System** - Safe production/staging environment switching
17
+ - 📦 **Small Updates** - Patches typically 10-50x smaller than full bundles
18
+ - 🛡️ **Type-Safe** - Full TypeScript support
19
+ - 🎨 **React Hooks** - Modern API with Provider pattern
20
+ - 📱 **Cross-Platform** - iOS and Android support
21
+
22
+ ---
23
+
24
+ ## 📦 Installation
25
+
26
+ ```bash
27
+ npm install @swiftpatch/react-native
28
+ # or
29
+ yarn add @swiftpatch/react-native
30
+ ```
31
+
32
+ ### iOS Setup
33
+
34
+ ```bash
35
+ cd ios
36
+ pod install
37
+ cd ..
38
+ ```
39
+
40
+ ### Android Setup
41
+
42
+ No additional steps required.
43
+
44
+ ---
45
+
46
+ ## 🚀 Quick Start
47
+
48
+ ### 1. Wrap your app with SwiftPatchProvider
49
+
50
+ ```tsx
51
+ import { SwiftPatchProvider } from '@swiftpatch/react-native';
52
+
53
+ export default function App() {
54
+ return (
55
+ <SwiftPatchProvider
56
+ config={{
57
+ deploymentKey: 'YOUR_DEPLOYMENT_KEY',
58
+ serverUrl: 'https://your-server.com/api/v1', // optional
59
+ debug: __DEV__,
60
+ }}
61
+ >
62
+ <YourApp />
63
+ </SwiftPatchProvider>
64
+ );
65
+ }
66
+ ```
67
+
68
+ ### 2. Use the hook in your components
69
+
70
+ ```tsx
71
+ import { useSwiftPatch, UpdateStatus } from '@swiftpatch/react-native';
72
+
73
+ function UpdateButton() {
74
+ const {
75
+ status,
76
+ availableUpdate,
77
+ downloadProgress,
78
+ checkForUpdate,
79
+ downloadUpdate,
80
+ installUpdate,
81
+ restart,
82
+ } = useSwiftPatch();
83
+
84
+ const handleUpdate = async () => {
85
+ // Check for updates
86
+ const update = await checkForUpdate();
87
+
88
+ if (update) {
89
+ // Download the update
90
+ await downloadUpdate();
91
+
92
+ // Install and restart
93
+ await installUpdate();
94
+ restart();
95
+ }
96
+ };
97
+
98
+ if (status === UpdateStatus.DOWNLOADING) {
99
+ return <Text>Downloading: {downloadProgress?.percentage}%</Text>;
100
+ }
101
+
102
+ return (
103
+ <Button
104
+ title={availableUpdate ? 'Update Available' : 'Check for Updates'}
105
+ onPress={handleUpdate}
106
+ />
107
+ );
108
+ }
109
+ ```
110
+
111
+ ### 3. Or use the built-in modal
112
+
113
+ ```tsx
114
+ import { useSwiftPatchModal, SwiftPatchModal } from '@swiftpatch/react-native';
115
+
116
+ function App() {
117
+ const { showModal } = useSwiftPatchModal();
118
+
119
+ return (
120
+ <>
121
+ <YourApp />
122
+ <SwiftPatchModal />
123
+ <Button title="Check for Updates" onPress={showModal} />
124
+ </>
125
+ );
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 📚 API Reference
132
+
133
+ ### SwiftPatchProvider
134
+
135
+ ```tsx
136
+ interface SwiftPatchConfig {
137
+ deploymentKey: string;
138
+ serverUrl?: string;
139
+ checkOnResume?: boolean;
140
+ checkInterval?: number;
141
+ installMode?: InstallMode;
142
+ mandatoryInstallMode?: InstallMode;
143
+ debug?: boolean;
144
+ customHeaders?: Record<string, string>;
145
+ publicKey?: string;
146
+ autoStabilizeAfterLaunches?: number;
147
+ }
148
+ ```
149
+
150
+ ### useSwiftPatch Hook
151
+
152
+ ```tsx
153
+ const {
154
+ // State
155
+ status, // Current update status
156
+ downloadProgress, // Download progress (0-100%)
157
+ currentBundle, // Currently installed bundle info
158
+ availableUpdate, // Available update info
159
+ isRestartRequired, // Whether restart is needed
160
+ error, // Last error
161
+ lastCheckedAt, // Last check timestamp
162
+ slotMetadata, // Dual-slot system metadata
163
+ environment, // Current environment (PROD/STAGE)
164
+
165
+ // Actions
166
+ checkForUpdate, // Check for available updates
167
+ downloadUpdate, // Download available update
168
+ installUpdate, // Install downloaded update
169
+ restart, // Restart app to apply update
170
+ rollback, // Rollback to previous version
171
+ clearPendingUpdate, // Clear pending update
172
+ getCurrentBundle, // Get current bundle info
173
+ stabilize, // Stabilize current bundle
174
+ switchEnvironment, // Switch PROD/STAGE environment
175
+ getSlotMetadata, // Get slot metadata
176
+ markMounted, // Mark app as mounted (crash detection)
177
+ downloadStageBundle, // Download staging bundle
178
+ } = useSwiftPatch();
179
+ ```
180
+
181
+ ### Imperative API (Non-React)
182
+
183
+ For use outside React components:
184
+
185
+ ```tsx
186
+ import { SwiftPatch } from '@swiftpatch/react-native';
187
+
188
+ const swiftPatch = new SwiftPatch({
189
+ deploymentKey: 'YOUR_KEY',
190
+ });
191
+
192
+ await swiftPatch.init();
193
+
194
+ const update = await swiftPatch.checkForUpdate();
195
+ if (update) {
196
+ await swiftPatch.downloadAndInstall(update);
197
+ swiftPatch.restart();
198
+ }
199
+ ```
200
+
201
+ ---
202
+
203
+ ## 🎯 Install Modes
204
+
205
+ ```tsx
206
+ enum InstallMode {
207
+ IMMEDIATE = 'immediate', // Install and restart immediately
208
+ ON_NEXT_RESTART = 'onNextRestart', // Install on next app restart
209
+ ON_NEXT_RESUME = 'onNextResume', // Install when app resumes
210
+ }
211
+ ```
212
+
213
+ ---
214
+
215
+ ## 🔧 Advanced Features
216
+
217
+ ### Differential Patching
218
+
219
+ SwiftPatch automatically uses differential patching when available:
220
+
221
+ ```tsx
222
+ // Server determines if patch is available
223
+ // SDK handles full bundle vs patch automatically
224
+ await downloadUpdate();
225
+
226
+ // Patch files are typically 10-50x smaller
227
+ // e.g., 50MB bundle → 2MB patch
228
+ ```
229
+
230
+ ### Automatic Rollback
231
+
232
+ ```tsx
233
+ // Crash detection window: 10 seconds
234
+ // If app crashes during this window, automatic rollback occurs
235
+
236
+ const { rollback } = useSwiftPatch();
237
+
238
+ // Manual rollback
239
+ await rollback();
240
+ ```
241
+
242
+ ### Bundle Signing (Optional)
243
+
244
+ ```tsx
245
+ <SwiftPatchProvider
246
+ config={{
247
+ deploymentKey: 'YOUR_KEY',
248
+ publicKey: 'YOUR_RSA_PUBLIC_KEY',
249
+ }}
250
+ >
251
+ <App />
252
+ </SwiftPatchProvider>
253
+
254
+ // SDK automatically verifies signatures
255
+ ```
256
+
257
+ ### Environment Switching (PROD/STAGE)
258
+
259
+ ```tsx
260
+ const { switchEnvironment, environment } = useSwiftPatch();
261
+
262
+ // Switch to staging
263
+ await switchEnvironment(EnvironmentMode.STAGING);
264
+
265
+ // Download and test staging bundle
266
+ await downloadStageBundle(url, hash);
267
+
268
+ // Switch back to production
269
+ await switchEnvironment(EnvironmentMode.PRODUCTION);
270
+ ```
271
+
272
+ ---
273
+
274
+ ## 🆕 New Architecture Support
275
+
276
+ SwiftPatch v2.0+ fully supports the React Native New Architecture:
277
+
278
+ ### Enable New Architecture
279
+
280
+ **iOS** (`ios/Podfile`):
281
+ ```ruby
282
+ ENV['RCT_NEW_ARCH_ENABLED'] = '1'
283
+ ```
284
+
285
+ **Android** (`android/gradle.properties`):
286
+ ```properties
287
+ newArchEnabled=true
288
+ ```
289
+
290
+ ### Performance Benefits
291
+
292
+ | Operation | Legacy | TurboModule | Improvement |
293
+ |-----------|--------|-------------|-------------|
294
+ | Check Update | 15ms | 2ms | 87% faster |
295
+ | Get Bundle Info | 8ms | 1ms | 87% faster |
296
+ | Native Calls | 3-5ms | 0.5-1ms | 80% faster |
297
+
298
+ ### Detection
299
+
300
+ ```tsx
301
+ import { IS_TURBO_MODULE_ENABLED } from '@swiftpatch/react-native';
302
+
303
+ console.log('Using TurboModules:', IS_TURBO_MODULE_ENABLED);
304
+ ```
305
+
306
+ ---
307
+
308
+ ## 🧪 Testing
309
+
310
+ ```bash
311
+ npm test
312
+ ```
313
+
314
+ All core functionality is tested:
315
+ - Update checking
316
+ - Download & installation
317
+ - Rollback mechanisms
318
+ - Cryptographic verification
319
+ - Event handling
320
+
321
+ ---
322
+
323
+ ## 📱 Platform Requirements
324
+
325
+ | Platform | Minimum | Recommended |
326
+ |----------|---------|-------------|
327
+ | iOS | 13.4+ | 15.0+ |
328
+ | Android | API 24+ (7.0) | API 31+ (12) |
329
+ | React Native | 0.76.0+ | 0.76.5+ |
330
+ | React | 18.2.0+ | 18.3.0+ |
331
+
332
+ ---
333
+
334
+ ## 🔒 Security
335
+
336
+ - **Bundle Signing**: Optional RSA signature verification
337
+ - **HTTPS Only**: All downloads over secure connections
338
+ - **Hash Verification**: SHA-256 hash checking for all bundles
339
+ - **Integrity Checks**: Automatic corruption detection
340
+
341
+ ---
342
+
343
+ ## 📊 Bundle Size
344
+
345
+ | File | Size | Compressed |
346
+ |------|------|------------|
347
+ | Core JS | ~45KB | ~12KB |
348
+ | Native (iOS) | ~150KB | - |
349
+ | Native (Android) | ~200KB | - |
350
+
351
+ ---
352
+
353
+ ## 🛠️ Development
354
+
355
+ ```bash
356
+ # Clone the repository
357
+ git clone https://github.com/codewprincee/react-native-swiftpatch.git
358
+
359
+ # Install dependencies
360
+ npm install
361
+
362
+ # Run tests
363
+ npm test
364
+
365
+ # Build
366
+ npm run prepare
367
+
368
+ # Run example app
369
+ npm run example start
370
+ ```
371
+
372
+ ---
373
+
374
+ ## 🐛 Troubleshooting
375
+
376
+ ### iOS Build Errors
377
+
378
+ ```bash
379
+ cd ios
380
+ rm -rf Pods Podfile.lock
381
+ pod install
382
+ cd ..
383
+ ```
384
+
385
+ ### Android Build Errors
386
+
387
+ ```bash
388
+ cd android
389
+ ./gradlew clean
390
+ cd ..
391
+ ```
392
+
393
+ ### Type Errors
394
+
395
+ ```bash
396
+ npm run typescript
397
+ ```
398
+
399
+ ---
400
+
401
+ ## 📄 License
402
+
403
+ MIT License - see [LICENSE](LICENSE) for details
404
+
405
+ ---
406
+
407
+ ## 🤝 Contributing
408
+
409
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) first.
410
+
411
+ ---
412
+
413
+ ## 📞 Support
414
+
415
+ - 📧 Email: sdk@swiftpatch.io
416
+ - 🐛 Issues: [GitHub Issues](https://github.com/codewprincee/react-native-swiftpatch/issues)
417
+ - 📖 Docs: [swiftpatch.io](https://swiftpatch.io)
418
+
419
+ ---
420
+
421
+ ## 🎉 Acknowledgments
422
+
423
+ Built with:
424
+ - [React Native](https://reactnative.dev/)
425
+ - [bsdiff/bspatch](http://www.daemonology.net/bsdiff/) for differential patching
426
+ - [TypeScript](https://www.typescriptlang.org/)
427
+
428
+ ---
429
+
430
+ **Made with ❤️ by the SwiftPatch Team**
@@ -0,0 +1,105 @@
1
+ buildscript {
2
+ ext.safeExtGet = {prop, fallback ->
3
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4
+ }
5
+ repositories {
6
+ google()
7
+ mavenCentral()
8
+ }
9
+ dependencies {
10
+ classpath("com.android.tools.build:gradle:8.7.3")
11
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '2.0.21')}")
12
+ }
13
+ }
14
+
15
+ def isNewArchitectureEnabled() {
16
+ return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
17
+ }
18
+
19
+ apply plugin: "com.android.library"
20
+ apply plugin: "kotlin-android"
21
+
22
+ if (isNewArchitectureEnabled()) {
23
+ apply plugin: "com.facebook.react"
24
+ }
25
+
26
+ def reactNativeArchitectures() {
27
+ def value = project.getProperties().get("reactNativeArchitectures")
28
+ return value ? value.split(",") : ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]
29
+ }
30
+
31
+ android {
32
+ namespace "com.swiftpatch"
33
+ compileSdkVersion safeExtGet("compileSdkVersion", 35)
34
+
35
+ defaultConfig {
36
+ minSdkVersion safeExtGet("minSdkVersion", 24)
37
+ targetSdkVersion safeExtGet("targetSdkVersion", 35)
38
+
39
+ ndk {
40
+ abiFilters(*reactNativeArchitectures())
41
+ }
42
+
43
+ externalNativeBuild {
44
+ cmake {
45
+ cppFlags "-std=c++17"
46
+ arguments "-DANDROID_STL=c++_shared"
47
+ }
48
+ }
49
+
50
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
51
+ }
52
+
53
+ externalNativeBuild {
54
+ cmake {
55
+ path "src/main/jni/CMakeLists.txt"
56
+ }
57
+ }
58
+
59
+ buildFeatures {
60
+ buildConfig true
61
+ }
62
+
63
+ buildTypes {
64
+ release {
65
+ minifyEnabled false
66
+ }
67
+ }
68
+
69
+ compileOptions {
70
+ sourceCompatibility JavaVersion.VERSION_17
71
+ targetCompatibility JavaVersion.VERSION_17
72
+ }
73
+
74
+ kotlinOptions {
75
+ jvmTarget = "17"
76
+ }
77
+
78
+ sourceSets {
79
+ main {
80
+ java.srcDirs = ['src/main/java']
81
+ if (isNewArchitectureEnabled()) {
82
+ java.srcDirs += ['build/generated/source/codegen/java']
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ repositories {
89
+ mavenCentral()
90
+ google()
91
+ maven {
92
+ url "$projectDir/../node_modules/react-native/android"
93
+ }
94
+ }
95
+
96
+ dependencies {
97
+ implementation "com.facebook.react:react-android:+"
98
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:${safeExtGet('kotlinVersion', '2.0.21')}"
99
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0"
100
+
101
+ if (isNewArchitectureEnabled()) {
102
+ implementation "com.facebook.react:react-native:+"
103
+ implementation "androidx.annotation:annotation:1.9.1"
104
+ }
105
+ }
@@ -0,0 +1,6 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.swiftpatch">
3
+
4
+ <uses-permission android:name="android.permission.INTERNET" />
5
+
6
+ </manifest>
@@ -0,0 +1,107 @@
1
+ package com.swiftpatch
2
+
3
+ import android.content.Context
4
+ import android.content.SharedPreferences
5
+ import java.io.File
6
+ import java.io.FileOutputStream
7
+
8
+ class BundleManager(private val context: Context) {
9
+
10
+ private val baseDir: File
11
+ get() = File(context.filesDir, "swiftpatch")
12
+
13
+ private val bundlesDir: File
14
+ get() = File(baseDir, "bundles")
15
+
16
+ private val patchesDir: File
17
+ get() = File(baseDir, "patches")
18
+
19
+ private val tempDir: File
20
+ get() = File(baseDir, "temp")
21
+
22
+ /**
23
+ * Ensure all required directories exist
24
+ */
25
+ fun ensureDirectoriesExist() {
26
+ bundlesDir.mkdirs()
27
+ patchesDir.mkdirs()
28
+ tempDir.mkdirs()
29
+ }
30
+
31
+ /**
32
+ * Get the file path for a downloaded update (before processing)
33
+ */
34
+ fun getDownloadFile(hash: String): File {
35
+ return File(tempDir, "$hash.download")
36
+ }
37
+
38
+ /**
39
+ * Get the file path for a decompressed file
40
+ */
41
+ fun getDecompressedFile(hash: String): File {
42
+ return File(tempDir, "$hash.decompressed")
43
+ }
44
+
45
+ /**
46
+ * Get the file path for a bundle by its hash
47
+ */
48
+ fun getBundleFile(hash: String): File {
49
+ return File(bundlesDir, "$hash.bundle")
50
+ }
51
+
52
+ /**
53
+ * Extract the original bundled JS bundle from APK assets
54
+ */
55
+ fun extractOriginalBundle(context: Context): File {
56
+ val originalFile = File(tempDir, "original.bundle")
57
+ if (originalFile.exists()) {
58
+ return originalFile
59
+ }
60
+
61
+ try {
62
+ context.assets.open("index.android.bundle").use { input ->
63
+ FileOutputStream(originalFile).use { output ->
64
+ input.copyTo(output)
65
+ }
66
+ }
67
+ } catch (_: Exception) {
68
+ // Try alternate bundle name
69
+ context.assets.open("main.jsbundle").use { input ->
70
+ FileOutputStream(originalFile).use { output ->
71
+ input.copyTo(output)
72
+ }
73
+ }
74
+ }
75
+
76
+ return originalFile
77
+ }
78
+
79
+ /**
80
+ * Clean up old bundles that are no longer needed.
81
+ * Keeps only the current and previous bundles.
82
+ */
83
+ fun cleanupOldBundles(prefs: SharedPreferences) {
84
+ val currentHash = prefs.getString("current_bundle_hash", null)
85
+ val previousHash = prefs.getString("previous_bundle_hash", null)
86
+
87
+ val keepHashes = setOfNotNull(currentHash, previousHash)
88
+
89
+ // Clean up bundles
90
+ bundlesDir.listFiles()?.forEach { file ->
91
+ val fileHash = file.nameWithoutExtension
92
+ if (fileHash !in keepHashes) {
93
+ file.delete()
94
+ }
95
+ }
96
+
97
+ // Clean up temp directory
98
+ tempDir.listFiles()?.forEach { file ->
99
+ file.delete()
100
+ }
101
+
102
+ // Clean up patches
103
+ patchesDir.listFiles()?.forEach { file ->
104
+ file.delete()
105
+ }
106
+ }
107
+ }