-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Handle TargetBinaryVersionMismatch #888
Conversation
This seems like a small (but important) contribution, so no Contribution License Agreement is required at this point. We will now review your pull request. |
Hi @akki-ng, thanks for reaching us! checkForUpate() {
CodePush.checkForUpdate()
.then((update) => console.log(update));
} |
Hi @sergey-akhalkov, checkForUpdate will essentially do the same if the binary version of the update did not mismatch with the version of installed app. Below is the part of existing code of checkForUpdate function if (!update || update.updateAppVersion ||
localPackage && (update.packageHash === localPackage.packageHash) ||
(!localPackage || localPackage._isDebugOnly) && config.packageHash === update.packageHash) {
if (update && update.updateAppVersion) {
log("An update is available but it is not targeting the binary version of your app.");
}
return null;
} else {
const remotePackage = { ...update, ...PackageMixins.remote(sdk.reportStatusDownload) };
remotePackage.failedInstall = await NativeCodePush.isFailedUpdate(remotePackage.packageHash);
remotePackage.deploymentKey = deploymentKey || nativeConfig.deploymentKey;
return remotePackage;
} Lets consider a use-case, where current installed binary version is 1.0.1 with label(codepush label) v1. And native code has changed in the dev cycle and binary version is changed to 1.0.2 in build.gradle. And code-push update has been triggered. The above existing code ignores any binary version mismatch, thinking the update was not targeted to the binary version of currently installed app. In our example, installed app(1.0.1) will ignore the update of 1.0.2. As codepush forces these updates to happen from respective store as native codes can not be pushed as an update via codepush. But with the fix we can provide a hook to handle such cases. And the code-push client in the app using decorator pattern App = codePush(codePushOptions)(ReactCustomUpdateComponent) Decorator pattern supports 2 function definition(existing) The api "codePushOnBinaryVersionMismatch" will provide a viable option for users to handle such updates in their own way (enterprise internal application) to download the latest "APK" file from hosted store(AWS S3). By this way new apk's can be distributed without going through the channel of PlayStore in some cases, for other cases PlayStore App can be opened up with the option to install the current app's latest binary. Below is the sample code which I wrote for our internal audience. let codePushOptions = { updateDialog: true, installMode: codePush.InstallMode.IMMEDIATE, checkFrequency: codePush.CheckFrequency.ON_APP_RESUME};
codePush.SyncStatus.DOWNLOADING_BIN_PACKAGE = -100
class App extends Component {
constructor(props) {
super(props)
this.state = {
codepushStatus: codePush.SyncStatus.CHECKING_FOR_UPDATE,
codepushStatusMessage: "Checking for updates",
progress: {
receivedBytes: 0,
totalBytes: 1
},
update: {
appVersion: // Current installed binary version
}
}
}
codePushStatusDidChange(status) {
var message = ""
switch(status) {
case codePush.SyncStatus.CHECKING_FOR_UPDATE:
console.log("Checking for updates");
message = "Checking for updates"
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
console.log("Downloading package.");
message = "Downloading package"
case codePush.SyncStatus.INSTALLING_UPDATE:
console.log("Installing update.");
message = "Installing update"
case codePush.SyncStatus.UP_TO_DATE:
console.log("Up-to-date.");
message = "Up-to-date"
case codePush.SyncStatus.UPDATE_INSTALLED:
console.log("Update installed.");
message = "Update installed"
}
if(this.state.codepushStatus != codePush.SyncStatus.DOWNLOADING_BIN_PACKAGE) {
this.setState({codepushStatus: status, codepushStatusMessage: message})
}
}
codePushDownloadDidProgress(progress) {
this.setState({codepushStatusMessage: "Downloading updates", progress: progress})
}
codePushOnBinaryVersionMismatch(update) {
if(update && update.updateAppVersion) {
alert("You are running on version " + Config.VERSION_NAME + "\nApp has been updated to " + update.appVersion + " \nDownload latest APP and install")
this.setState({codepushStatus: codePush.SyncStatus.DOWNLOADING_BIN_PACKAGE, codepushStatusMessage: "Download newer version of your " + Config.BUILD_NAME + " app", update: update})
}
}
renderDownloadBin() {
if("<Url to get the APK from AWS S3> is defined") {
return(
<TouchableOpacity style={{backgroundColor: "#0fb14a", padding: 10, marginTop: 20}} onPress={() => Linking.openURL("<Url to get the APK from AWS S3>")}>
<View>
<Text style={{textAlign:'center',
fontSize:14,
color:"#ffffff",
fontFamily: "Roboto-Medium"}}>Download Now</Text>
</View>
</TouchableOpacity>
)
}else {
return (
<View>
<Text style={{textAlign:'center',
fontSize:14,
color:"#ffffff",
fontFamily: "Roboto-Medium"}}>Please download the latest APK</Text>
</View>
)
}
}
render() {
if(((this.state.codepushStatus == codePush.SyncStatus.DOWNLOADING_BIN_PACKAGE) && this.state.update)) {
console.log(this.state.update)
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Installed Version: {Config.VERSION_NAME}</Text>
<Text>New Version: {this.state.update.appVersion}</Text>
{this.renderDownloadBin()}
</View>
)
}else {
return (
<Provider store={store}>
<AppContainer />
</Provider>
)
}
}
}
if(Config.CODE_PUSH_ENABLE) {
App = codePush(codePushOptions)(App);
} We could handle the changes in native code by forcing users to download the new apk by clicking "Download Now" button. It is convenient for end users as well because there is no need of sharing the link of updated binary and notifying users on a different channel about binary updates. |
@akki-ng, got it, thanks for the clarification! Everything looks good and I'm going to merge it, but before doing it we also need to update
Issue sample is here https://stackoverflow.com/questions/37310731/apple-rejected-app-because-i-am-forcing-users-to-update-their-app-version At least we should mention about review process and this issue for iOS developers - that should help them to avoid such kind of problems in the future. What do you think? |
@sergey-akhalkov Yeah, You are absolutely right. We must update the |
Hi @akki-ng,
I don't think so, this PR just provides an ability for developers to handle binary version mismatch. A developer will decide to use this or not. Also CodePush already has |
sergey-akhalkov any idea about the timelines, when can we merge this PR? |
Hi @akki-ng, we are going to make a release this week and we could include your PR, but could you please do the following first:
Please let me know if you have any questions. |
@@ -8,7 +8,7 @@ import log from "./logging"; | |||
let NativeCodePush = require("react-native").NativeModules.CodePush; | |||
const PackageMixins = require("./package-mixins")(NativeCodePush); | |||
|
|||
async function checkForUpdate(deploymentKey = null) { | |||
async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatch = null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update readme and typings in order to mention about new handleBinaryVersionMismatch
feature and checkForUpdate
method signature changes
Hey @akki-ng, first of all thank you for your contribution to the project, we appreciate it! |
Hey @max-mironov, |
@max-mironov I am seeing that PR #920 is already signed. But in this case how can I get the recognition for my contribution. Because my contribution takes a significant space in PR #920 . |
@akki-ng Yep but I thought that you have already signed it before (please correct me if Im wrong). If you have not signed it previously - could you please do it now. And sorry for confusion about this. |
@max-mironov Thanks for the update. I did not sign the CLA earlier as the label was CLA-Not-Required. But I appreciate your quick response. I have signed the CLA now and I got the signed PDF too. It will be really helpful if you guide me through further steps. Thanks. |
@akki-ng thanks for this. So after you have signed the CLA I believe no more further steps needed (if you have any issues with this please let us know). |
@max-mironov Thanks for the info. I'm fine with this as long as I get the credit for being the original contributor related to 'aa6e989' |
@akki-ng I think so as #920 is based on your commit |
@max-mironov In that case let's roll it out then! |
@akki-ng I'm hoping it will be included in the next |
@max-mironov @akki-ng |
@TrustTheBoy Please look at the comment It explains how to use this. The only prerequisite is the URL where you will host the latest APK. It should be straight-forward, let me know if you need more details. This feature is available since V4.1.1 - beta. |
@akki-ng sounds good, will try to manage this soon. |
@akki-ng @max-mironov Thanks very much for help, but I found that the >>> I have submitted a new question
CodePushUpdata = () => {
CodePush.sync({
updateDialog: {
appendReleaseDescription: true,
descriptionPrefix:'更新内容:\n',
title:'更新标题',
mandatoryUpdateMessage:'',
mandatoryContinueButtonLabel:'更新',
},
mandatoryInstallMode:CodePush.InstallMode.IMMEDIATE,
//deploymentKey: CODE_PUSH_PRODUCTION_KEY,
},
this.codePushStatusDidChange.bind(this),
(progress)=>{
this.codePushDownloadDidProgress.bind(this)
},
(binary)=> this.handleBinaryVersionMismatchCallback(binary)
);
} and CodePush.checkForUpdate()
.then((update) => {
if (!update) {
Toast.loading('The application is up to date!', 3, () => {
console.log('Load complete !!!');
});
} else {
CodePush.disallowRestart();
Modal.alert('message', `New updates available ${JSON.stringify(update)}`, [
{ text: 'cancel' /* onPress: () => this.goBack() */ },
{ text: 'install', onPress: () => CodePushUpdate() },
]);
}
})
.then((update) => {
Modal.alert('message', `There is a new version that can be used. Is it installed?${ update}`, [
{ text: 'cancel' },
{ text: 'install', onPress: () => Linking.openURL('http://xxx.xxx.xx.xx/path/android.apk') },
]);
})
.catch((error) => {
Toast.loading(`error?${error}`, 3, () => {
console.log('Load complete !!!');
});
}); |
Hi @TrustTheBoy, please take a look at the following:
So I believe your CodePush.sync(
{}, //options
this.codePushStatusDidChange.bind(this),
this.codePushDownloadDidProgress.bind(this),
this.codePushOnBinaryVersionMismatch.bind(this)
); |
@sergey-akhalkov I tried to use your method, or not, and the hook function failed to execute |
@TrustTheBoy let's continue discussion in #1023 issue please |
@akki-ng Can you see that I have failed to perform the replication?>> Demo << |
A handler function can be added for version upgrades.