react-native-codepush-sdk 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 React Native CodePush SDK
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,278 @@
1
+ # React Native CodePush SDK
2
+
3
+ A comprehensive SDK for integrating CodePush-style over-the-air updates into your React Native apps, with support for custom servers and advanced update workflows.
4
+
5
+ > **Looking for a working demo app?**
6
+ > See the `example/` folder for a full React Native project that consumes this SDK.
7
+
8
+ ## Features
9
+
10
+ ### 🚀 Core Functionality
11
+ - **Custom Server Integration**: Connect to your own CodePush server
12
+ - **Over-the-Air Updates**: Download and install app updates without app store releases
13
+ - **Rollback Support**: Automatically rollback failed updates
14
+ - **Progress Tracking**: Real-time download and installation progress
15
+ - **Mandatory Updates**: Support for required updates that users cannot skip
16
+
17
+ ### 📱 Platform Support
18
+ - **iOS**: Full native integration
19
+ - **Android**: Complete Android support
20
+ - **Cross-Platform**: Unified API for both platforms
21
+
22
+ ### 🔧 Advanced Features
23
+ - **Gradual Rollouts**: Support for percentage-based rollouts
24
+ - **Update Validation**: Verify update integrity before installation
25
+ - **Offline Support**: Handle updates when network is unavailable
26
+ - **Background Downloads**: Download updates in the background
27
+ - **Custom Install Modes**: Immediate, on restart, or on resume installation
28
+
29
+ ## Installation
30
+
31
+ ### 1. Install Dependencies
32
+
33
+ ```bash
34
+ npm install react-native-fs react-native-zip-archive react-native-device-info @react-native-async-storage/async-storage
35
+ ```
36
+
37
+ ### 2. Platform Setup
38
+
39
+ #### iOS Setup
40
+ 1. Run `cd ios && pod install`
41
+ 2. Add the following to your `Info.plist`:
42
+ ```xml
43
+ <key>NSAppTransportSecurity</key>
44
+ <dict>
45
+ <key>NSAllowsArbitraryLoads</key>
46
+ <true/>
47
+ </dict>
48
+ ```
49
+
50
+ #### Android Setup
51
+ 1. Add permissions to `android/app/src/main/AndroidManifest.xml`:
52
+ ```xml
53
+ <uses-permission android:name="android.permission.INTERNET" />
54
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
55
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ### Basic Setup
61
+
62
+ ```tsx
63
+ import React from 'react';
64
+ import { SafeAreaView } from 'react-native';
65
+ import { CodePushProvider } from './src/sdk/CodePushProvider';
66
+ import UpdateChecker from './src/components/UpdateChecker';
67
+
68
+ const App: React.FC = () => {
69
+ const codePushConfig = {
70
+ serverUrl: 'https://your-custom-codepush-server.com',
71
+ deploymentKey: 'your-deployment-key-here',
72
+ appVersion: '1.0.0',
73
+ checkFrequency: 'ON_APP_START',
74
+ installMode: 'ON_NEXT_RESTART',
75
+ };
76
+
77
+ return (
78
+ <CodePushProvider config={codePushConfig} autoCheck={true}>
79
+ <SafeAreaView style={{ flex: 1 }}>
80
+ <UpdateChecker />
81
+ </SafeAreaView>
82
+ </CodePushProvider>
83
+ );
84
+ };
85
+
86
+ export default App;
87
+ ```
88
+
89
+ ### Using the Hook
90
+
91
+ ```tsx
92
+ import { useCodePush } from './src/sdk/CodePushProvider';
93
+
94
+ const MyComponent = () => {
95
+ const {
96
+ availableUpdate,
97
+ isChecking,
98
+ checkForUpdate,
99
+ syncUpdate,
100
+ } = useCodePush();
101
+
102
+ return (
103
+ <View>
104
+ {availableUpdate && (
105
+ <Button title="Install Update" onPress={syncUpdate} />
106
+ )}
107
+ <Button
108
+ title="Check for Updates"
109
+ onPress={checkForUpdate}
110
+ disabled={isChecking}
111
+ />
112
+ </View>
113
+ );
114
+ };
115
+ ```
116
+
117
+ ### Manual Integration
118
+
119
+ ```tsx
120
+ import CustomCodePush from './src/sdk/CustomCodePush';
121
+
122
+ const codePush = new CustomCodePush({
123
+ serverUrl: 'https://your-server.com',
124
+ deploymentKey: 'your-key',
125
+ appVersion: '1.0.0',
126
+ });
127
+
128
+ // Check for updates
129
+ const update = await codePush.checkForUpdate();
130
+
131
+ // Download and install
132
+ if (update) {
133
+ const localPackage = await codePush.downloadUpdate(update, (progress) => {
134
+ console.log(`Download progress: ${progress.receivedBytes}/${progress.totalBytes}`);
135
+ });
136
+
137
+ await codePush.installUpdate(localPackage);
138
+ }
139
+ ```
140
+
141
+ ## Server Implementation
142
+
143
+ Your custom CodePush server needs to implement these endpoints:
144
+
145
+ ### Check for Updates
146
+ ```
147
+ POST /api/v1/updates/check
148
+ ```
149
+
150
+ ### Report Installation
151
+ ```
152
+ POST /api/v1/updates/report
153
+ ```
154
+
155
+ ### Report Rollback
156
+ ```
157
+ POST /api/v1/updates/rollback
158
+ ```
159
+
160
+ See `src/api/server-example.md` for detailed API documentation.
161
+
162
+ ## Configuration Options
163
+
164
+ ```typescript
165
+ interface CodePushConfiguration {
166
+ serverUrl: string; // Your server URL
167
+ deploymentKey: string; // Deployment key for authentication
168
+ appVersion: string; // Current app version
169
+ checkFrequency?: 'ON_APP_START' | // When to check for updates
170
+ 'ON_APP_RESUME' |
171
+ 'MANUAL';
172
+ installMode?: 'IMMEDIATE' | // When to install updates
173
+ 'ON_NEXT_RESTART' |
174
+ 'ON_NEXT_RESUME';
175
+ minimumBackgroundDuration?: number; // Minimum background time before checking
176
+ }
177
+ ```
178
+
179
+ ## API Reference
180
+
181
+ ### CustomCodePush Class
182
+
183
+ #### Methods
184
+
185
+ - `checkForUpdate()`: Check if an update is available
186
+ - `downloadUpdate(update, progressCallback)`: Download an update package
187
+ - `installUpdate(localPackage)`: Install a downloaded update
188
+ - `sync(options, statusCallback, progressCallback)`: Complete sync process
189
+ - `getCurrentPackage()`: Get current installed package info
190
+ - `rollback()`: Rollback to previous version
191
+ - `clearUpdates()`: Clear all downloaded updates
192
+
193
+ ### CodePushProvider Component
194
+
195
+ #### Props
196
+
197
+ - `config`: CodePush configuration object
198
+ - `autoCheck`: Automatically check for updates on app start
199
+ - `checkOnResume`: Check for updates when app resumes
200
+
201
+ ### useCodePush Hook
202
+
203
+ #### Returns
204
+
205
+ - `codePush`: CustomCodePush instance
206
+ - `currentUpdate`: Currently installed update info
207
+ - `availableUpdate`: Available update info
208
+ - `syncStatus`: Current sync status
209
+ - `isChecking`: Whether checking for updates
210
+ - `isDownloading`: Whether downloading an update
211
+ - `isInstalling`: Whether installing an update
212
+ - `checkForUpdate()`: Function to check for updates
213
+ - `syncUpdate()`: Function to sync and install updates
214
+ - `rollback()`: Function to rollback updates
215
+ - `clearUpdates()`: Function to clear all updates
216
+
217
+ ## Update Package Format
218
+
219
+ Update packages should be ZIP files with this structure:
220
+
221
+ ```
222
+ package.zip
223
+ ├── index.bundle # Main JavaScript bundle
224
+ ├── index.bundle.map # Source map (optional)
225
+ ├── assets/ # Static assets
226
+ │ ├── images/
227
+ │ ├── fonts/
228
+ │ └── ...
229
+ └── metadata.json # Package metadata
230
+ ```
231
+
232
+ ## Security Considerations
233
+
234
+ 1. **HTTPS Only**: Always use HTTPS for your server
235
+ 2. **Authentication**: Validate deployment keys on server
236
+ 3. **Package Signing**: Consider signing update packages
237
+ 4. **Rate Limiting**: Implement rate limiting on your server
238
+ 5. **Rollback Protection**: Implement automatic rollback for failed updates
239
+
240
+ ## Troubleshooting
241
+
242
+ ### Common Issues
243
+
244
+ 1. **Network Errors**: Check server URL and network connectivity
245
+ 2. **Permission Errors**: Ensure file system permissions are granted
246
+ 3. **Bundle Errors**: Verify update package format and integrity
247
+ 4. **Installation Failures**: Check available storage space
248
+
249
+ ### Debug Mode
250
+
251
+ Enable debug logging by setting:
252
+
253
+ ```typescript
254
+ // Add to your configuration
255
+ const config = {
256
+ // ... other config
257
+ debug: true,
258
+ };
259
+ ```
260
+
261
+ ## Contributing
262
+
263
+ 1. Fork the repository
264
+ 2. Create a feature branch
265
+ 3. Make your changes
266
+ 4. Add tests if applicable
267
+ 5. Submit a pull request
268
+
269
+ ## License
270
+
271
+ MIT License - see LICENSE file for details.
272
+
273
+ ## Support
274
+
275
+ For issues and questions:
276
+ - Check the troubleshooting section
277
+ - Review the server API documentation
278
+ - Create an issue in the repository
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useFrameworkReady = useFrameworkReady;
4
+ const react_1 = require("react");
5
+ function useFrameworkReady() {
6
+ (0, react_1.useEffect)(() => {
7
+ if (typeof window !== 'undefined' && window.frameworkReady) {
8
+ window.frameworkReady();
9
+ }
10
+ });
11
+ }
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.useFrameworkReady = exports.codePushService = exports.BundleManager = exports.UpdateChecker = exports.CustomCodePush = exports.useCodePush = exports.CodePushProvider = void 0;
21
+ // Main entry point for React Native CodePush SDK
22
+ var CodePushProvider_1 = require("./src/sdk/CodePushProvider");
23
+ Object.defineProperty(exports, "CodePushProvider", { enumerable: true, get: function () { return CodePushProvider_1.CodePushProvider; } });
24
+ Object.defineProperty(exports, "useCodePush", { enumerable: true, get: function () { return CodePushProvider_1.useCodePush; } });
25
+ var CustomCodePush_1 = require("./src/sdk/CustomCodePush");
26
+ Object.defineProperty(exports, "CustomCodePush", { enumerable: true, get: function () { return __importDefault(CustomCodePush_1).default; } });
27
+ var UpdateChecker_1 = require("./src/components/UpdateChecker");
28
+ Object.defineProperty(exports, "UpdateChecker", { enumerable: true, get: function () { return __importDefault(UpdateChecker_1).default; } });
29
+ var BundleManager_1 = require("./src/utils/BundleManager");
30
+ Object.defineProperty(exports, "BundleManager", { enumerable: true, get: function () { return BundleManager_1.BundleManager; } });
31
+ var codepushService_1 = require("./services/codepushService");
32
+ Object.defineProperty(exports, "codePushService", { enumerable: true, get: function () { return codepushService_1.codePushService; } });
33
+ var useFrameworkReady_1 = require("./hooks/useFrameworkReady");
34
+ Object.defineProperty(exports, "useFrameworkReady", { enumerable: true, get: function () { return useFrameworkReady_1.useFrameworkReady; } });
35
+ // Export types
36
+ __exportStar(require("./types/codepush"), exports);
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.codePushService = void 0;
4
+ // Mock service for demonstration - replace with actual CodePush SDK calls
5
+ class CodePushService {
6
+ constructor() {
7
+ this.mockDeployments = [
8
+ {
9
+ name: 'Production',
10
+ key: 'prod-key-12345678',
11
+ package: {
12
+ id: '1',
13
+ label: 'v1.2.3',
14
+ description: 'Bug fixes and performance improvements',
15
+ packageHash: 'abc123def456',
16
+ blobUrl: 'https://codepush.blob.core.windows.net/package1',
17
+ downloadUrl: 'https://codepush.blob.core.windows.net/package1',
18
+ packageSize: 2048576,
19
+ deploymentKey: 'prod-key-12345678',
20
+ isFirstRun: false,
21
+ failedInstall: false,
22
+ isMandatory: false,
23
+ timestamp: Date.now() - 86400000,
24
+ version: '1.2.3'
25
+ }
26
+ },
27
+ {
28
+ name: 'Staging',
29
+ key: 'staging-key-87654321',
30
+ package: {
31
+ id: '2',
32
+ label: 'v1.2.4-beta',
33
+ description: 'New feature preview and experimental changes',
34
+ packageHash: 'def456ghi789',
35
+ blobUrl: 'https://codepush.blob.core.windows.net/package2',
36
+ downloadUrl: 'https://codepush.blob.core.windows.net/package2',
37
+ packageSize: 3145728,
38
+ deploymentKey: 'staging-key-87654321',
39
+ isFirstRun: false,
40
+ failedInstall: false,
41
+ isMandatory: true,
42
+ timestamp: Date.now() - 3600000,
43
+ version: '1.2.4'
44
+ }
45
+ },
46
+ {
47
+ name: 'Development',
48
+ key: 'dev-key-11223344',
49
+ }
50
+ ];
51
+ this.mockHistory = [
52
+ {
53
+ id: '1',
54
+ version: '1.2.3',
55
+ timestamp: Date.now() - 86400000,
56
+ status: 'SUCCESS',
57
+ description: 'Bug fixes and performance improvements',
58
+ downloadSize: 2048576,
59
+ },
60
+ {
61
+ id: '2',
62
+ version: '1.2.2',
63
+ timestamp: Date.now() - 172800000,
64
+ status: 'SUCCESS',
65
+ description: 'UI improvements and new dashboard features',
66
+ downloadSize: 1536000,
67
+ },
68
+ {
69
+ id: '3',
70
+ version: '1.2.1',
71
+ timestamp: Date.now() - 259200000,
72
+ status: 'ROLLBACK',
73
+ description: 'Critical bug fix rollback',
74
+ downloadSize: 1024000,
75
+ },
76
+ {
77
+ id: '4',
78
+ version: '1.2.0',
79
+ timestamp: Date.now() - 345600000,
80
+ status: 'FAILED',
81
+ description: 'Major feature update with new authentication',
82
+ downloadSize: 4096000,
83
+ }
84
+ ];
85
+ }
86
+ async checkForUpdate() {
87
+ // Simulate API call delay
88
+ await new Promise(resolve => setTimeout(resolve, 1500));
89
+ // 70% chance of no update, 30% chance of update available
90
+ if (Math.random() > 0.3) {
91
+ return null;
92
+ }
93
+ return {
94
+ id: 'update-' + Date.now(),
95
+ label: 'v1.2.5',
96
+ description: 'Security updates and bug fixes',
97
+ packageHash: 'new-hash-123',
98
+ blobUrl: 'https://codepush.blob.core.windows.net/new-package',
99
+ downloadUrl: 'https://codepush.blob.core.windows.net/new-package',
100
+ packageSize: 1843200,
101
+ deploymentKey: 'prod-key-12345678',
102
+ isFirstRun: false,
103
+ failedInstall: false,
104
+ isMandatory: false,
105
+ timestamp: Date.now(),
106
+ version: '1.2.5'
107
+ };
108
+ }
109
+ async downloadUpdate(update, onProgress) {
110
+ // Simulate download progress
111
+ for (let i = 0; i <= 100; i += 5) {
112
+ await new Promise(resolve => setTimeout(resolve, 100));
113
+ onProgress(i);
114
+ }
115
+ return true;
116
+ }
117
+ async installUpdate() {
118
+ // Simulate installation
119
+ await new Promise(resolve => setTimeout(resolve, 2000));
120
+ return true;
121
+ }
122
+ async sync(onStatusChange) {
123
+ onStatusChange({ status: 'CHECKING_FOR_UPDATE' });
124
+ await new Promise(resolve => setTimeout(resolve, 1000));
125
+ const update = await this.checkForUpdate();
126
+ if (!update) {
127
+ onStatusChange({ status: 'UP_TO_DATE' });
128
+ return false;
129
+ }
130
+ onStatusChange({ status: 'DOWNLOADING_PACKAGE', progress: 0 });
131
+ const downloadSuccess = await this.downloadUpdate(update, (progress) => {
132
+ onStatusChange({ status: 'DOWNLOADING_PACKAGE', progress });
133
+ });
134
+ if (!downloadSuccess) {
135
+ onStatusChange({ status: 'UNKNOWN_ERROR' });
136
+ return false;
137
+ }
138
+ onStatusChange({ status: 'INSTALLING_UPDATE' });
139
+ const installSuccess = await this.installUpdate();
140
+ if (installSuccess) {
141
+ onStatusChange({ status: 'UPDATE_INSTALLED' });
142
+ return true;
143
+ }
144
+ else {
145
+ onStatusChange({ status: 'UNKNOWN_ERROR' });
146
+ return false;
147
+ }
148
+ }
149
+ async getDeployments() {
150
+ // Simulate API call
151
+ await new Promise(resolve => setTimeout(resolve, 500));
152
+ return this.mockDeployments;
153
+ }
154
+ async getUpdateHistory() {
155
+ // Simulate API call
156
+ await new Promise(resolve => setTimeout(resolve, 300));
157
+ return this.mockHistory;
158
+ }
159
+ async getCurrentPackageInfo() {
160
+ // Return current package info
161
+ return this.mockDeployments[0].package || null;
162
+ }
163
+ }
164
+ exports.codePushService = new CodePushService();