// Copyright 2019 650 Industries. All rights reserved. #import #import #import #import #import #import #import @interface EXUpdatesModule () @property (nonatomic, weak) id updatesService; @end @implementation EXUpdatesModule UM_EXPORT_MODULE(ExpoUpdates); - (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry { _updatesService = [moduleRegistry getModuleImplementingProtocol:@protocol(EXUpdatesInterface)]; } - (NSDictionary *)constantsToExport { if (!_updatesService.isStarted) { return @{ @"isEnabled": @(NO) }; } EXUpdatesUpdate *launchedUpdate = _updatesService.launchedUpdate; if (!launchedUpdate) { return @{ @"isEnabled": @(NO) }; } else { return @{ @"isEnabled": @(YES), @"isUsingEmbeddedAssets": @(_updatesService.isUsingEmbeddedAssets), @"updateId": launchedUpdate.updateId.UUIDString ?: @"", @"manifest": launchedUpdate.rawManifest ?: @{}, @"releaseChannel": _updatesService.config.releaseChannel, @"localAssets": _updatesService.assetFilesMap ?: @{}, @"isEmergencyLaunch": @(_updatesService.isEmergencyLaunch) }; } } UM_EXPORT_METHOD_AS(reload, reloadAsync:(UMPromiseResolveBlock)resolve reject:(UMPromiseRejectBlock)reject) { if (!_updatesService.canRelaunch) { reject(@"ERR_UPDATES_DISABLED", @"The updates module controller has not been properly initialized. If you're in development mode, you cannot use this method. Otherwise, make sure you have called [[EXUpdatesAppController sharedInstance] start].", nil); return; } [_updatesService requestRelaunchWithCompletion:^(BOOL success) { if (success) { resolve(nil); } else { reject(@"ERR_UPDATES_RELOAD", @"Could not reload application. Ensure you have set the `bridge` property of EXUpdatesAppController.", nil); } }]; } UM_EXPORT_METHOD_AS(checkForUpdateAsync, checkForUpdateAsync:(UMPromiseResolveBlock)resolve reject:(UMPromiseRejectBlock)reject) { if (!_updatesService.isStarted) { reject(@"ERR_UPDATES_DISABLED", @"The updates module controller has not been properly initialized. If you're in development mode, you cannot check for updates. Otherwise, make sure you have called [[EXUpdatesAppController sharedInstance] start].", nil); return; } EXUpdatesFileDownloader *fileDownloader = [[EXUpdatesFileDownloader alloc] initWithUpdatesConfig:_updatesService.config]; [fileDownloader downloadManifestFromURL:_updatesService.config.updateUrl withDatabase:_updatesService.database cacheDirectory:_updatesService.directory successBlock:^(EXUpdatesUpdate *update) { EXUpdatesUpdate *launchedUpdate = self->_updatesService.launchedUpdate; id selectionPolicy = self->_updatesService.selectionPolicy; if ([selectionPolicy shouldLoadNewUpdate:update withLaunchedUpdate:launchedUpdate]) { resolve(@{ @"isAvailable": @(YES), @"manifest": update.rawManifest }); } else { resolve(@{ @"isAvailable": @(NO) }); } } errorBlock:^(NSError *error, NSURLResponse *response) { reject(@"ERR_UPDATES_CHECK", error.localizedDescription, error); }]; } UM_EXPORT_METHOD_AS(fetchUpdateAsync, fetchUpdateAsync:(UMPromiseResolveBlock)resolve reject:(UMPromiseRejectBlock)reject) { if (!_updatesService.isStarted) { reject(@"ERR_UPDATES_DISABLED", @"The updates module controller has not been properly initialized. If you're in development mode, you cannot fetch updates. Otherwise, make sure you have called [[EXUpdatesAppController sharedInstance] start].", nil); return; } EXUpdatesRemoteAppLoader *remoteAppLoader = [[EXUpdatesRemoteAppLoader alloc] initWithConfig:_updatesService.config database:_updatesService.database directory:_updatesService.directory completionQueue:self.methodQueue]; [remoteAppLoader loadUpdateFromUrl:_updatesService.config.updateUrl onManifest:^BOOL(EXUpdatesUpdate * _Nonnull update) { return [self->_updatesService.selectionPolicy shouldLoadNewUpdate:update withLaunchedUpdate:self->_updatesService.launchedUpdate]; } success:^(EXUpdatesUpdate * _Nullable update) { if (update) { resolve(@{ @"isNew": @(YES), @"manifest": update.rawManifest }); } else { resolve(@{ @"isNew": @(NO) }); } } error:^(NSError * _Nonnull error) { reject(@"ERR_UPDATES_FETCH", @"Failed to download new update", error); }]; } @end