mirror of
				https://gitcode.com/gh_mirrors/re/react-native-pushy.git
				synced 2025-10-31 21:33:12 +08:00 
			
		
		
		
	Implement download progress
This commit is contained in:
		| @@ -27,6 +27,10 @@ import _updateConfig from '../update.json'; | ||||
| const {appKey} = _updateConfig[Platform.OS]; | ||||
|  | ||||
| export default class App extends Component { | ||||
|   state = { | ||||
|     received: 0, | ||||
|     total: 0, | ||||
|   }; | ||||
|   componentDidMount() { | ||||
|     if (isRolledBack) { | ||||
|       Alert.alert('提示', '刚刚更新失败了,版本被回滚.'); | ||||
| @@ -51,9 +55,16 @@ export default class App extends Component { | ||||
|       ); | ||||
|     } | ||||
|   } | ||||
|   doUpdate = async info => { | ||||
|   doUpdate = async (info) => { | ||||
|     try { | ||||
|       const hash = await downloadUpdate(info); | ||||
|       const hash = await downloadUpdate(info, { | ||||
|         onDownloadProgress: ({received, total}) => { | ||||
|           setState({ | ||||
|             received, | ||||
|             total, | ||||
|           }); | ||||
|         }, | ||||
|       }); | ||||
|       Alert.alert('提示', '下载完毕,是否重启应用?', [ | ||||
|         { | ||||
|           text: '是', | ||||
| @@ -126,6 +137,9 @@ export default class App extends Component { | ||||
|           当前热更新版本Hash: {currentVersion || '(空)'} | ||||
|           {'\n'} | ||||
|         </Text> | ||||
|         <Text> | ||||
|           下载进度:{received} / {total} | ||||
|         </Text> | ||||
|         <TouchableOpacity onPress={this.checkUpdate}> | ||||
|           <Text style={styles.instructions}>点击这里检查更新</Text> | ||||
|         </TouchableOpacity> | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -6,13 +6,11 @@ | ||||
| //  Copyright © 2016 erica. All rights reserved. | ||||
| // | ||||
|  | ||||
| #if __has_include(<React/RCTBridge.h>) | ||||
| #import <React/RCTBridgeModule.h> | ||||
| #else | ||||
| #import "RCTBridgeModule.h" | ||||
| #endif | ||||
| #import <React/RCTEventEmitter.h> | ||||
|  | ||||
| @interface RCTPushy : NSObject<RCTBridgeModule> | ||||
|  | ||||
| @interface RCTPushy : RCTEventEmitter<RCTBridgeModule> | ||||
|  | ||||
| + (NSURL *)bundleURL; | ||||
|  | ||||
|   | ||||
| @@ -10,17 +10,11 @@ | ||||
| #import "RCTPushyDownloader.h" | ||||
| #import "RCTPushyManager.h" | ||||
|  | ||||
| #if __has_include(<React/RCTBridge.h>) | ||||
| #import "React/RCTEventDispatcher.h" | ||||
|  | ||||
| #import <React/RCTConvert.h> | ||||
| #import <React/RCTLog.h> | ||||
| #else | ||||
| #import "RCTEventDispatcher.h" | ||||
| #import "RCTConvert.h" | ||||
| #import "RCTLog.h" | ||||
| #endif | ||||
| #import <React/RCTReloadCommand.h> | ||||
|  | ||||
| // | ||||
| static NSString *const keyPushyInfo = @"REACTNATIVECN_PUSHY_INFO_KEY"; | ||||
| static NSString *const paramPackageVersion = @"packageVersion"; | ||||
| static NSString *const paramLastVersion = @"lastVersion"; | ||||
| @@ -65,6 +59,7 @@ static BOOL ignoreRollback = false; | ||||
|  | ||||
| @implementation RCTPushy { | ||||
|     RCTPushyManager *_fileManager; | ||||
|     bool hasListeners; | ||||
| } | ||||
|  | ||||
| @synthesize bridge = _bridge; | ||||
| @@ -281,10 +276,12 @@ RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options) | ||||
|         [self setNeedUpdate:options]; | ||||
|          | ||||
|         // reload | ||||
|         dispatch_async(dispatch_get_main_queue(), ^{ | ||||
|             [_bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"]; | ||||
|             [_bridge reload]; | ||||
|         }); | ||||
|         RCTReloadCommandSetBundleURL([[self class] bundleURL]); | ||||
|         RCTTriggerReloadCommandListeners(@"pushy reload"); | ||||
| //        dispatch_async(dispatch_get_main_queue(), ^{ | ||||
| //            [self.bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"]; | ||||
| //            [self.bridge reload]; | ||||
| //        }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -302,7 +299,27 @@ RCT_EXPORT_METHOD(markSuccess) | ||||
|     [self clearInvalidFiles]; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| #pragma mark - private | ||||
| - (NSArray<NSString *> *)supportedEvents | ||||
| { | ||||
|   return @[EVENT_PROGRESS_DOWNLOAD, EVENT_PROGRESS_UNZIP]; | ||||
| } | ||||
|  | ||||
| // Will be called when this module's first listener is added. | ||||
| -(void)startObserving { | ||||
|     hasListeners = YES; | ||||
|     // Set up any upstream listeners or background tasks as necessary | ||||
| } | ||||
|  | ||||
| // Will be called when this module's last listener is removed, or on dealloc. | ||||
| -(void)stopObserving { | ||||
|     hasListeners = NO; | ||||
|     // Remove upstream listeners, stop unnecessary background tasks | ||||
| } | ||||
|  | ||||
|  | ||||
| - (void)doPushy:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback | ||||
| { | ||||
|     NSString *updateUrl = [RCTConvert NSString:options[@"updateUrl"]]; | ||||
| @@ -325,16 +342,17 @@ RCT_EXPORT_METHOD(markSuccess) | ||||
|     } | ||||
|  | ||||
|     NSString *zipFilePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",hashName, [self zipExtension:type]]]; | ||||
|     NSString *unzipDir = [dir stringByAppendingPathComponent:hashName]; | ||||
| //    NSString *unzipDir = [dir stringByAppendingPathComponent:hashName]; | ||||
|  | ||||
|     RCTLogInfo(@"RCTPushy -- download file %@", updateUrl); | ||||
|     [RCTPushyDownloader download:updateUrl savePath:zipFilePath progressHandler:^(long long receivedBytes, long long totalBytes) { | ||||
|         [self.bridge.eventDispatcher sendAppEventWithName:EVENT_PROGRESS_DOWNLOAD | ||||
|                                                      body:@{ | ||||
|         if (self->hasListeners) { | ||||
|             [self sendEventWithName:EVENT_PROGRESS_DOWNLOAD body:@{ | ||||
|                 PARAM_PROGRESS_HASHNAME:hashName, | ||||
|                 PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLongLong:receivedBytes], | ||||
|                 PARAM_PROGRESS_TOTAL:[NSNumber numberWithLongLong:totalBytes] | ||||
|             }]; | ||||
|         } | ||||
|     } completionHandler:^(NSString *path, NSError *error) { | ||||
|         if (error) { | ||||
|             callback(error); | ||||
| @@ -342,16 +360,18 @@ RCT_EXPORT_METHOD(markSuccess) | ||||
|         else { | ||||
|             RCTLogInfo(@"RCTPushy -- unzip file %@", zipFilePath); | ||||
|             NSString *unzipFilePath = [dir stringByAppendingPathComponent:hashName]; | ||||
|             [_fileManager unzipFileAtPath:zipFilePath toDestination:unzipFilePath progressHandler:^(NSString *entry,long entryNumber, long total) { | ||||
|                 [self.bridge.eventDispatcher sendAppEventWithName:EVENT_PROGRESS_UNZIP | ||||
|             [self->_fileManager unzipFileAtPath:zipFilePath toDestination:unzipFilePath progressHandler:^(NSString *entry,long entryNumber, long total) { | ||||
|                 if (self->hasListeners) { | ||||
|                     [self sendEventWithName:EVENT_PROGRESS_UNZIP | ||||
|                                        body:@{ | ||||
|                                            PARAM_PROGRESS_HASHNAME:hashName, | ||||
|                                            PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLong:entryNumber], | ||||
|                                            PARAM_PROGRESS_TOTAL:[NSNumber numberWithLong:total] | ||||
|                                        }]; | ||||
|                 } | ||||
|                  | ||||
|             } completionHandler:^(NSString *path, BOOL succeeded, NSError *error) { | ||||
|                 dispatch_async(_methodQueue, ^{ | ||||
|                 dispatch_async(self->_methodQueue, ^{ | ||||
|                     if (error) { | ||||
|                         callback(error); | ||||
|                     } | ||||
| @@ -404,7 +424,7 @@ RCT_EXPORT_METHOD(markSuccess) | ||||
|             NSDictionary *copies = json[@"copies"]; | ||||
|             NSDictionary *deletes = json[@"deletes"]; | ||||
|  | ||||
|             [_fileManager copyFiles:copies fromDir:sourceOrigin toDir:unzipDir deletes:deletes completionHandler:^(NSError *error) { | ||||
|             [self->_fileManager copyFiles:copies fromDir:sourceOrigin toDir:unzipDir deletes:deletes completionHandler:^(NSError *error) { | ||||
|                 if (error) { | ||||
|                     callback(error); | ||||
|                 } | ||||
|   | ||||
							
								
								
									
										10
									
								
								lib/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								lib/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -31,7 +31,11 @@ export type CheckResult = | ||||
| export function checkUpdate(appkey: string): Promise<CheckResult>; | ||||
|  | ||||
| export function downloadUpdate( | ||||
|   options: UpdateAvailableResult, | ||||
|   info: UpdateAvailableResult, | ||||
|   eventListeners?: { | ||||
|     onDownloadProgress?: (data: ProgressData) => void; | ||||
|     onUnzipProgress?: (data: ProgressData) => void; | ||||
|   }, | ||||
| ): Promise<undefined | string>; | ||||
|  | ||||
| export function switchVersion(hash: string): void; | ||||
| @@ -56,8 +60,8 @@ export function setCustomEndpoints({ | ||||
|   backupQueryUrl?: string; | ||||
| }): void; | ||||
|  | ||||
|  | ||||
| interface ProgressEvent { | ||||
| interface ProgressData { | ||||
|   hashname: string; | ||||
|   received: number; | ||||
|   total: number; | ||||
| } | ||||
|   | ||||
							
								
								
									
										45
									
								
								lib/index.js
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								lib/index.js
									
									
									
									
									
								
							| @@ -3,7 +3,7 @@ import { | ||||
|   getCheckUrl, | ||||
|   setCustomEndpoints, | ||||
| } from './endpoint'; | ||||
| import { NativeAppEventEmitter, NativeModules, Platform } from 'react-native'; | ||||
| import { NativeEventEmitter, NativeModules, Platform } from 'react-native'; | ||||
| export { setCustomEndpoints }; | ||||
| const { | ||||
|   version: v, | ||||
| @@ -32,12 +32,18 @@ if (Platform.OS === 'android' && !Pushy.isUsingBundleUrl) { | ||||
|   ); | ||||
| } | ||||
|  | ||||
| const eventEmitter = new NativeEventEmitter(Pushy); | ||||
|  | ||||
| if (!uuid) { | ||||
|   uuid = uuidv4(); | ||||
|   Pushy.setUuid(uuid); | ||||
| } | ||||
|  | ||||
| console.log('Pushy uuid: ' + uuid); | ||||
| function logger(text) { | ||||
|   console.log(`Pushy: ${text}`); | ||||
| } | ||||
|  | ||||
| logger('uuid: ' + uuid); | ||||
|  | ||||
| /* | ||||
| Return json: | ||||
| @@ -77,6 +83,10 @@ export async function checkUpdate(APPKEY, isRetry) { | ||||
|       ).toLocaleString()}"之后重试。`, | ||||
|     ); | ||||
|   } | ||||
|   if (typeof APPKEY !== 'string') { | ||||
|     throw new Error('未检查到合法的APPKEY,请查看update.json文件是否正确生成'); | ||||
|   } | ||||
|   logger('checking update'); | ||||
|   let resp; | ||||
|   try { | ||||
|     resp = await fetch(getCheckUrl(APPKEY), { | ||||
| @@ -129,41 +139,62 @@ function checkOperation(op) { | ||||
|   }); | ||||
| } | ||||
|  | ||||
| export async function downloadUpdate(options) { | ||||
| export async function downloadUpdate(options, eventListeners) { | ||||
|   assertRelease(); | ||||
|   if (!options.update) { | ||||
|     return; | ||||
|   } | ||||
|   if (eventListeners) { | ||||
|     if (eventListeners.onDownloadProgress) { | ||||
|       const downloadCallback = eventListeners.onDownloadProgress; | ||||
|       eventEmitter.addListener('RCTPushyDownloadProgress', (progressData) => { | ||||
|         if (progressData.hash === options.hash) { | ||||
|           downloadCallback(progressData); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|     if (eventListeners.onUnzipProgress) { | ||||
|       const unzipCallback = eventListeners.onUnzipProgress; | ||||
|       eventEmitter.addListener('RCTPushyUnzipProgress', (progressData) => { | ||||
|         if (progressData.hash === options.hash) { | ||||
|           unzipCallback(progressData); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|   if (options.diffUrl) { | ||||
|     logger('downloading diff'); | ||||
|     await Pushy.downloadPatchFromPpk({ | ||||
|       updateUrl: options.diffUrl, | ||||
|       hashName: options.hash, | ||||
|       originHashName: currentVersion, | ||||
|     }); | ||||
|   } else if (options.pdiffUrl) { | ||||
|     logger('downloading pdiff'); | ||||
|     await Pushy.downloadPatchFromPackage({ | ||||
|       updateUrl: options.pdiffUrl, | ||||
|       hashName: options.hash, | ||||
|     }); | ||||
|   } | ||||
|   eventEmitter.removeAllListeners('RCTPushyDownloadProgress'); | ||||
|   eventEmitter.removeAllListeners('RCTPushyUnzipProgress'); | ||||
|   return options.hash; | ||||
| } | ||||
|  | ||||
| export function switchVersion(hash) { | ||||
|   assertRelease(); | ||||
|   logger('switchVersion'); | ||||
|   Pushy.reloadUpdate({ hashName: hash }); | ||||
| } | ||||
|  | ||||
| export function switchVersionLater(hash) { | ||||
|   assertRelease(); | ||||
|   logger('switchVersionLater'); | ||||
|   Pushy.setNeedUpdate({ hashName: hash }); | ||||
| } | ||||
|  | ||||
| export function markSuccess() { | ||||
|   assertRelease(); | ||||
|   logger('markSuccess'); | ||||
|   Pushy.markSuccess(); | ||||
| } | ||||
|  | ||||
| NativeAppEventEmitter.addListener('RCTPushyDownloadProgress', (params) => {}); | ||||
|  | ||||
| NativeAppEventEmitter.addListener('RCTPushyUnzipProgress', (params) => {}); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 sunnylqm
					sunnylqm