@appzung/react-native-code-push
Version:
React Native plugin for the CodePush service
226 lines (219 loc) • 11.3 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.sync = exports.DEFAULT_UPDATE_DIALOG = void 0;
var _reactNative = require("react-native");
var _checkForUpdates = require("./checkForUpdates.js");
var _InstallModeEnum = require("./enums/InstallMode.enum.js");
var _LogLevelEnum = require("./enums/LogLevel.enum.js");
var _SyncStatusEnum = require("./enums/SyncStatus.enum.js");
var _getCurrentPackage = require("./internals/getCurrentPackage.js");
var _shouldUpdateBeIgnored = require("./internals/shouldUpdateBeIgnored.js");
var _log = require("./internals/utils/log.js");
var _notifyAppReady = require("./notifyAppReady.js");
/**
* Represents the default settings that will be used by the sync method if
* an update dialog is configured to be displayed.
*/
const DEFAULT_UPDATE_DIALOG = exports.DEFAULT_UPDATE_DIALOG = {
appendReleaseDescription: false,
descriptionPrefix: ' Description: ',
mandatoryContinueButtonLabel: 'Continue',
mandatoryUpdateMessage: 'An update is available that must be installed.',
optionalIgnoreButtonLabel: 'Ignore',
optionalInstallButtonLabel: 'Install',
optionalUpdateMessage: 'An update is available. Would you like to install it?',
title: 'Update available'
};
/*
* The syncInternal method provides a simple, one-line experience for
* incorporating the check, download and installation of an update.
*
* It simply composes the existing API methods together and adds additional
* support for respecting mandatory updates, ignoring previously failed
* releases, and displaying a standard confirmation UI to the end-user
* when an update is available.
*/
async function syncInternal(options, syncStatusChangeCallback, downloadProgressCallback, handleBinaryVersionMismatchCallback) {
let resolvedInstallMode;
const syncOptions = {
releaseChannelPublicId: undefined,
ignoreFailedUpdates: true,
rollbackRetryOptions: undefined,
installMode: _InstallModeEnum.InstallMode.ON_NEXT_RESTART,
mandatoryInstallMode: _InstallModeEnum.InstallMode.IMMEDIATE,
minimumBackgroundDuration: 0,
updateDialog: undefined,
...options
};
syncStatusChangeCallback = typeof syncStatusChangeCallback === 'function' ? syncStatusChangeCallback : syncStatus => {
switch (syncStatus) {
case _SyncStatusEnum.SyncStatus.CHECKING_FOR_UPDATE:
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Checking for update.');
break;
case _SyncStatusEnum.SyncStatus.AWAITING_USER_ACTION:
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Awaiting user action.');
break;
case _SyncStatusEnum.SyncStatus.DOWNLOADING_PACKAGE:
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Downloading package.');
break;
case _SyncStatusEnum.SyncStatus.INSTALLING_UPDATE:
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Installing update.');
break;
case _SyncStatusEnum.SyncStatus.UP_TO_DATE:
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'App is up to date.');
break;
case _SyncStatusEnum.SyncStatus.UPDATE_IGNORED:
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'User cancelled the update.');
break;
case _SyncStatusEnum.SyncStatus.UPDATE_INSTALLED:
if (resolvedInstallMode === _InstallModeEnum.InstallMode.ON_NEXT_RESTART) {
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Update is installed and will be run on the next app restart.');
} else if (resolvedInstallMode === _InstallModeEnum.InstallMode.ON_NEXT_RESUME) {
if (syncOptions.minimumBackgroundDuration) {
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, `Update is installed and will be run after the app has been in the background for at least ${syncOptions.minimumBackgroundDuration} seconds.`);
} else {
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Update is installed and will be run when the app next resumes.');
}
}
break;
case _SyncStatusEnum.SyncStatus.UNKNOWN_ERROR:
(0, _log.log)(_LogLevelEnum.LogLevel.ERROR, 'An unknown error occurred.');
break;
}
};
try {
await (0, _notifyAppReady.notifyAppReady)();
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.CHECKING_FOR_UPDATE);
const remotePackage = await (0, _checkForUpdates.checkForUpdate)(syncOptions.releaseChannelPublicId, handleBinaryVersionMismatchCallback);
const doDownloadAndInstall = async () => {
if (!remotePackage) {
throw new Error('remotePackage should be defined');
}
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.DOWNLOADING_PACKAGE);
const localPackage = await remotePackage.download(downloadProgressCallback);
// Determine the correct install mode based on whether the update is mandatory or not.
resolvedInstallMode = localPackage.isMandatory ? syncOptions.mandatoryInstallMode : syncOptions.installMode;
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.INSTALLING_UPDATE);
await localPackage.install(resolvedInstallMode, syncOptions.minimumBackgroundDuration, () => {
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UPDATE_INSTALLED);
});
return _SyncStatusEnum.SyncStatus.UPDATE_INSTALLED;
};
const updateShouldBeIgnored = await (0, _shouldUpdateBeIgnored.shouldUpdateBeIgnored)(remotePackage, syncOptions);
if (!remotePackage || updateShouldBeIgnored) {
if (updateShouldBeIgnored) {
(0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'An update is available, but it is being ignored due to having been previously rolled back.');
}
const currentPackage = await (0, _getCurrentPackage.getCurrentPackage)();
if (currentPackage && currentPackage.isPending) {
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UPDATE_INSTALLED);
return _SyncStatusEnum.SyncStatus.UPDATE_INSTALLED;
} else {
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UP_TO_DATE);
return _SyncStatusEnum.SyncStatus.UP_TO_DATE;
}
} else if (syncOptions.updateDialog) {
const updateDialogConfig = typeof syncOptions.updateDialog !== 'object' ? DEFAULT_UPDATE_DIALOG : {
...DEFAULT_UPDATE_DIALOG,
...syncOptions.updateDialog
};
return await new Promise((resolve, reject) => {
let message;
let installButtonText;
const dialogButtons = [];
if (remotePackage.isMandatory) {
message = updateDialogConfig.mandatoryUpdateMessage;
installButtonText = updateDialogConfig.mandatoryContinueButtonLabel;
} else {
message = updateDialogConfig.optionalUpdateMessage;
installButtonText = updateDialogConfig.optionalInstallButtonLabel;
// Since this is an optional update, add a button
// to allow the end-user to ignore it
dialogButtons.push({
text: updateDialogConfig.optionalIgnoreButtonLabel ?? '',
onPress: () => {
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UPDATE_IGNORED);
resolve(_SyncStatusEnum.SyncStatus.UPDATE_IGNORED);
}
});
}
// Since the install button should be placed to the
// right of any other button, add it last
dialogButtons.push({
text: installButtonText ?? '',
onPress: () => {
doDownloadAndInstall().then(resolve, reject);
}
});
// If the update has a description, and the developer
// explicitly chose to display it, then set that as the message
if (updateDialogConfig.appendReleaseDescription && remotePackage.description) {
message += `${updateDialogConfig.descriptionPrefix} ${remotePackage.description}`;
}
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.AWAITING_USER_ACTION);
_reactNative.Alert.alert(updateDialogConfig.title || '', message || '', _reactNative.Platform.OS === 'android' ? [...dialogButtons.reverse()] : dialogButtons);
});
} else {
return await doDownloadAndInstall();
}
} catch (error) {
syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UNKNOWN_ERROR);
(0, _log.log)(_LogLevelEnum.LogLevel.ERROR, error != null && typeof error === 'object' && 'message' in error && typeof error.message === 'string' ? error.message : 'Unknown');
throw error;
}
}
/**
* @function
*
* Allows checking for an update, downloading it and installing it, all with a single call.
*
* Unless you need custom UI and/or behavior, we recommend most developers to use this method when integrating CodePush into their apps, if they are not using the `withCodePush` HOC.
*
* @param options Options used to configure the end-user update experience (e.g. show a prompt?, install the update immediately?).
* @param syncStatusChangedCallback An optional callback that allows tracking the status of the sync operation, as opposed to simply checking the resolved state via the returned Promise.
* @param downloadProgressCallback An optional callback that allows tracking the progress of an update while it is being downloaded.
* @param handleBinaryVersionMismatchCallback An optional callback for handling target binary version mismatch
*/
const sync = exports.sync = (() => {
// This function allows only one syncInternal operation to proceed at any given time.
// Parallel calls to sync() while one is ongoing yields CodePush.SyncStatus.SYNC_IN_PROGRESS.
let syncInProgress = false;
const setSyncCompleted = () => {
syncInProgress = false;
};
return (options, syncStatusChangedCallback, downloadProgressCallback, handleBinaryVersionMismatchCallback) => {
(0, _log.log)(_LogLevelEnum.LogLevel.DEBUG, `sync start`);
let syncStatusCallbackWithTryCatch = status => {
(0, _log.log)(_LogLevelEnum.LogLevel.DEBUG, `sync status ${_SyncStatusEnum.SyncStatus[status]}`);
if (typeof syncStatusChangedCallback !== 'function') {
return;
}
try {
syncStatusChangedCallback(status);
} catch (error) {
(0, _log.log)(_LogLevelEnum.LogLevel.ERROR, `An error has occurred : ${error instanceof Error ? error.stack : 'unknown'}`);
}
};
let downloadProgressCallbackWithTryCatch;
if (typeof downloadProgressCallback === 'function') {
downloadProgressCallbackWithTryCatch = (...args) => {
try {
downloadProgressCallback(...args);
} catch (error) {
(0, _log.log)(_LogLevelEnum.LogLevel.ERROR, `An error has occurred: ${error instanceof Error ? error.stack : 'unknown'}`);
}
};
}
if (syncInProgress) {
typeof syncStatusCallbackWithTryCatch === 'function' ? syncStatusCallbackWithTryCatch(_SyncStatusEnum.SyncStatus.SYNC_IN_PROGRESS) : (0, _log.log)(_LogLevelEnum.LogLevel.WARN, 'Sync already in progress.');
return Promise.resolve(_SyncStatusEnum.SyncStatus.SYNC_IN_PROGRESS);
}
syncInProgress = true;
const syncPromise = syncInternal(options, syncStatusCallbackWithTryCatch, downloadProgressCallbackWithTryCatch, handleBinaryVersionMismatchCallback);
syncPromise.then(setSyncCompleted).catch(setSyncCompleted);
return syncPromise;
};
})();
//# sourceMappingURL=sync.js.map
;