mirror of
https://github.com/zhigang1992/react-native-code-push.git
synced 2026-06-11 08:04:23 +08:00
Merge pull request #150 from Microsoft/report-acquisition-status
Report Acquisition Status
This commit is contained in:
47
CodePush.js
47
CodePush.js
@@ -60,8 +60,9 @@ async function checkForUpdate(deploymentKey = null) {
|
||||
if (!update || update.updateAppVersion || (update.packageHash === localPackage.packageHash)) {
|
||||
return null;
|
||||
} else {
|
||||
const remotePackage = { ...update, ...PackageMixins.remote };
|
||||
const remotePackage = { ...update, ...PackageMixins.remote(sdk.reportStatusDownload) };
|
||||
remotePackage.failedInstall = await NativeCodePush.isFailedUpdate(remotePackage.packageHash);
|
||||
remotePackage.deploymentKey = deploymentKey || nativeConfig.deploymentKey;
|
||||
return remotePackage;
|
||||
}
|
||||
}
|
||||
@@ -101,7 +102,31 @@ function getPromisifiedSdk(requestFetchAdapter, config) {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
sdk.reportStatusDeploy = (deployedPackage, status) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
module.exports.AcquisitionSdk.prototype.reportStatusDeploy.call(sdk, deployedPackage, status, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
sdk.reportStatusDownload = (downloadedPackage) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
module.exports.AcquisitionSdk.prototype.reportStatusDownload.call(sdk, downloadedPackage, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return sdk;
|
||||
}
|
||||
|
||||
@@ -110,6 +135,22 @@ function log(message) {
|
||||
console.log(`[CodePush] ${message}`)
|
||||
}
|
||||
|
||||
async function notifyApplicationReady() {
|
||||
await NativeCodePush.notifyApplicationReady();
|
||||
const statusReport = await NativeCodePush.getNewStatusReport();
|
||||
if (statusReport) {
|
||||
const config = await getConfiguration();
|
||||
if (statusReport.appVersion) {
|
||||
const sdk = getPromisifiedSdk(requestFetchAdapter, config);
|
||||
sdk.reportStatusDeploy();
|
||||
} else {
|
||||
config.deploymentKey = statusReport.package.deploymentKey;
|
||||
const sdk = getPromisifiedSdk(requestFetchAdapter, config);
|
||||
sdk.reportStatusDeploy(statusReport.package, statusReport.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function restartApp(onlyIfUpdateIsPending = false) {
|
||||
NativeCodePush.restartApp(onlyIfUpdateIsPending);
|
||||
}
|
||||
@@ -269,7 +310,7 @@ const CodePush = {
|
||||
getConfiguration,
|
||||
getCurrentPackage,
|
||||
log,
|
||||
notifyApplicationReady: NativeCodePush.notifyApplicationReady,
|
||||
notifyApplicationReady,
|
||||
restartApp,
|
||||
setUpTestDependencies,
|
||||
sync,
|
||||
|
||||
121
CodePush.m
121
CodePush.m
@@ -13,10 +13,17 @@
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
static BOOL needToReportRollback = NO;
|
||||
static BOOL isRunningBinaryVersion = NO;
|
||||
static BOOL testConfigurationFlag = NO;
|
||||
|
||||
// These constants represent valid deployment statuses
|
||||
static NSString *const DeploymentFailed = @"DeploymentFailed";
|
||||
static NSString *const DeploymentSucceeded = @"DeploymentSucceeded";
|
||||
|
||||
// These keys represent the names we use to store data in NSUserDefaults
|
||||
static NSString *const FailedUpdatesKey = @"CODE_PUSH_FAILED_UPDATES";
|
||||
static NSString *const LastDeploymentReportKey = @"CODE_PUSH_LAST_DEPLOYMENT_REPORT";
|
||||
static NSString *const PendingUpdateKey = @"CODE_PUSH_PENDING_UPDATE";
|
||||
|
||||
// These keys are already "namespaced" by the PendingUpdateKey, so
|
||||
@@ -26,6 +33,8 @@ static NSString *const PendingUpdateIsLoadingKey = @"isLoading";
|
||||
|
||||
// These keys are used to inspect/augment the metadata
|
||||
// that is associated with an update's package.
|
||||
static NSString *const DeploymentKeyKey = @"deploymentKey";
|
||||
static NSString *const LabelKey = @"label";
|
||||
static NSString *const PackageHashKey = @"packageHash";
|
||||
static NSString *const PackageIsPendingKey = @"isPending";
|
||||
|
||||
@@ -54,6 +63,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
|
||||
if (error || !packageFile) {
|
||||
NSLog(logMessageFormat, binaryJsBundleUrl);
|
||||
isRunningBinaryVersion = YES;
|
||||
return binaryJsBundleUrl;
|
||||
}
|
||||
|
||||
@@ -65,15 +75,17 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
NSDictionary *currentPackageMetadata = [CodePushPackage getCurrentPackage:&error];
|
||||
if (error || !currentPackageMetadata) {
|
||||
NSLog(logMessageFormat, binaryJsBundleUrl);
|
||||
isRunningBinaryVersion = YES;
|
||||
return binaryJsBundleUrl;
|
||||
}
|
||||
|
||||
NSString *packageAppVersion = [currentPackageMetadata objectForKey:@"appVersion"];
|
||||
|
||||
if ([binaryDate compare:packageDate] == NSOrderedAscending && [binaryAppVersion isEqualToString:packageAppVersion]) {
|
||||
if ([binaryDate compare:packageDate] == NSOrderedAscending && ([CodePush isUsingTestConfiguration] ||[binaryAppVersion isEqualToString:packageAppVersion])) {
|
||||
// Return package file because it is newer than the app store binary's JS bundle
|
||||
NSURL *packageUrl = [[NSURL alloc] initFileURLWithPath:packageFile];
|
||||
NSLog(logMessageFormat, packageUrl);
|
||||
isRunningBinaryVersion = NO;
|
||||
return packageUrl;
|
||||
} else {
|
||||
#ifndef DEBUG
|
||||
@@ -81,6 +93,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
#endif
|
||||
|
||||
NSLog(logMessageFormat, binaryJsBundleUrl);
|
||||
isRunningBinaryVersion = YES;
|
||||
return binaryJsBundleUrl;
|
||||
}
|
||||
}
|
||||
@@ -148,6 +161,19 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (NSString *)getPackageStatusReportIdentifier:(NSDictionary *)package
|
||||
{
|
||||
// Because deploymentKeys can be dynamically switched, we use a
|
||||
// combination of the deploymentKey and label as the packageIdentifier.
|
||||
NSString *deploymentKey = [package objectForKey:DeploymentKeyKey];
|
||||
NSString *label = [package objectForKey:LabelKey];
|
||||
if (deploymentKey && label) {
|
||||
return [[deploymentKey stringByAppendingString:@":"] stringByAppendingString:label];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
@@ -175,6 +201,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
// Pending update was initialized, but notifyApplicationReady was not called.
|
||||
// Therefore, deduce that it is a broken update and rollback.
|
||||
NSLog(@"Update did not finish loading the last time, rolling back to a previous version.");
|
||||
needToReportRollback = YES;
|
||||
[self rollbackPackage];
|
||||
} else {
|
||||
// Mark that we tried to initialize the new update, so that if it crashes,
|
||||
@@ -185,6 +212,13 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isDeploymentStatusNotYetReported:(NSString *)appVersionOrPackageIdentifier
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSString *sentStatusReportIdentifier = [preferences objectForKey:LastDeploymentReportKey];
|
||||
return sentStatusReportIdentifier == nil || ![sentStatusReportIdentifier isEqualToString:appVersionOrPackageIdentifier];
|
||||
}
|
||||
|
||||
/*
|
||||
* This method checks to see whether a specific package hash
|
||||
* has previously failed installation.
|
||||
@@ -193,7 +227,25 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
|
||||
return (failedUpdates != nil && [failedUpdates containsObject:packageHash]);
|
||||
if (failedUpdates == nil || packageHash == nil) {
|
||||
return NO;
|
||||
} else {
|
||||
for (NSDictionary *failedPackage in failedUpdates)
|
||||
{
|
||||
// Type check is needed for backwards compatibility, where we used to just store
|
||||
// the failed package hash instead of the metadata. This only impacts "dev"
|
||||
// scenarios, since in production we clear out old information whenever a new
|
||||
// binary is applied.
|
||||
if ([failedPackage isKindOfClass:[NSDictionary class]]) {
|
||||
NSString *failedPackageHash = [failedPackage objectForKey:PackageHashKey];
|
||||
if ([packageHash isEqualToString:failedPackageHash]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -237,6 +289,13 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
});
|
||||
}
|
||||
|
||||
- (void)recordDeploymentStatusReported:(NSString *)appVersionOrPackageIdentifier
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
[preferences setValue:appVersionOrPackageIdentifier forKey:LastDeploymentReportKey];
|
||||
[preferences synchronize];
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used when an update has failed installation
|
||||
* and the app needs to be rolled back to the previous bundle.
|
||||
@@ -247,10 +306,10 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
- (void)rollbackPackage
|
||||
{
|
||||
NSError *error;
|
||||
NSString *packageHash = [CodePushPackage getCurrentPackageHash:&error];
|
||||
NSDictionary *failedPackage = [CodePushPackage getCurrentPackage:&error];
|
||||
|
||||
// Write the current package's hash to the "failed list"
|
||||
[self saveFailedUpdate:packageHash];
|
||||
// Write the current package's metadata to the "failed list"
|
||||
[self saveFailedUpdate:failedPackage];
|
||||
|
||||
// Rollback to the previous version and de-register the new update
|
||||
[CodePushPackage rollbackPackage];
|
||||
@@ -263,7 +322,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
* to store its hash so that it can be ignored on future
|
||||
* attempts to check the server for an update.
|
||||
*/
|
||||
- (void)saveFailedUpdate:(NSString *)packageHash
|
||||
- (void)saveFailedUpdate:(NSDictionary *)failedPackage
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
|
||||
@@ -275,7 +334,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
failedUpdates = [failedUpdates mutableCopy];
|
||||
}
|
||||
|
||||
[failedUpdates addObject:packageHash];
|
||||
[failedUpdates addObject:failedPackage];
|
||||
[preferences setObject:failedUpdates forKey:FailedUpdatesKey];
|
||||
[preferences synchronize];
|
||||
}
|
||||
@@ -467,6 +526,54 @@ RCT_EXPORT_METHOD(notifyApplicationReady:(RCTPromiseResolveBlock)resolve
|
||||
resolve([NSNull null]);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is checks if a new status update exists (new version was installed,
|
||||
* or an update failed) and return its details (version label, status).
|
||||
*/
|
||||
RCT_EXPORT_METHOD(getNewStatusReport:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
if (needToReportRollback) {
|
||||
// Check if there was a rollback that was not yet reported
|
||||
needToReportRollback = NO;
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
|
||||
if (failedUpdates) {
|
||||
NSDictionary *lastFailedPackage = [failedUpdates lastObject];
|
||||
if (lastFailedPackage) {
|
||||
NSString *lastFailedPackageIdentifier = [self getPackageStatusReportIdentifier:lastFailedPackage];
|
||||
if (lastFailedPackageIdentifier && [self isDeploymentStatusNotYetReported:lastFailedPackageIdentifier]) {
|
||||
[self recordDeploymentStatusReported:lastFailedPackageIdentifier];
|
||||
resolve(@{ @"package": lastFailedPackage, @"status": DeploymentFailed });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (_isFirstRunAfterUpdate) {
|
||||
// Check if the current CodePush package has been reported
|
||||
NSError *error;
|
||||
NSDictionary *currentPackage = [CodePushPackage getCurrentPackage:&error];
|
||||
if (!error && currentPackage) {
|
||||
NSString *currentPackageIdentifier = [self getPackageStatusReportIdentifier:currentPackage];
|
||||
if (currentPackageIdentifier && [self isDeploymentStatusNotYetReported:currentPackageIdentifier]) {
|
||||
[self recordDeploymentStatusReported:currentPackageIdentifier];
|
||||
resolve(@{ @"package": currentPackage, @"status": DeploymentSucceeded });
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (isRunningBinaryVersion || [_bridge.bundleURL.scheme hasPrefix:@"http"]) {
|
||||
// Check if the current appVersion has been reported.
|
||||
NSString *appVersion = [[CodePushConfig current] appVersion];
|
||||
if ([self isDeploymentStatusNotYetReported:appVersion]) {
|
||||
[self recordDeploymentStatusReported:appVersion];
|
||||
resolve(@{ @"appVersion": appVersion });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resolve([NSNull null]);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is the native side of the CodePush.restartApp() method.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#import "CodePush.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@implementation CodePushConfig {
|
||||
NSMutableDictionary *_configDictionary;
|
||||
@@ -8,6 +9,7 @@ static CodePushConfig *_currentConfig;
|
||||
|
||||
static NSString * const AppVersionConfigKey = @"appVersion";
|
||||
static NSString * const BuildVdersionConfigKey = @"buildVersion";
|
||||
static NSString * const ClientUniqueIDConfigKey = @"clientUniqueId";
|
||||
static NSString * const DeploymentKeyConfigKey = @"deploymentKey";
|
||||
static NSString * const ServerURLConfigKey = @"serverUrl";
|
||||
|
||||
@@ -31,6 +33,14 @@ static NSString * const ServerURLConfigKey = @"serverUrl";
|
||||
NSString *deploymentKey = [infoDictionary objectForKey:@"CodePushDeploymentKey"];
|
||||
NSString *serverURL = [infoDictionary objectForKey:@"CodePushServerURL"];
|
||||
|
||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
NSString *clientUniqueId = [userDefaults stringForKey:ClientUniqueIDConfigKey];
|
||||
if (clientUniqueId == nil) {
|
||||
clientUniqueId = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
|
||||
[userDefaults setObject:clientUniqueId forKey:ClientUniqueIDConfigKey];
|
||||
[userDefaults synchronize];
|
||||
}
|
||||
|
||||
if (!serverURL) {
|
||||
serverURL = @"https://codepush.azurewebsites.net/";
|
||||
}
|
||||
@@ -39,6 +49,7 @@ static NSString * const ServerURLConfigKey = @"serverUrl";
|
||||
appVersion,AppVersionConfigKey,
|
||||
buildVersion,BuildVdersionConfigKey,
|
||||
serverURL,ServerURLConfigKey,
|
||||
clientUniqueId,ClientUniqueIDConfigKey,
|
||||
deploymentKey,DeploymentKeyConfigKey,
|
||||
nil];
|
||||
|
||||
@@ -70,6 +81,11 @@ static NSString * const ServerURLConfigKey = @"serverUrl";
|
||||
return [_configDictionary objectForKey:ServerURLConfigKey];
|
||||
}
|
||||
|
||||
- (NSString *)clientUniqueId
|
||||
{
|
||||
return [_configDictionary objectForKey:ClientUniqueIDConfigKey];
|
||||
}
|
||||
|
||||
- (void)setDeploymentKey:(NSString *)deploymentKey
|
||||
{
|
||||
[_configDictionary setValue:deploymentKey forKey:DeploymentKeyConfigKey];
|
||||
|
||||
@@ -24,7 +24,7 @@ let FirstUpdateTest = createTestCaseComponent(
|
||||
},
|
||||
async () => {
|
||||
let update = await CodePush.checkForUpdate();
|
||||
assert.equal(JSON.stringify(update), JSON.stringify({ ...serverPackage, ...PackageMixins.remote, failedInstall: false }), "checkForUpdate did not return the update from the server");
|
||||
assert.equal(JSON.stringify(update), JSON.stringify({ ...serverPackage, ...PackageMixins.remote(), failedInstall: false }), "checkForUpdate did not return the update from the server");
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ let NewUpdateTest = createTestCaseComponent(
|
||||
},
|
||||
async () => {
|
||||
let update = await CodePush.checkForUpdate();
|
||||
assert.equal(JSON.stringify(update), JSON.stringify({ ...serverPackage, ...PackageMixins.remote, failedInstall: false }), "checkForUpdate did not return the update from the server");
|
||||
assert.equal(JSON.stringify(update), JSON.stringify({ ...serverPackage, ...PackageMixins.remote(), failedInstall: false }), "checkForUpdate did not return the update from the server");
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ let SwitchDeploymentKeyTest = createTestCaseComponent(
|
||||
},
|
||||
async () => {
|
||||
let update = await CodePush.checkForUpdate(deploymentKey);
|
||||
assert.equal(JSON.stringify(update), JSON.stringify({ ...serverPackage, ...PackageMixins.remote, failedInstall: false }), "checkForUpdate did not return the update from the server");
|
||||
assert.equal(JSON.stringify(update), JSON.stringify({ ...serverPackage, ...PackageMixins.remote(), failedInstall: false, deploymentKey }), "checkForUpdate did not return the update from the server");
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ let DownloadProgressTest = createTestCaseComponent(
|
||||
"should successfully download all the bytes contained in the test packages",
|
||||
() => {
|
||||
testPackages.forEach((aPackage, index) => {
|
||||
testPackages[index] = Object.assign(aPackage, PackageMixins.remote);
|
||||
testPackages[index] = Object.assign(aPackage, PackageMixins.remote());
|
||||
});
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ let RollbackTest = React.createClass({
|
||||
await NativeCodePush.downloadAndReplaceCurrentBundle("http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/RollbackTestBundleV1Pass.includeRequire.runModule.bundle?platform=ios&dev=true");
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
|
||||
let localPackage = await remotePackage.download();
|
||||
return await localPackage.install(NativeCodePush.codePushInstallModeImmediate);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export default {
|
||||
deploymentKey: "myKey123",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
|
||||
@@ -21,7 +21,7 @@ let InstallModeImmediateTest = createTestCaseComponent(
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeImmediateTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
},
|
||||
async () => {
|
||||
let localPackage = await remotePackage.download();
|
||||
|
||||
@@ -22,7 +22,7 @@ let InstallModeOnNextRestartTest = createTestCaseComponent(
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeOnNextRestartTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
},
|
||||
async () => {
|
||||
let localPackage = await remotePackage.download();
|
||||
|
||||
@@ -21,7 +21,7 @@ let InstallModeOnNextResumeTest = createTestCaseComponent(
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeOnNextResumeTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
},
|
||||
async () => {
|
||||
let localPackage = await remotePackage.download()
|
||||
|
||||
@@ -21,7 +21,7 @@ let IsFailedUpdateTest = createTestCaseComponent(
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/IsFailedUpdateTestBundleV1.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
},
|
||||
async () => {
|
||||
let localPackage = await remotePackage.download();
|
||||
|
||||
@@ -20,7 +20,7 @@ let IsFirstRunTest = createTestCaseComponent(
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/CheckIsFirstRunAndPassTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
},
|
||||
async () => {
|
||||
let localPackage = await remotePackage.download();
|
||||
|
||||
@@ -21,7 +21,7 @@ let IsPendingTest = createTestCaseComponent(
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/CheckIsFirstRunAndPassTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
},
|
||||
async () => {
|
||||
let localPackage = await remotePackage.download();
|
||||
|
||||
@@ -21,7 +21,7 @@ let NotifyApplicationReadyTest = createTestCaseComponent(
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/NotifyApplicationReadyAndRestart.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
},
|
||||
async () => {
|
||||
let localPackage = await remotePackage.download()
|
||||
|
||||
@@ -21,7 +21,7 @@ let RollbackTest = createTestCaseComponent(
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/RollbackTestBundleV1.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote());
|
||||
},
|
||||
async () => {
|
||||
let localPackage = await remotePackage.download()
|
||||
|
||||
@@ -13,6 +13,16 @@ function createMockAcquisitionSdk(serverPackage, localPackage, expectedDeploymen
|
||||
callback(/*err:*/ null, serverPackage);
|
||||
};
|
||||
|
||||
AcquisitionManager.prototype.reportStatusDeploy = (package, status, callback) => {
|
||||
// No-op and return success.
|
||||
callback(null, null);
|
||||
};
|
||||
|
||||
AcquisitionManager.prototype.reportStatusDownload = (package, callback) => {
|
||||
// No-op and return success.
|
||||
callback(null, null);
|
||||
};
|
||||
|
||||
return AcquisitionManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,10 @@ let CodePushDemoApp = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
CodePush.notifyApplicationReady();
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return { };
|
||||
},
|
||||
|
||||
@@ -23,7 +23,9 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.provider.Settings;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@@ -38,22 +40,32 @@ import java.util.zip.ZipFile;
|
||||
|
||||
public class CodePush {
|
||||
|
||||
private static boolean needToReportRollback = false;
|
||||
private static boolean isRunningBinaryVersion = false;
|
||||
private static boolean testConfigurationFlag = false;
|
||||
|
||||
private boolean didUpdate = false;
|
||||
|
||||
private String assetsBundleFileName;
|
||||
|
||||
private final String ASSETS_BUNDLE_PREFIX = "assets://";
|
||||
private final String BINARY_MODIFIED_TIME_KEY = "binaryModifiedTime";
|
||||
private final String CODE_PUSH_PREFERENCES = "CodePush";
|
||||
private final String DEPLOYMENT_FAILED_STATUS = "DeploymentFailed";
|
||||
private final String DEPLOYMENT_KEY_KEY = "deploymentKey";
|
||||
private final String DEPLOYMENT_SUCCEEDED_STATUS = "DeploymentSucceeded";
|
||||
private final String DOWNLOAD_PROGRESS_EVENT_NAME = "CodePushDownloadProgress";
|
||||
private final String FAILED_UPDATES_KEY = "CODE_PUSH_FAILED_UPDATES";
|
||||
private final String PENDING_UPDATE_KEY = "CODE_PUSH_PENDING_UPDATE";
|
||||
private final String LABEL_KEY = "label";
|
||||
private final String PACKAGE_HASH_KEY = "packageHash";
|
||||
private final String PENDING_UPDATE_HASH_KEY = "hash";
|
||||
private final String PENDING_UPDATE_IS_LOADING_KEY = "isLoading";
|
||||
private final String ASSETS_BUNDLE_PREFIX = "assets://";
|
||||
private final String CODE_PUSH_PREFERENCES = "CodePush";
|
||||
private final String DOWNLOAD_PROGRESS_EVENT_NAME = "CodePushDownloadProgress";
|
||||
private final String PENDING_UPDATE_KEY = "CODE_PUSH_PENDING_UPDATE";
|
||||
private final String RESOURCES_BUNDLE = "resources.arsc";
|
||||
private final String LAST_DEPLOYMENT_REPORT_KEY = "CODE_PUSH_LAST_DEPLOYMENT_REPORT";
|
||||
|
||||
// This needs to be kept in sync with https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java#L78
|
||||
private final String REACT_DEV_BUNDLE_CACHE_FILE_NAME = "ReactNativeDevBundle.js";
|
||||
private final String BINARY_MODIFIED_TIME_KEY = "binaryModifiedTime";
|
||||
|
||||
private CodePushPackage codePushPackage;
|
||||
private CodePushReactPackage codePushReactPackage;
|
||||
@@ -132,6 +144,7 @@ public class CodePush {
|
||||
if (packageFilePath == null) {
|
||||
// There has not been any downloaded updates.
|
||||
CodePushUtils.logBundleUrl(binaryJsBundleUrl);
|
||||
isRunningBinaryVersion = true;
|
||||
return binaryJsBundleUrl;
|
||||
}
|
||||
|
||||
@@ -142,11 +155,12 @@ public class CodePush {
|
||||
binaryModifiedDateDuringPackageInstall = Long.parseLong(binaryModifiedDateDuringPackageInstallString);
|
||||
}
|
||||
|
||||
String pacakgeAppVersion = CodePushUtils.tryGetString(packageMetadata, "appVersion");
|
||||
String packageAppVersion = CodePushUtils.tryGetString(packageMetadata, "appVersion");
|
||||
if (binaryModifiedDateDuringPackageInstall != null &&
|
||||
binaryModifiedDateDuringPackageInstall == binaryResourcesModifiedTime &&
|
||||
this.appVersion.equals(pacakgeAppVersion)) {
|
||||
(this.isUsingTestConfiguration() || this.appVersion.equals(packageAppVersion))) {
|
||||
CodePushUtils.logBundleUrl(packageFilePath);
|
||||
isRunningBinaryVersion = false;
|
||||
return packageFilePath;
|
||||
} else {
|
||||
// The binary version is newer.
|
||||
@@ -156,15 +170,44 @@ public class CodePush {
|
||||
}
|
||||
|
||||
CodePushUtils.logBundleUrl(binaryJsBundleUrl);
|
||||
isRunningBinaryVersion = true;
|
||||
return binaryJsBundleUrl;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error in getting current package bundle path", e);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new CodePushUnknownException("Error in reading binary modified date from package metadata", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getPackageStatusReportIdentifier(WritableMap updatePackage) {
|
||||
// Because deploymentKeys can be dynamically switched, we use a
|
||||
// combination of the deploymentKey and label as the packageIdentifier.
|
||||
String deploymentKey = CodePushUtils.tryGetString(updatePackage, DEPLOYMENT_KEY_KEY);
|
||||
String label = CodePushUtils.tryGetString(updatePackage, LABEL_KEY);
|
||||
if (deploymentKey != null && label != null) {
|
||||
return deploymentKey + ":" + label;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private JSONArray getFailedUpdates() {
|
||||
SharedPreferences settings = applicationContext.getSharedPreferences(CODE_PUSH_PREFERENCES, 0);
|
||||
String failedUpdatesString = settings.getString(FAILED_UPDATES_KEY, null);
|
||||
if (failedUpdatesString == null) {
|
||||
return new JSONArray();
|
||||
}
|
||||
|
||||
try {
|
||||
JSONArray failedUpdates = new JSONArray(failedUpdatesString);
|
||||
return failedUpdates;
|
||||
} catch (JSONException e) {
|
||||
// Unrecognized data format, clear and replace with expected format.
|
||||
JSONArray emptyArray = new JSONArray();
|
||||
settings.edit().putString(FAILED_UPDATES_KEY, emptyArray.toString()).commit();
|
||||
return emptyArray;
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject getPendingUpdate() {
|
||||
SharedPreferences settings = applicationContext.getSharedPreferences(CODE_PUSH_PREFERENCES, 0);
|
||||
String pendingUpdateString = settings.getString(PENDING_UPDATE_KEY, null);
|
||||
@@ -200,6 +243,7 @@ public class CodePush {
|
||||
// Pending update was initialized, but notifyApplicationReady was not called.
|
||||
// Therefore, deduce that it is a broken update and rollback.
|
||||
CodePushUtils.log("Update did not finish loading the last time, rolling back to a previous version.");
|
||||
needToReportRollback = true;
|
||||
rollbackPackage();
|
||||
} else {
|
||||
// Clear the React dev bundle cache so that new updates can be loaded.
|
||||
@@ -217,22 +261,35 @@ public class CodePush {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFailedHash(String packageHash) {
|
||||
|
||||
private boolean isDeploymentStatusNotYetReported(String appVersionOrPackageIdentifier) {
|
||||
SharedPreferences settings = applicationContext.getSharedPreferences(CODE_PUSH_PREFERENCES, 0);
|
||||
String failedUpdatesString = settings.getString(FAILED_UPDATES_KEY, null);
|
||||
if (failedUpdatesString == null) {
|
||||
return false;
|
||||
String lastDeploymentReportIdentifier = settings.getString(LAST_DEPLOYMENT_REPORT_KEY, null);
|
||||
if (lastDeploymentReportIdentifier == null) {
|
||||
return true;
|
||||
} else {
|
||||
return !lastDeploymentReportIdentifier.equals(appVersionOrPackageIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFailedHash(String packageHash) {
|
||||
JSONArray failedUpdates = getFailedUpdates();
|
||||
if (packageHash != null) {
|
||||
for (int i = 0; i < failedUpdates.length(); i++) {
|
||||
JSONObject failedPackage = null;
|
||||
try {
|
||||
failedPackage = failedUpdates.getJSONObject(i);
|
||||
String failedPackageHash = failedPackage.getString(PACKAGE_HASH_KEY);
|
||||
if (packageHash.equals(failedPackageHash)) {
|
||||
return true;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
throw new CodePushUnknownException("Unable to read failedUpdates data stored in SharedPreferences.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject failedUpdates = new JSONObject(failedUpdatesString);
|
||||
return failedUpdates.has(packageHash);
|
||||
} catch (JSONException e) {
|
||||
// Should not happen.
|
||||
throw new CodePushUnknownException("Unable to parse failed updates information " +
|
||||
failedUpdatesString + " stored in SharedPreferences", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isPendingUpdate(String packageHash) {
|
||||
@@ -249,6 +306,11 @@ public class CodePush {
|
||||
}
|
||||
}
|
||||
|
||||
private void recordDeploymentStatusReported(String appVersionOrPackageIdentifier) {
|
||||
SharedPreferences settings = applicationContext.getSharedPreferences(CODE_PUSH_PREFERENCES, 0);
|
||||
settings.edit().putString(LAST_DEPLOYMENT_REPORT_KEY, appVersionOrPackageIdentifier).commit();
|
||||
}
|
||||
|
||||
private void removeFailedUpdates() {
|
||||
SharedPreferences settings = applicationContext.getSharedPreferences(CODE_PUSH_PREFERENCES, 0);
|
||||
settings.edit().remove(FAILED_UPDATES_KEY).commit();
|
||||
@@ -260,45 +322,31 @@ public class CodePush {
|
||||
}
|
||||
|
||||
private void rollbackPackage() {
|
||||
try {
|
||||
String packageHash = codePushPackage.getCurrentPackageHash();
|
||||
saveFailedUpdate(packageHash);
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Attempted a rollback without having a current downloaded package", e);
|
||||
}
|
||||
|
||||
try {
|
||||
codePushPackage.rollbackPackage();
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error in rolling back package", e);
|
||||
}
|
||||
|
||||
WritableMap failedPackage = codePushPackage.getCurrentPackage();
|
||||
saveFailedUpdate(failedPackage);
|
||||
codePushPackage.rollbackPackage();
|
||||
removePendingUpdate();
|
||||
}
|
||||
|
||||
private void saveFailedUpdate(String packageHash) {
|
||||
private void saveFailedUpdate(WritableMap failedPackage) {
|
||||
SharedPreferences settings = applicationContext.getSharedPreferences(CODE_PUSH_PREFERENCES, 0);
|
||||
String failedUpdatesString = settings.getString(FAILED_UPDATES_KEY, null);
|
||||
JSONObject failedUpdates;
|
||||
JSONArray failedUpdates;
|
||||
if (failedUpdatesString == null) {
|
||||
failedUpdates = new JSONObject();
|
||||
failedUpdates = new JSONArray();
|
||||
} else {
|
||||
try {
|
||||
failedUpdates = new JSONObject(failedUpdatesString);
|
||||
failedUpdates = new JSONArray(failedUpdatesString);
|
||||
} catch (JSONException e) {
|
||||
// Should not happen.
|
||||
throw new CodePushMalformedDataException("Unable to parse failed updates information " +
|
||||
failedUpdatesString + " stored in SharedPreferences", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
failedUpdates.put(packageHash, true);
|
||||
settings.edit().putString(FAILED_UPDATES_KEY, failedUpdates.toString()).commit();
|
||||
} catch (JSONException e) {
|
||||
// Should not happen unless the packageHash is null.
|
||||
throw new CodePushUnknownException("Unable to save package hash " +
|
||||
packageHash + " as a failed update", e);
|
||||
}
|
||||
|
||||
JSONObject failedPackageJSON = CodePushUtils.convertReadableToJsonObject(failedPackage);
|
||||
failedUpdates.put(failedPackageJSON);
|
||||
settings.edit().putString(FAILED_UPDATES_KEY, failedUpdates.toString()).commit();
|
||||
}
|
||||
|
||||
private void savePendingUpdate(String packageHash, boolean isLoading) {
|
||||
@@ -377,6 +425,9 @@ public class CodePush {
|
||||
configMap.putInt("buildVersion", buildVersion);
|
||||
configMap.putString("deploymentKey", deploymentKey);
|
||||
configMap.putString("serverUrl", serverUrl);
|
||||
configMap.putString("clientUniqueId",
|
||||
Settings.Secure.getString(mainActivity.getContentResolver(),
|
||||
android.provider.Settings.Secure.ANDROID_ID));
|
||||
promise.resolve(configMap);
|
||||
}
|
||||
|
||||
@@ -385,30 +436,76 @@ public class CodePush {
|
||||
AsyncTask asyncTask = new AsyncTask() {
|
||||
@Override
|
||||
protected Void doInBackground(Object... params) {
|
||||
try {
|
||||
WritableMap currentPackage = codePushPackage.getCurrentPackage();
|
||||
WritableMap currentPackage = codePushPackage.getCurrentPackage();
|
||||
|
||||
Boolean isPendingUpdate = false;
|
||||
Boolean isPendingUpdate = false;
|
||||
|
||||
if (currentPackage.hasKey(codePushPackage.PACKAGE_HASH_KEY)) {
|
||||
String currentHash = currentPackage.getString(codePushPackage.PACKAGE_HASH_KEY);
|
||||
isPendingUpdate = CodePush.this.isPendingUpdate(currentHash);
|
||||
}
|
||||
|
||||
currentPackage.putBoolean("isPending", isPendingUpdate);
|
||||
promise.resolve(currentPackage);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
promise.reject(e.getMessage());
|
||||
if (currentPackage.hasKey(codePushPackage.PACKAGE_HASH_KEY)) {
|
||||
String currentHash = currentPackage.getString(codePushPackage.PACKAGE_HASH_KEY);
|
||||
isPendingUpdate = CodePush.this.isPendingUpdate(currentHash);
|
||||
}
|
||||
|
||||
|
||||
currentPackage.putBoolean("isPending", isPendingUpdate);
|
||||
promise.resolve(currentPackage);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
asyncTask.execute();
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void getNewStatusReport(Promise promise) {
|
||||
if (needToReportRollback) {
|
||||
// Check if there was a rollback that was not yet reported
|
||||
needToReportRollback = false;
|
||||
JSONArray failedUpdates = getFailedUpdates();
|
||||
if (failedUpdates != null && failedUpdates.length() > 0) {
|
||||
try {
|
||||
JSONObject lastFailedPackageJSON = failedUpdates.getJSONObject(failedUpdates.length() - 1);
|
||||
WritableMap lastFailedPackage = CodePushUtils.convertJsonObjectToWriteable(lastFailedPackageJSON);
|
||||
String lastFailedPackageIdentifier = getPackageStatusReportIdentifier(lastFailedPackage);
|
||||
if (lastFailedPackage != null && isDeploymentStatusNotYetReported(lastFailedPackageIdentifier)) {
|
||||
recordDeploymentStatusReported(lastFailedPackageIdentifier);
|
||||
WritableNativeMap reportMap = new WritableNativeMap();
|
||||
reportMap.putMap("package", lastFailedPackage);
|
||||
reportMap.putString("status", DEPLOYMENT_FAILED_STATUS);
|
||||
promise.resolve(reportMap);
|
||||
return;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
throw new CodePushUnknownException("Unable to read failed updates information stored in SharedPreferences.", e);
|
||||
}
|
||||
}
|
||||
} else if (didUpdate) {
|
||||
// Check if the current CodePush package has been reported
|
||||
WritableMap currentPackage = codePushPackage.getCurrentPackage();
|
||||
if (currentPackage != null) {
|
||||
String currentPackageIdentifier = getPackageStatusReportIdentifier(currentPackage);
|
||||
if (currentPackageIdentifier != null && isDeploymentStatusNotYetReported(currentPackageIdentifier)) {
|
||||
recordDeploymentStatusReported(currentPackageIdentifier);
|
||||
WritableNativeMap reportMap = new WritableNativeMap();
|
||||
reportMap.putMap("package", currentPackage);
|
||||
reportMap.putString("status", DEPLOYMENT_SUCCEEDED_STATUS);
|
||||
promise.resolve(reportMap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (isRunningBinaryVersion) {
|
||||
// Check if the current appVersion has been reported.
|
||||
String binaryIdentifier = "" + getBinaryResourcesModifiedTime();
|
||||
if (isDeploymentStatusNotYetReported(binaryIdentifier)) {
|
||||
recordDeploymentStatusReported(binaryIdentifier);
|
||||
WritableNativeMap reportMap = new WritableNativeMap();
|
||||
reportMap.putString("appVersion", appVersion);
|
||||
promise.resolve(reportMap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
promise.resolve("");
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void installUpdate(final ReadableMap updatePackage, final int installMode, final Promise promise) {
|
||||
AsyncTask asyncTask = new AsyncTask() {
|
||||
@@ -464,16 +561,11 @@ public class CodePush {
|
||||
|
||||
@ReactMethod
|
||||
public void isFirstRun(String packageHash, Promise promise) {
|
||||
try {
|
||||
boolean isFirstRun = didUpdate
|
||||
&& packageHash != null
|
||||
&& packageHash.length() > 0
|
||||
&& packageHash.equals(codePushPackage.getCurrentPackageHash());
|
||||
promise.resolve(isFirstRun);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
promise.reject(e.getMessage());
|
||||
}
|
||||
boolean isFirstRun = didUpdate
|
||||
&& packageHash != null
|
||||
&& packageHash.length() > 0
|
||||
&& packageHash.equals(codePushPackage.getCurrentPackageHash());
|
||||
promise.resolve(isFirstRun);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
|
||||
@@ -50,20 +50,28 @@ public class CodePushPackage {
|
||||
return CodePushUtils.appendPathComponent(getCodePushPath(), STATUS_FILE);
|
||||
}
|
||||
|
||||
public WritableMap getCurrentPackageInfo() throws IOException {
|
||||
public WritableMap getCurrentPackageInfo() {
|
||||
String statusFilePath = getStatusFilePath();
|
||||
if (!CodePushUtils.fileAtPathExists(statusFilePath)) {
|
||||
return new WritableNativeMap();
|
||||
}
|
||||
|
||||
return CodePushUtils.getWritableMapFromFile(statusFilePath);
|
||||
try {
|
||||
return CodePushUtils.getWritableMapFromFile(statusFilePath);
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error getting current package info" , e);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCurrentPackageInfo(ReadableMap packageInfo) throws IOException {
|
||||
CodePushUtils.writeReadableMapToFile(packageInfo, getStatusFilePath());
|
||||
public void updateCurrentPackageInfo(ReadableMap packageInfo) {
|
||||
try {
|
||||
CodePushUtils.writeReadableMapToFile(packageInfo, getStatusFilePath());
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error updating current package info" , e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getCurrentPackageFolderPath() throws IOException {
|
||||
public String getCurrentPackageFolderPath() {
|
||||
WritableMap info = getCurrentPackageInfo();
|
||||
String packageHash = CodePushUtils.tryGetString(info, CURRENT_PACKAGE_KEY);
|
||||
if (packageHash == null) {
|
||||
@@ -73,7 +81,7 @@ public class CodePushPackage {
|
||||
return getPackageFolderPath(packageHash);
|
||||
}
|
||||
|
||||
public String getCurrentPackageBundlePath() throws IOException {
|
||||
public String getCurrentPackageBundlePath() {
|
||||
String packageFolder = getCurrentPackageFolderPath();
|
||||
if (packageFolder == null) {
|
||||
return null;
|
||||
@@ -86,17 +94,17 @@ public class CodePushPackage {
|
||||
return CodePushUtils.appendPathComponent(getCodePushPath(), packageHash);
|
||||
}
|
||||
|
||||
public String getCurrentPackageHash() throws IOException {
|
||||
public String getCurrentPackageHash() {
|
||||
WritableMap info = getCurrentPackageInfo();
|
||||
return CodePushUtils.tryGetString(info, CURRENT_PACKAGE_KEY);
|
||||
}
|
||||
|
||||
public String getPreviousPackageHash() throws IOException {
|
||||
public String getPreviousPackageHash() {
|
||||
WritableMap info = getCurrentPackageInfo();
|
||||
return CodePushUtils.tryGetString(info, PREVIOUS_PACKAGE_KEY);
|
||||
}
|
||||
|
||||
public WritableMap getCurrentPackage() throws IOException {
|
||||
public WritableMap getCurrentPackage() {
|
||||
String folderPath = getCurrentPackageFolderPath();
|
||||
if (folderPath == null) {
|
||||
return new WritableNativeMap();
|
||||
@@ -111,7 +119,7 @@ public class CodePushPackage {
|
||||
}
|
||||
}
|
||||
|
||||
public WritableMap getPackage(String packageHash) throws IOException {
|
||||
public WritableMap getPackage(String packageHash) {
|
||||
String folderPath = getPackageFolderPath(packageHash);
|
||||
String packageFilePath = CodePushUtils.appendPathComponent(folderPath, PACKAGE_FILE_NAME);
|
||||
try {
|
||||
@@ -185,7 +193,7 @@ public class CodePushPackage {
|
||||
updateCurrentPackageInfo(info);
|
||||
}
|
||||
|
||||
public void rollbackPackage() throws IOException {
|
||||
public void rollbackPackage() {
|
||||
WritableMap info = getCurrentPackageInfo();
|
||||
String currentPackageFolderPath = getCurrentPackageFolderPath();
|
||||
CodePushUtils.deleteDirectoryAtPath(currentPackageFolderPath);
|
||||
|
||||
@@ -1,35 +1,39 @@
|
||||
import { AcquisitionManager as Sdk } from "code-push/script/acquisition-sdk";
|
||||
import { DeviceEventEmitter } from "react-native";
|
||||
|
||||
// This function is used to augment remote and local
|
||||
// package objects with additional functionality/properties
|
||||
// beyond what is included in the metadata sent by the server.
|
||||
module.exports = (NativeCodePush) => {
|
||||
const remote = {
|
||||
async download(downloadProgressCallback) {
|
||||
if (!this.downloadUrl) {
|
||||
throw new Error("Cannot download an update without a download url");
|
||||
}
|
||||
const remote = (reportStatusDownload) => {
|
||||
return {
|
||||
async download(downloadProgressCallback) {
|
||||
if (!this.downloadUrl) {
|
||||
throw new Error("Cannot download an update without a download url");
|
||||
}
|
||||
|
||||
let downloadProgressSubscription;
|
||||
if (downloadProgressCallback) {
|
||||
// Use event subscription to obtain download progress.
|
||||
downloadProgressSubscription = DeviceEventEmitter.addListener(
|
||||
"CodePushDownloadProgress",
|
||||
downloadProgressCallback
|
||||
);
|
||||
}
|
||||
let downloadProgressSubscription;
|
||||
if (downloadProgressCallback) {
|
||||
// Use event subscription to obtain download progress.
|
||||
downloadProgressSubscription = DeviceEventEmitter.addListener(
|
||||
"CodePushDownloadProgress",
|
||||
downloadProgressCallback
|
||||
);
|
||||
}
|
||||
|
||||
// Use the downloaded package info. Native code will save the package info
|
||||
// so that the client knows what the current package version is.
|
||||
try {
|
||||
const downloadedPackage = await NativeCodePush.downloadUpdate(this);
|
||||
return { ...downloadedPackage, ...local };
|
||||
} finally {
|
||||
downloadProgressSubscription && downloadProgressSubscription.remove();
|
||||
}
|
||||
},
|
||||
// Use the downloaded package info. Native code will save the package info
|
||||
// so that the client knows what the current package version is.
|
||||
try {
|
||||
const downloadedPackage = await NativeCodePush.downloadUpdate(this);
|
||||
reportStatusDownload && reportStatusDownload(this);
|
||||
return { ...downloadedPackage, ...local };
|
||||
} finally {
|
||||
downloadProgressSubscription && downloadProgressSubscription.remove();
|
||||
}
|
||||
},
|
||||
|
||||
isPending: false // A remote package could never be in a pending state
|
||||
isPending: false // A remote package could never be in a pending state
|
||||
};
|
||||
};
|
||||
|
||||
const local = {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"url": "https://github.com/Microsoft/react-native-code-push"
|
||||
},
|
||||
"dependencies": {
|
||||
"code-push": "^1.1.1-beta",
|
||||
"code-push": "1.5.1-beta",
|
||||
"semver": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
module.exports = {
|
||||
async request(verb, url, body, callback) {
|
||||
if (typeof body === "function") {
|
||||
callback = body;
|
||||
body = null;
|
||||
async request(verb, url, requestBody, callback) {
|
||||
if (typeof requestBody === "function") {
|
||||
callback = requestBody;
|
||||
requestBody = null;
|
||||
}
|
||||
|
||||
var headers = {
|
||||
@@ -10,15 +10,15 @@ module.exports = {
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
|
||||
if (body && typeof body === "object") {
|
||||
body = JSON.stringify(body);
|
||||
if (requestBody && typeof requestBody === "object") {
|
||||
requestBody = JSON.stringify(requestBody);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: verb,
|
||||
method: getHttpMethodName(verb),
|
||||
headers: headers,
|
||||
body: body
|
||||
body: requestBody
|
||||
});
|
||||
|
||||
const statusCode = response.status;
|
||||
@@ -28,4 +28,20 @@ module.exports = {
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function getHttpMethodName(verb) {
|
||||
// Note: This should stay in sync with the enum definition in
|
||||
// https://github.com/Microsoft/code-push/blob/master/sdk/script/acquisition-sdk.ts#L6
|
||||
return [
|
||||
"GET",
|
||||
"HEAD",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"TRACE",
|
||||
"OPTIONS",
|
||||
"CONNECT",
|
||||
"PATCH"
|
||||
][verb];
|
||||
}
|
||||
Reference in New Issue
Block a user