retry status report if failure

This commit is contained in:
Geoffrey Goh 2016-05-12 23:55:36 -07:00
Родитель 8310bd6d19
Коммит 07d3aced97
18 изменённых файлов: 494 добавлений и 162 удалений

Просмотреть файл

@ -24,30 +24,43 @@ var CodePush = (function () {
CodePush.prototype.restartApplication = function (installSuccess, errorCallback) {
cordova.exec(installSuccess, errorCallback, "CodePush", "restartApplication", []);
};
CodePush.prototype.reportStatus = function (status, label, appVersion, currentDeploymentKey, previousLabelOrAppVersion, previousDeploymentKey) {
try {
var createPackageForReporting = function (label, appVersion) {
return {
label: label, appVersion: appVersion,
deploymentKey: currentDeploymentKey, description: null,
isMandatory: false, packageHash: null,
packageSize: null, failedInstall: false
};
CodePush.prototype.reportStatus = function (status, label, appVersion, deploymentKey, previousLabelOrAppVersion, previousDeploymentKey) {
var createPackageForReporting = function (label, appVersion) {
return {
label: label, appVersion: appVersion, deploymentKey: deploymentKey,
description: null, isMandatory: false,
packageHash: null, packageSize: null,
failedInstall: false
};
switch (status) {
case ReportStatus.STORE_VERSION:
Sdk.reportStatusDeploy(null, AcquisitionStatus.DeploymentSucceeded, currentDeploymentKey, previousLabelOrAppVersion, previousDeploymentKey);
break;
case ReportStatus.UPDATE_CONFIRMED:
Sdk.reportStatusDeploy(createPackageForReporting(label, appVersion), AcquisitionStatus.DeploymentSucceeded, currentDeploymentKey, previousLabelOrAppVersion, previousDeploymentKey);
break;
case ReportStatus.UPDATE_ROLLED_BACK:
Sdk.reportStatusDeploy(createPackageForReporting(label, appVersion), AcquisitionStatus.DeploymentFailed, currentDeploymentKey, previousLabelOrAppVersion, previousDeploymentKey);
break;
};
var reportDone = function (error) {
var reportArgs = {
status: status,
label: label,
appVersion: appVersion,
deploymentKey: deploymentKey,
previousLabelOrAppVersion: previousLabelOrAppVersion,
previousDeploymentKey: previousDeploymentKey
};
if (error) {
CodePushUtil.logError("An error occurred while reporting status: " + JSON.stringify(reportArgs), error);
cordova.exec(null, null, "CodePush", "reportFailed", [reportArgs]);
}
}
catch (e) {
CodePushUtil.logError("An error occurred while reporting." + CodePushUtil.getErrorMessage(e));
else {
CodePushUtil.logMessage("Reported status: " + JSON.stringify(reportArgs));
cordova.exec(null, null, "CodePush", "reportSucceeded", [reportArgs]);
}
};
switch (status) {
case ReportStatus.STORE_VERSION:
Sdk.reportStatusDeploy(null, AcquisitionStatus.DeploymentSucceeded, deploymentKey, previousLabelOrAppVersion, previousDeploymentKey, reportDone);
break;
case ReportStatus.UPDATE_CONFIRMED:
Sdk.reportStatusDeploy(createPackageForReporting(label, appVersion), AcquisitionStatus.DeploymentSucceeded, deploymentKey, previousLabelOrAppVersion, previousDeploymentKey, reportDone);
break;
case ReportStatus.UPDATE_ROLLED_BACK:
Sdk.reportStatusDeploy(createPackageForReporting(label, appVersion), AcquisitionStatus.DeploymentFailed, deploymentKey, previousLabelOrAppVersion, previousDeploymentKey, reportDone);
break;
}
};
CodePush.prototype.getCurrentPackage = function (packageSuccess, packageError) {

Просмотреть файл

@ -70,13 +70,12 @@ var Sdk = (function () {
callback && callback(error, null);
}
else {
console.log("Reporting status: " + status + " label: " + (pkg && pkg.label) + " appVersion: " + Sdk.DefaultConfiguration.appVersion + " previousLabelOrAppVersion: " + previousLabelOrAppVersion + " previousDeploymentKey:" + previousDeploymentKey);
acquisitionManager.reportStatusDeploy(pkg, status, previousLabelOrAppVersion, previousDeploymentKey, callback);
}
}, currentDeploymentKey, "application/json");
}
catch (e) {
callback && callback(new Error("An error occured while reporting the deployment status. " + e), null);
callback && callback(e, null);
}
};
Sdk.reportStatusDownload = function (pkg, deploymentKey, callback) {

Просмотреть файл

@ -7,8 +7,8 @@
<repo>https://github.com/Microsoft/cordova-plugin-code-push.git</repo>
<dependency id="code-push" version=">=1.8.0-beta" />
<dependency id="cordova-plugin-file" version=">=3.0.0" />
<dependency id="cordova-plugin-file-transfer" version=">=1.3.0" />
<dependency id="cordova-plugin-file" version=">=3.0.0" />
<dependency id="cordova-plugin-file-transfer" version=">=1.3.0" />
<dependency id="cordova-plugin-zip" version=">=3.0.0" />
<dependency id="cordova-plugin-dialogs" version=">=1.1.1" />
<dependency id="cordova-plugin-device" version=">=1.1.0" />
@ -66,8 +66,10 @@
<source-file src="src/android/CodePushReportingManager.java" target-dir="src/com/microsoft/cordova" />
<source-file src="src/android/InstallMode.java" target-dir="src/com/microsoft/cordova" />
<source-file src="src/android/InstallOptions.java" target-dir="src/com/microsoft/cordova" />
<source-file src="src/android/Utilities.java" target-dir="src/com/microsoft/cordova" />
<source-file src="src/android/ReportingStatus.java" target-dir="src/com/microsoft/cordova" />
<source-file src="src/android/StatusReport.java" target-dir="src/com/microsoft/cordova" />
<source-file src="src/android/UpdateHashUtils.java" target-dir="src/com/microsoft/cordova" />
<source-file src="src/android/Utilities.java" target-dir="src/com/microsoft/cordova" />
<config-file target="config.xml" parent="/*">
<feature name="CodePush">
<param name="android-package" value="com.microsoft.cordova.CodePush" />
@ -83,15 +85,17 @@
<source-file src="src/ios/CodePushPackageMetadata.m" />
<header-file src="src/ios/CodePushPackageManager.h" />
<source-file src="src/ios/CodePushPackageManager.m" />
<source-file src="src/ios/CodePushReportingManager.m" />
<header-file src="src/ios/CodePushReportingManager.h" />
<header-file src="src/ios/Utilities.h" />
<source-file src="src/ios/Utilities.m" />
<source-file src="src/ios/CodePushReportingManager.m" />
<header-file src="src/ios/InstallOptions.h" />
<source-file src="src/ios/InstallOptions.m" />
<header-file src="src/ios/InstallMode.h" />
<source-file src="src/ios/UpdateHashUtils.m" />
<header-file src="src/ios/StatusReport.h" />
<source-file src="src/ios/StatusReport.m" />
<header-file src="src/ios/UpdateHashUtils.h" />
<source-file src="src/ios/UpdateHashUtils.m" />
<header-file src="src/ios/Utilities.h" />
<source-file src="src/ios/Utilities.m" />
<config-file target="config.xml" parent="/*">
<feature name="CodePush">
<param name="ios-package" value="CodePush" />

Просмотреть файл

@ -46,32 +46,36 @@ public class CodePush extends CordovaPlugin {
@Override
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) {
if ("getServerURL".equals(action)) {
this.returnStringPreference("codepushserverurl", callbackContext);
return true;
if ("getAppVersion".equals(action)) {
return execGetAppVersion(callbackContext);
} else if ("getBinaryHash".equals(action)) {
return execGetBinaryHash(callbackContext);
} else if ("getDeploymentKey".equals(action)) {
this.returnStringPreference(DEPLOYMENT_KEY_PREFERENCE, callbackContext);
return true;
} else if ("getNativeBuildTime".equals(action)) {
return execGetNativeBuildTime(callbackContext);
} else if ("getAppVersion".equals(action)) {
return execGetAppVersion(callbackContext);
} else if ("getBinaryHash".equals(action)) {
return execGetBinaryHash(callbackContext);
} else if ("preInstall".equals(action)) {
return execPreInstall(args, callbackContext);
} else if ("getServerURL".equals(action)) {
this.returnStringPreference("codepushserverurl", callbackContext);
return true;
} else if ("install".equals(action)) {
return execInstall(args, callbackContext);
} else if ("updateSuccess".equals(action)) {
return execUpdateSuccess(callbackContext);
} else if ("restartApplication".equals(action)) {
return execRestartApplication(args, callbackContext);
} else if ("isPendingUpdate".equals(action)) {
return execIsPendingUpdate(args, callbackContext);
} else if ("isFailedUpdate".equals(action)) {
return execIsFailedUpdate(args, callbackContext);
} else if ("isFirstRun".equals(action)) {
return execIsFirstRun(args, callbackContext);
} else if ("isPendingUpdate".equals(action)) {
return execIsPendingUpdate(args, callbackContext);
} else if ("preInstall".equals(action)) {
return execPreInstall(args, callbackContext);
} else if ("reportFailed".equals(action)) {
return execReportFailed(args, callbackContext);
} else if ("reportSucceeded".equals(action)) {
return execReportSucceeded(args, callbackContext);
} else if ("restartApplication".equals(action)) {
return execRestartApplication(args, callbackContext);
} else if ("updateSuccess".equals(action)) {
return execUpdateSuccess(callbackContext);
} else {
return false;
}
@ -109,17 +113,17 @@ public class CodePush extends CordovaPlugin {
/* save reporting status for first install */
try {
String appVersion = Utilities.getAppVersionName(cordova.getActivity());
codePushReportingManager.reportStatus(CodePushReportingManager.Status.STORE_VERSION, null, appVersion, mainWebView.getPreferences().getString(DEPLOYMENT_KEY_PREFERENCE, null), this.mainWebView);
codePushReportingManager.reportStatus(new StatusReport(ReportingStatus.STORE_VERSION, null, appVersion, mainWebView.getPreferences().getString(DEPLOYMENT_KEY_PREFERENCE, null)), this.mainWebView);
} catch (PackageManager.NameNotFoundException e) {
// Should not happen unless the appVersion is not specified, in which case we can't report anything anyway.
e.printStackTrace();
}
}
if (this.codePushPackageManager.installNeedsConfirmation()) {
} else if (this.codePushPackageManager.installNeedsConfirmation()) {
/* save reporting status */
CodePushPackageMetadata currentMetadata = this.codePushPackageManager.getCurrentPackageMetadata();
codePushReportingManager.reportStatus(CodePushReportingManager.Status.UPDATE_CONFIRMED, currentMetadata.label, currentMetadata.appVersion, currentMetadata.deploymentKey, this.mainWebView);
codePushReportingManager.reportStatus(new StatusReport(ReportingStatus.UPDATE_CONFIRMED, currentMetadata.label, currentMetadata.appVersion, currentMetadata.deploymentKey), this.mainWebView);
} else if (codePushReportingManager.hasFailedReport()) {
codePushReportingManager.reportStatus(codePushReportingManager.getAndClearFailedReport(), this.mainWebView);
}
this.codePushPackageManager.clearInstallNeedsConfirmation();
@ -197,6 +201,28 @@ public class CodePush extends CordovaPlugin {
return true;
}
private boolean execReportFailed(CordovaArgs args, CallbackContext callbackContext) {
try {
StatusReport statusReport = StatusReport.deserialize(args.optJSONObject(0));
codePushReportingManager.saveFailedReport(statusReport);
} catch (JSONException e) {
Utilities.logException(e);
}
return true;
}
private boolean execReportSucceeded(CordovaArgs args, CallbackContext callbackContext) {
try {
StatusReport statusReport = StatusReport.deserialize(args.optJSONObject(0));
codePushReportingManager.saveSuccessfulReport(statusReport);
} catch (JSONException e) {
Utilities.logException(e);
}
return true;
}
private boolean execRestartApplication(CordovaArgs args, CallbackContext callbackContext) {
try {
/* check if we have a deployed package already */
@ -312,7 +338,7 @@ public class CodePush extends CordovaPlugin {
this.codePushPackageManager.clearInstallNeedsConfirmation();
try {
String appVersion = Utilities.getAppVersionName(cordova.getActivity());
codePushReportingManager.reportStatus(CodePushReportingManager.Status.STORE_VERSION, null, appVersion, mainWebView.getPreferences().getString(DEPLOYMENT_KEY_PREFERENCE, null), this.mainWebView);
codePushReportingManager.reportStatus(new StatusReport(ReportingStatus.STORE_VERSION, null, appVersion, mainWebView.getPreferences().getString(DEPLOYMENT_KEY_PREFERENCE, null)), this.mainWebView);
} catch (PackageManager.NameNotFoundException e) {
// Should not happen unless the appVersion is not specified, in which case we can't report anything anyway.
e.printStackTrace();
@ -330,7 +356,7 @@ public class CodePush extends CordovaPlugin {
if (this.codePushPackageManager.installNeedsConfirmation()) {
/* save status for later reporting */
CodePushPackageMetadata currentMetadata = this.codePushPackageManager.getCurrentPackageMetadata();
codePushReportingManager.reportStatus(CodePushReportingManager.Status.UPDATE_ROLLED_BACK, currentMetadata.label, currentMetadata.appVersion, currentMetadata.deploymentKey, this.mainWebView);
codePushReportingManager.reportStatus(new StatusReport(ReportingStatus.UPDATE_ROLLED_BACK, currentMetadata.label, currentMetadata.appVersion, currentMetadata.deploymentKey), this.mainWebView);
/* revert application to the previous version */
this.codePushPackageManager.clearInstallNeedsConfirmation();
@ -461,6 +487,8 @@ public class CodePush extends CordovaPlugin {
handleAppStart();
this.markUpdate();
this.codePushPackageManager.clearPendingInstall();
} else if (codePushReportingManager.hasFailedReport()) {
codePushReportingManager.reportStatus(codePushReportingManager.getAndClearFailedReport(), this.mainWebView);
}
}
}

Просмотреть файл

@ -3,6 +3,8 @@ package com.microsoft.cordova;
import android.content.Context;
import android.content.SharedPreferences;
import org.json.JSONException;
import java.util.HashSet;
import java.util.Set;
@ -20,6 +22,8 @@ public class CodePushPreferences {
private static final String INSTALL_MIN_BACKGROUND_DURATION = "INSTALL_MINIMUM_BACKGROUND_DURATION";
private static final String INSTALL_NEEDS_CONFIRMATION = "INSTALL_NEEDS_CONFIRMATION";
private static final String INSTALL_NEEDS_CONFIRMATION_KEY = "INSTALL_NEEDS_CONFIRMATION_KEY";
private static final String FAILED_STATUS_REPORT_PREFERENCE = "CODE_PUSH_FAILED_STATUS_REPORT_PREFERENCE";
private static final String FAILED_STATUS_REPORT_PREFERENCE_KEY = "CODE_PUSH_FAILED_STATUS_REPORT_PREFERENCE_KEY";
private static final String FIRST_RUN_PREFERENCE = "CODE_PUSH_FIRST_RUN";
private static final String FIRST_RUN_PREFERENCE_KEY = "CODE_PUSH_FIRST_RUN_KEY";
private static final String LAST_VERSION_PREFERENCE = "CODE_PUSH_LAST_VERSION";
@ -134,6 +138,29 @@ public class CodePushPreferences {
editor.commit();
}
public void clearFailedReport() {
this.clearPreferences(CodePushPreferences.FAILED_STATUS_REPORT_PREFERENCE);
}
public StatusReport getFailedReport() {
SharedPreferences preferences = context.getSharedPreferences(CodePushPreferences.FAILED_STATUS_REPORT_PREFERENCE, Context.MODE_PRIVATE);
String statusReportJson = preferences.getString(CodePushPreferences.FAILED_STATUS_REPORT_PREFERENCE_KEY, null);
try {
return statusReportJson == null ? null : StatusReport.deserialize(statusReportJson);
} catch (JSONException e) {
// Should not happen
e.printStackTrace();
return null;
}
}
public void saveFailedReport(StatusReport statusReport) {
SharedPreferences preferences = context.getSharedPreferences(CodePushPreferences.FAILED_STATUS_REPORT_PREFERENCE, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(CodePushPreferences.FAILED_STATUS_REPORT_PREFERENCE_KEY, statusReport.serialize());
editor.commit();
}
public void saveLastVersion(String labelOrAppVersion, String deploymentKey) {
SharedPreferences preferences = context.getSharedPreferences(CodePushPreferences.LAST_VERSION_PREFERENCE, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();

Просмотреть файл

@ -2,7 +2,6 @@ package com.microsoft.cordova;
import org.apache.cordova.CordovaWebView;
import java.util.ArrayList;
import java.util.Locale;
import android.app.Activity;
@ -13,28 +12,7 @@ public class CodePushReportingManager {
private Activity cordovaActivity;
private CodePushPreferences codePushPreferences;
/**
* Defines application statuses we use in reporting events from the native to the JS layer.
*/
public static enum Status {
STORE_VERSION(0),
UPDATE_CONFIRMED(1),
UPDATE_ROLLED_BACK(2);
private int value;
Status(int i) {
this.value = i;
}
/**
* Returns the value associated with this enum.
*/
public int getValue() {
return this.value;
}
}
private Boolean hasFailedReport = null;
public CodePushReportingManager(Activity cordovaActivity, CodePushPreferences codePushPreferences) {
this.cordovaActivity = cordovaActivity;
@ -44,26 +22,22 @@ public class CodePushReportingManager {
/**
* Invokes the window.codePush.reportStatus JS function for the given webView.
*/
public void reportStatus(Status status, String label, String appVersion, String deploymentKey, final CordovaWebView webView) {
public void reportStatus(StatusReport statusReport, final CordovaWebView webView) {
/* JS function to call: window.codePush.reportStatus(status: number, label: String, appVersion: String, currentDeploymentKey: String, previousLabelOrAppVersion?: string, previousDeploymentKey?: string) */
if (deploymentKey == null || deploymentKey.isEmpty()) {
if (statusReport.deploymentKey == null || statusReport.deploymentKey.isEmpty()) {
return;
}
final String script = String.format(
Locale.US,
"javascript:document.addEventListener(\"deviceready\", function () { window.codePush.reportStatus(%d, %s, %s, %s, %s, %s); });",
status.getValue(),
convertStringParameter(label),
convertStringParameter(appVersion),
convertStringParameter(deploymentKey),
convertStringParameter(codePushPreferences.getLastVersionLabelOrAppVersion()),
convertStringParameter(codePushPreferences.getLastVersionDeploymentKey())
);
if (status == Status.STORE_VERSION || status == Status.UPDATE_CONFIRMED) {
codePushPreferences.saveLastVersion(label == null ? appVersion : label, deploymentKey);
}
statusReport.status.getValue(),
convertStringParameter(statusReport.label),
convertStringParameter(statusReport.appVersion),
convertStringParameter(statusReport.deploymentKey),
statusReport.lastVersionLabelOrAppVersion == null ? convertStringParameter(codePushPreferences.getLastVersionLabelOrAppVersion()) : convertStringParameter(statusReport.lastVersionLabelOrAppVersion),
statusReport.lastVersionDeploymentKey == null ? convertStringParameter(codePushPreferences.getLastVersionDeploymentKey()) : convertStringParameter(statusReport.lastVersionDeploymentKey)
);
cordovaActivity.runOnUiThread(new Runnable() {
public void run() {
@ -72,6 +46,34 @@ public class CodePushReportingManager {
});
}
public boolean hasFailedReport() {
if (this.hasFailedReport == null) {
this.hasFailedReport = codePushPreferences.getFailedReport() != null;
}
return this.hasFailedReport;
}
public StatusReport getAndClearFailedReport() {
StatusReport failedReport = codePushPreferences.getFailedReport();
codePushPreferences.clearFailedReport();
this.hasFailedReport = false;
return failedReport;
}
public void saveFailedReport(StatusReport statusReport) {
codePushPreferences.saveFailedReport(statusReport);
this.hasFailedReport = true;
}
public void saveSuccessfulReport(StatusReport statusReport) {
if (statusReport.status == ReportingStatus.STORE_VERSION || statusReport.status == ReportingStatus.UPDATE_CONFIRMED) {
codePushPreferences.saveLastVersion(statusReport.label == null ? statusReport.appVersion : statusReport.label, statusReport.deploymentKey);
codePushPreferences.clearFailedReport();
this.hasFailedReport = false;
}
}
private String convertStringParameter(String input) {
if (null == input) {
return "undefined";

Просмотреть файл

@ -0,0 +1,23 @@
package com.microsoft.cordova;
/**
* Defines application statuses we use in reporting events from the native to the JS layer.
*/
public enum ReportingStatus {
STORE_VERSION(0),
UPDATE_CONFIRMED(1),
UPDATE_ROLLED_BACK(2);
private int value;
ReportingStatus(int i) {
this.value = i;
}
/**
* Returns the value associated with this enum.
*/
public int getValue() {
return this.value;
}
}

Просмотреть файл

@ -0,0 +1,80 @@
package com.microsoft.cordova;
import org.json.JSONException;
import org.json.JSONObject;
public class StatusReport {
private static final String STATUS_KEY = "status";
private static final String LABEL_KEY = "label";
private static final String APP_VERSION_KEY = "appVersion";
private static final String DEPLOYMENT_KEY_KEY = "deploymentKey";
private static final String LAST_VERSION_LABEL_OR_APP_VERSION_KEY = "lastVersionLabelOrAppVersion";
private static final String LAST_VERSION_DEPLOYMENT_KEY_KEY = "lastVersionDeploymentKey";
ReportingStatus status;
String label;
String appVersion;
String deploymentKey;
String lastVersionLabelOrAppVersion;
String lastVersionDeploymentKey;
public StatusReport(int status, String label, String appVersion, String deploymentKey, String lastVersionLabelOrAppVersion, String lastVersionDeploymentKey) {
this(ReportingStatus.values()[status], label, appVersion, deploymentKey, lastVersionLabelOrAppVersion, lastVersionDeploymentKey);
}
public StatusReport(ReportingStatus status, String label, String appVersion, String deploymentKey) {
this(status, label, appVersion, deploymentKey, null, null);
}
public StatusReport(ReportingStatus status, String label, String appVersion, String deploymentKey, String lastVersionLabelOrAppVersion, String lastVersionDeploymentKey) {
this.status = status;
this.label = label;
this.appVersion = appVersion;
this.deploymentKey = deploymentKey;
this.lastVersionLabelOrAppVersion = lastVersionLabelOrAppVersion;
this.lastVersionDeploymentKey = lastVersionDeploymentKey;
}
public String serialize() {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put(STATUS_KEY, status.getValue());
jsonObject.put(LABEL_KEY, label);
jsonObject.put(APP_VERSION_KEY, appVersion);
if (deploymentKey != null) {
jsonObject.put(DEPLOYMENT_KEY_KEY, deploymentKey);
}
if (lastVersionLabelOrAppVersion != null) {
jsonObject.put(LAST_VERSION_LABEL_OR_APP_VERSION_KEY, lastVersionLabelOrAppVersion);
}
if (lastVersionDeploymentKey != null) {
jsonObject.put(LAST_VERSION_DEPLOYMENT_KEY_KEY, lastVersionDeploymentKey);
}
return jsonObject.toString();
} catch (JSONException e) {
// Should not happen
e.printStackTrace();
return null;
}
}
public static StatusReport deserialize(JSONObject jsonObject) throws JSONException {
return new StatusReport(
jsonObject.optInt(STATUS_KEY),
jsonObject.optString(LABEL_KEY, null),
jsonObject.optString(APP_VERSION_KEY, null),
jsonObject.optString(DEPLOYMENT_KEY_KEY, null),
jsonObject.optString(LAST_VERSION_LABEL_OR_APP_VERSION_KEY, null),
jsonObject.optString(LAST_VERSION_DEPLOYMENT_KEY_KEY, null)
);
}
public static StatusReport deserialize(String jsonString) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonString);
return deserialize(jsonObject);
}
}

Просмотреть файл

@ -7,6 +7,7 @@
#import "InstallOptions.h"
#import "InstallMode.h"
#import "CodePushReportingManager.h"
#import "StatusReport.h"
#import "UpdateHashUtils.h"
@implementation CodePush
@ -14,7 +15,7 @@
bool didUpdate = false;
bool pendingInstall = false;
NSDate* lastResignedDate;
const NSString* DeploymentKeyPreference = @"codepushdeploymentkey";
NSString* const DeploymentKeyPreference = @"codepushdeploymentkey";
- (void)getBinaryHash:(CDVInvokedUrlCommand *)command {
CDVPluginResult* pluginResult = nil;
@ -42,7 +43,8 @@ const NSString* DeploymentKeyPreference = @"codepushdeploymentkey";
if ([CodePushPackageManager installNeedsConfirmation]) {
/* save reporting status */
CodePushPackageMetadata* currentMetadata = [CodePushPackageManager getCurrentPackageMetadata];
[CodePushReportingManager reportStatus:UPDATE_ROLLED_BACK withLabel:currentMetadata.label version:currentMetadata.appVersion deploymentKey:currentMetadata.deploymentKey webView:self.webView];
StatusReport* statusReport = [[StatusReport alloc] initWithStatus:UPDATE_ROLLED_BACK andLabel:currentMetadata.label andAppVersion:currentMetadata.appVersion andDeploymentKey:currentMetadata.deploymentKey];
[CodePushReportingManager reportStatus:statusReport withWebView:self.webView];
[CodePushPackageManager clearInstallNeedsConfirmation];
[CodePushPackageManager revertToPreviousVersion];
@ -60,15 +62,17 @@ const NSString* DeploymentKeyPreference = @"codepushdeploymentkey";
- (void)updateSuccess:(CDVInvokedUrlCommand *)command {
if ([CodePushPackageManager isFirstRun]) {
[CodePushPackageManager markFirstRunFlag];
NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString *deploymentKey = ((CDVViewController *)self.viewController).settings[DeploymentKeyPreference];
[CodePushReportingManager reportStatus:STORE_VERSION withLabel:nil version:appVersion deploymentKey:deploymentKey webView:self.webView];
}
if ([CodePushPackageManager installNeedsConfirmation]) {
NSString* appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString* deploymentKey = ((CDVViewController *)self.viewController).settings[DeploymentKeyPreference];
StatusReport* statusReport = [[StatusReport alloc] initWithStatus:STORE_VERSION andLabel:nil andAppVersion:appVersion andDeploymentKey:deploymentKey];
[CodePushReportingManager reportStatus:statusReport withWebView:self.webView];
} else if ([CodePushPackageManager installNeedsConfirmation]) {
/* save reporting status */
CodePushPackageMetadata* currentMetadata = [CodePushPackageManager getCurrentPackageMetadata];
[CodePushReportingManager reportStatus:UPDATE_CONFIRMED withLabel:currentMetadata.label version:currentMetadata.appVersion deploymentKey:currentMetadata.deploymentKey webView:self.webView];
StatusReport* statusReport = [[StatusReport alloc] initWithStatus:UPDATE_CONFIRMED andLabel:currentMetadata.label andAppVersion:currentMetadata.appVersion andDeploymentKey:currentMetadata.deploymentKey];
[CodePushReportingManager reportStatus:statusReport withWebView:self.webView];
} else if ([CodePushReportingManager hasFailedReport]) {
[CodePushReportingManager reportStatus:[CodePushReportingManager getAndClearFailedReport] withWebView:self.webView];
}
[CodePushPackageManager clearInstallNeedsConfirmation];
@ -112,6 +116,20 @@ const NSString* DeploymentKeyPreference = @"codepushdeploymentkey";
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
- (void)reportFailed:(CDVInvokedUrlCommand *)command {
NSDictionary* statusReportDict = [command argumentAtIndex:0 withDefault:nil andClass:[NSDictionary class]];
if (statusReportDict) {
[CodePushReportingManager saveFailedReport:[[StatusReport alloc] initWithDictionary:statusReportDict]];
}
}
- (void)reportSucceeded:(CDVInvokedUrlCommand *)command {
NSDictionary* statusReportDict = [command argumentAtIndex:0 withDefault:nil andClass:[NSDictionary class]];
if (statusReportDict) {
[CodePushReportingManager saveSuccessfulReport:[[StatusReport alloc] initWithDictionary:statusReportDict]];
}
}
- (void)restartApplication:(CDVInvokedUrlCommand *)command {
/* Callback before navigating */
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
@ -164,7 +182,6 @@ const NSString* DeploymentKeyPreference = @"codepushdeploymentkey";
[self sendResultForPreference:DeploymentKeyPreference command:command];
}
- (void)getNativeBuildTime:(CDVInvokedUrlCommand *)command {
NSString* timeStamp = [Utilities getApplicationTimestamp];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:timeStamp];
@ -208,9 +225,10 @@ const NSString* DeploymentKeyPreference = @"codepushdeploymentkey";
[CodePushPackageManager clearFailedUpdates];
[CodePushPackageManager clearPendingInstall];
[CodePushPackageManager clearInstallNeedsConfirmation];
NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString *deploymentKey = ((CDVViewController *)self.viewController).settings[DeploymentKeyPreference];
[CodePushReportingManager reportStatus:STORE_VERSION withLabel:nil version:appVersion deploymentKey:deploymentKey webView:self.webView];
NSString* appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString* deploymentKey = ((CDVViewController *)self.viewController).settings[DeploymentKeyPreference];
StatusReport* statusReport = [[StatusReport alloc] initWithStatus:STORE_VERSION andLabel:nil andAppVersion:appVersion andDeploymentKey:deploymentKey];
[CodePushReportingManager reportStatus:statusReport withWebView:self.webView];
}
}
}
@ -246,6 +264,8 @@ const NSString* DeploymentKeyPreference = @"codepushdeploymentkey";
[CodePushPackageManager clearPendingInstall];
}
}
} else if ([CodePushReportingManager hasFailedReport]) {
[CodePushReportingManager reportStatus:[CodePushReportingManager getAndClearFailedReport] withWebView:self.webView];
}
}

Просмотреть файл

@ -1,11 +1,12 @@
enum {
STORE_VERSION = 0,
UPDATE_CONFIRMED = 1,
UPDATE_ROLLED_BACK = 2
};
typedef NSInteger ReportingStatus;
#import "StatusReport.h"
@interface CodePushReportingManager : NSObject
+ (void)reportStatus:(ReportingStatus)status withLabel:(NSString*)label version:(NSString*)version deploymentKey:(NSString*)deploymentKey webView:(UIView*)webView;
@end
+ (void)reportStatus:(StatusReport*)statusReport withWebView:(UIView*)webView;
+ (BOOL)hasFailedReport;
+ (StatusReport*)getFailedReport;
+ (StatusReport*)getAndClearFailedReport;
+ (void)saveFailedReport:(StatusReport*)statusReport;
+ (void)saveSuccessfulReport:(StatusReport*)statusReport;
@end

Просмотреть файл

@ -1,43 +1,42 @@
#import "CodePushReportingManager.h"
#import "StatusReport.h"
@implementation CodePushReportingManager
const NSString* LastVersionPreference = @"CODE_PUSH_LAST_VERSION";
const NSString* LastVersionDeploymentKeyKey = @"LAST_VERSION_DEPLOYMENT_KEY_KEY";
const NSString* LastVersionLabelOrAppVersionKey = @"LAST_VERSION_LABEL_OR_APP_VERSION_KEY";
int HasFailedReport = -1; // -1 = unset, 0 = false, 1 = true
+ (void)reportStatus:(ReportingStatus)status withLabel:(NSString*)label version:(NSString*)version deploymentKey:(NSString*)deploymentKey webView:(UIView*)webView {
NSString* const FailedStatusReportKey = @"CODE_PUSH_FAILED_STATUS_REPORT_KEY";
NSString* const LastVersionPreference = @"CODE_PUSH_LAST_VERSION";
NSString* const LastVersionPreferenceDeploymentKeyKey = @"LAST_VERSION_DEPLOYMENT_KEY_KEY";
NSString* const LastVersionPreferenceLabelOrAppVersionKey = @"LAST_VERSION_LABEL_OR_APP_VERSION_KEY";
+ (void)reportStatus:(StatusReport*)statusReport withWebView:(UIView*)webView {
@synchronized(self) {
if (!deploymentKey) {
if (!statusReport.deploymentKey) {
return;
}
NSString* labelParameter = [CodePushReportingManager convertStringParameter:label];
NSString* appVersionParameter = [CodePushReportingManager convertStringParameter:version];
NSString* deploymentKeyParameter = [CodePushReportingManager convertStringParameter:deploymentKey];
NSString* lastVersionLabelOrAppVersionParameter = nil;
NSString* lastVersionDeploymentKeyParameter = nil;
NSUserDefaults* preferences = [NSUserDefaults standardUserDefaults];
NSDictionary* lastVersion = [preferences objectForKey:LastVersionPreference];
if (lastVersion) {
lastVersionLabelOrAppVersionParameter = [CodePushReportingManager convertStringParameter:[lastVersion objectForKey:LastVersionLabelOrAppVersionKey]];
lastVersionDeploymentKeyParameter = [CodePushReportingManager convertStringParameter:[lastVersion objectForKey:LastVersionDeploymentKeyKey]];
NSString* labelParameter = [CodePushReportingManager convertStringParameter:statusReport.label];
NSString* appVersionParameter = [CodePushReportingManager convertStringParameter:statusReport.appVersion];
NSString* deploymentKeyParameter = [CodePushReportingManager convertStringParameter:statusReport.deploymentKey];
NSString* lastVersionLabelOrAppVersionParameter = statusReport.lastVersionLabelOrAppVersion;
NSString* lastVersionDeploymentKeyParameter = statusReport.lastVersionDeploymentKey;
if (!lastVersionLabelOrAppVersionParameter || !lastVersionDeploymentKeyParameter) {
NSUserDefaults* preferences = [NSUserDefaults standardUserDefaults];
NSDictionary* lastVersion = [preferences objectForKey:LastVersionPreference];
if (lastVersion) {
lastVersionLabelOrAppVersionParameter = [CodePushReportingManager convertStringParameter:[lastVersion objectForKey:LastVersionPreferenceLabelOrAppVersionKey]];
lastVersionDeploymentKeyParameter = [CodePushReportingManager convertStringParameter:[lastVersion objectForKey:LastVersionPreferenceDeploymentKeyKey]];
}
}
/* JS function to call: window.codePush.reportStatus(status: number, label: String, appVersion: String, deploymentKey: String) */
NSString* script = [NSString stringWithFormat:@"document.addEventListener(\"deviceready\", function () { window.codePush.reportStatus(%i, %@, %@, %@, %@, %@); });", (int)status, labelParameter, appVersionParameter, deploymentKeyParameter, lastVersionLabelOrAppVersionParameter, lastVersionDeploymentKeyParameter];
NSString* script = [NSString stringWithFormat:@"document.addEventListener(\"deviceready\", function () { window.codePush.reportStatus(%i, %@, %@, %@, %@, %@); });", (int)statusReport.status, labelParameter, appVersionParameter, deploymentKeyParameter, lastVersionLabelOrAppVersionParameter, lastVersionDeploymentKeyParameter];
if ([webView respondsToSelector:@selector(evaluateJavaScript:completionHandler:)]) {
[webView performSelector:@selector(evaluateJavaScript:completionHandler:) withObject:script withObject: NULL];
} else if ([webView isKindOfClass:[UIWebView class]]) {
[(UIWebView*)webView stringByEvaluatingJavaScriptFromString:script];
}
if (status == STORE_VERSION || status == UPDATE_CONFIRMED) {
NSDictionary* newLastVersion = @{LastVersionLabelOrAppVersionKey:(label ? label : version), LastVersionDeploymentKeyKey:deploymentKey};
[preferences setObject:newLastVersion forKey:LastVersionPreference];
[preferences synchronize];
}
}
}
@ -49,6 +48,58 @@ const NSString* LastVersionLabelOrAppVersionKey = @"LAST_VERSION_LABEL_OR_APP_VE
}
}
+ (BOOL)hasFailedReport {
if (HasFailedReport == -1) {
HasFailedReport = [self getFailedReport] != nil;
}
return HasFailedReport;
}
+ (StatusReport*)getFailedReport {
NSUserDefaults* preferences = [NSUserDefaults standardUserDefaults];
NSDictionary* failedReportDict = [preferences objectForKey:FailedStatusReportKey];
if (!failedReportDict) {
return nil;
}
return [[StatusReport alloc] initWithDictionary:failedReportDict];
}
+ (StatusReport*)getAndClearFailedReport {
StatusReport* failedReport = [self getFailedReport];
[self clearFailedReport];
HasFailedReport = 0;
return failedReport;
}
+ (void)clearFailedReport {
NSUserDefaults* preferences = [NSUserDefaults standardUserDefaults];
[preferences removeObjectForKey:FailedStatusReportKey];
[preferences synchronize];
}
+ (void)saveFailedReport:(StatusReport*)statusReport {
NSUserDefaults* preferences = [NSUserDefaults standardUserDefaults];
[preferences setObject:[statusReport toDictionary] forKey:FailedStatusReportKey];
[preferences synchronize];
HasFailedReport = 1;
}
+ (void)saveSuccessfulReport:(StatusReport*)statusReport {
if (statusReport.status == STORE_VERSION || statusReport.status == UPDATE_CONFIRMED) {
NSDictionary* newLastVersion = @{
LastVersionPreferenceLabelOrAppVersionKey:(statusReport.label ? statusReport.label : statusReport.appVersion),
LastVersionPreferenceDeploymentKeyKey:statusReport.deploymentKey
};
NSUserDefaults* preferences = [NSUserDefaults standardUserDefaults];
[preferences setObject:newLastVersion forKey:LastVersionPreference];
[preferences synchronize];
[self clearFailedReport];
HasFailedReport = 0;
}
}
@end

Просмотреть файл

@ -1,4 +1,4 @@
#include "InstallMode.h"
#import "InstallMode.h"
@interface InstallOptions : NSObject

Просмотреть файл

@ -1,4 +1,4 @@
#include "InstallOptions.h"
#import "InstallOptions.h"
@implementation InstallOptions

25
src/ios/StatusReport.h Normal file
Просмотреть файл

@ -0,0 +1,25 @@
enum {
STORE_VERSION = 0,
UPDATE_CONFIRMED = 1,
UPDATE_ROLLED_BACK = 2
};
typedef NSInteger ReportingStatus;
@interface StatusReport : NSObject
@property ReportingStatus status;
@property NSString* label;
@property NSString* appVersion;
@property NSString* deploymentKey;
@property NSString* lastVersionLabelOrAppVersion;
@property NSString* lastVersionDeploymentKey;
- (id)initWithStatus:(ReportingStatus)status andLabel:(NSString*)label andAppVersion:(NSString*)appVersion andDeploymentKey:(NSString*)deploymentKey;
- (id)initWithStatus:(ReportingStatus)status andLabel:(NSString*)label andAppVersion:(NSString*)appVersion andDeploymentKey:(NSString*)deploymentKey andLastVersionLabelOrAppVersion:(NSString*)lastVersionLabelOrAppVersion andLastVersionDeploymentKey:(NSString*)lastVersionDeploymentKey;
- (id)initWithDictionary:(NSDictionary*)dict;
- (NSDictionary*)toDictionary;
@end

46
src/ios/StatusReport.m Normal file
Просмотреть файл

@ -0,0 +1,46 @@
#import "StatusReport.h"
@implementation StatusReport
const NSString* StatusKey = @"status";
const NSString* LabelKey = @"label";
const NSString* AppVersionKey = @"appVersion";
const NSString* DeploymentKeyKey = @"deploymentKey";
const NSString* LastVersionLabelOrAppVersionKey = @"lastVersionLabelOrAppVersion";
const NSString* LastVersionDeploymentKeyKey = @"lastVersionDeploymentKey";
- (id)initWithStatus:(ReportingStatus)status andLabel:(NSString*)label andAppVersion:(NSString*)appVersion andDeploymentKey:(NSString*)deploymentKey {
return [self initWithStatus:status andLabel:label andAppVersion:appVersion andDeploymentKey:deploymentKey andLastVersionLabelOrAppVersion:nil andLastVersionDeploymentKey:nil];
}
- (id)initWithStatus:(ReportingStatus)status andLabel:(NSString*)label andAppVersion:(NSString*)appVersion andDeploymentKey:(NSString*)deploymentKey andLastVersionLabelOrAppVersion:(NSString*)lastVersionLabelOrAppVersion andLastVersionDeploymentKey:(NSString*)lastVersionDeploymentKey {
self = [super init];
if (self) {
_status = status;
_label = label;
_appVersion = appVersion;
_deploymentKey = deploymentKey;
_lastVersionLabelOrAppVersion = lastVersionLabelOrAppVersion;
_lastVersionDeploymentKey = lastVersionDeploymentKey;
}
return self;
}
- (id)initWithDictionary:(NSDictionary*)dict {
return [self initWithStatus:[dict[StatusKey] longValue] andLabel:dict[LabelKey] andAppVersion:dict[AppVersionKey] andDeploymentKey:dict[DeploymentKeyKey] andLastVersionLabelOrAppVersion:dict[LastVersionLabelOrAppVersionKey] andLastVersionDeploymentKey:dict[LastVersionDeploymentKeyKey]];
}
- (NSDictionary*)toDictionary {
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
dict[StatusKey] = @(_status);
if (_label) dict[LabelKey] = _label;
if (_appVersion) dict[AppVersionKey] = _appVersion;
if (_deploymentKey) dict[DeploymentKeyKey] = _deploymentKey;
if (_lastVersionLabelOrAppVersion) dict[LastVersionLabelOrAppVersionKey] = _lastVersionLabelOrAppVersion;
if (_lastVersionDeploymentKey) dict[LastVersionDeploymentKeyKey] = _lastVersionDeploymentKey;
return dict;
}
@end

2
typings/cordova.d.ts поставляемый
Просмотреть файл

@ -14,7 +14,7 @@ interface Cordova {
* @param action The action name to call on the native side (generally corresponds to the native class method).
* @param args An array of arguments to pass into the native environment.
*/
exec(success: () => any, fail: () => any, service: string, action: string, args?: string[]): void;
exec(success: () => any, fail: () => any, service: string, action: string, args?: any[]): void;
/** Gets the operating system name. */
platformId: string;
/** Gets Cordova framework version */

Просмотреть файл

@ -62,32 +62,47 @@ class CodePush implements CodePushCordovaPlugin {
* Reports an application status back to the server.
* !!! This function is called from the native side, please make changes accordingly. !!!
*/
public reportStatus(status: number, label: string, appVersion: string, currentDeploymentKey: string, previousLabelOrAppVersion?: string, previousDeploymentKey?: string) {
try {
var createPackageForReporting = (label: string, appVersion: string): IPackage => {
return {
/* The SDK only reports the label and appVersion.
The rest of the properties are added for type safety. */
label: label, appVersion: appVersion,
deploymentKey: currentDeploymentKey, description: null,
isMandatory: false, packageHash: null,
packageSize: null, failedInstall: false
};
public reportStatus(status: number, label: string, appVersion: string, deploymentKey: string, previousLabelOrAppVersion?: string, previousDeploymentKey?: string) {
var createPackageForReporting = (label: string, appVersion: string): IPackage => {
return {
/* The SDK only reports the label and appVersion.
The rest of the properties are added for type safety. */
label, appVersion, deploymentKey,
description: null, isMandatory: false,
packageHash: null, packageSize: null,
failedInstall: false
};
};
var reportDone = (error: Error) => {
var reportArgs = {
status,
label,
appVersion,
deploymentKey,
previousLabelOrAppVersion,
previousDeploymentKey
};
switch (status) {
case ReportStatus.STORE_VERSION:
Sdk.reportStatusDeploy(null, AcquisitionStatus.DeploymentSucceeded, currentDeploymentKey, previousLabelOrAppVersion, previousDeploymentKey);
break;
case ReportStatus.UPDATE_CONFIRMED:
Sdk.reportStatusDeploy(createPackageForReporting(label, appVersion), AcquisitionStatus.DeploymentSucceeded, currentDeploymentKey, previousLabelOrAppVersion, previousDeploymentKey);
break;
case ReportStatus.UPDATE_ROLLED_BACK:
Sdk.reportStatusDeploy(createPackageForReporting(label, appVersion), AcquisitionStatus.DeploymentFailed, currentDeploymentKey, previousLabelOrAppVersion, previousDeploymentKey);
break;
if (error) {
CodePushUtil.logError(`An error occurred while reporting status: ${JSON.stringify(reportArgs)}`, error);
cordova.exec(null, null, "CodePush", "reportFailed", [reportArgs]);
} else {
CodePushUtil.logMessage(`Reported status: ${JSON.stringify(reportArgs)}`);
cordova.exec(null, null, "CodePush", "reportSucceeded", [reportArgs]);
}
} catch (e) {
CodePushUtil.logError("An error occurred while reporting." + CodePushUtil.getErrorMessage(e));
};
switch (status) {
case ReportStatus.STORE_VERSION:
Sdk.reportStatusDeploy(null, AcquisitionStatus.DeploymentSucceeded, deploymentKey, previousLabelOrAppVersion, previousDeploymentKey, reportDone);
break;
case ReportStatus.UPDATE_CONFIRMED:
Sdk.reportStatusDeploy(createPackageForReporting(label, appVersion), AcquisitionStatus.DeploymentSucceeded, deploymentKey, previousLabelOrAppVersion, previousDeploymentKey, reportDone);
break;
case ReportStatus.UPDATE_ROLLED_BACK:
Sdk.reportStatusDeploy(createPackageForReporting(label, appVersion), AcquisitionStatus.DeploymentFailed, deploymentKey, previousLabelOrAppVersion, previousDeploymentKey, reportDone);
break;
}
}
@ -420,7 +435,6 @@ class CodePush implements CodePushCordovaPlugin {
return CodePush.DefaultUpdateDialogOptions;
}
}
/**

Просмотреть файл

@ -77,12 +77,11 @@ class Sdk {
callback && callback(error, null);
}
else {
console.log(`Reporting status: ${status} label: ${pkg && pkg.label} appVersion: ${Sdk.DefaultConfiguration.appVersion} previousLabelOrAppVersion: ${previousLabelOrAppVersion} previousDeploymentKey:${previousDeploymentKey}`);
acquisitionManager.reportStatusDeploy(pkg, status, previousLabelOrAppVersion, previousDeploymentKey, callback);
}
}, currentDeploymentKey, "application/json");
} catch (e) {
callback && callback(new Error("An error occured while reporting the deployment status. " + e), null);
callback && callback(e, null);
}
}