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 +21 -0
- package/README.md +278 -0
- package/dist/hooks/useFrameworkReady.js +11 -0
- package/dist/index.js +36 -0
- package/dist/services/codepushService.js +164 -0
- package/dist/src/components/UpdateChecker.js +230 -0
- package/dist/src/sdk/CodePushProvider.js +181 -0
- package/dist/src/sdk/CustomCodePush.js +405 -0
- package/dist/src/utils/BundleManager.js +124 -0
- package/dist/types/codepush.js +2 -0
- package/hooks/useFrameworkReady.ts +17 -0
- package/index.ts +10 -0
- package/package.json +72 -0
- package/services/codepushService.ts +181 -0
- package/src/components/UpdateChecker.tsx +303 -0
- package/src/sdk/CodePushProvider.tsx +184 -0
- package/src/sdk/CustomCodePush.ts +526 -0
- package/src/utils/BundleManager.ts +140 -0
- package/types/codepush.ts +44 -0
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();
|