Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Conversation

akki-ng
Copy link

@akki-ng akki-ng commented Jun 17, 2017

A handler function can be added for version upgrades.

codePushOnBinaryVersionMismatch(update) {
    console.log(VersionNumber.appVersion)
    console.log(update)
    if(update && update.updateAppVersion) {
      alert("You are running on version " + VersionNumber.appVersion + "\nApp has been updated to " + update.appVersion + " \nDownload latest APP and install")
      this.setState({codepushStatus: codePush.SyncStatus.DOWNLOADING_PACKAGE, codepushStatusMessage: "Downloading newer version of the app"})
    Linking.openURL(<Host link of app bin>)
    }
  }

It will be helpful in letting user know if there is any binary updates

@msftclas
Copy link

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.
Thanks,
Microsoft Pull Request Bot

@sergey-akhalkov
Copy link
Contributor

Hi @akki-ng, thanks for reaching us!
Could you please clarify what is codePushOnBinaryVersionMismatch method doing? If I get it right - it calls each time we call checkForUpdate. As of now this method looks like callback for checkForUpdate, instead of this we can use the following code:

checkForUpate() {
    CodePush.checkForUpdate()
        .then((update) => console.log(update));
}

@akki-ng
Copy link
Author

akki-ng commented Jun 20, 2017

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)
1. codePushDownloadDidProgress
2. codePushStatusDidChange
3. codePushOnBinaryVersionMismatch[Pull request]

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);
}

screen shot 2017-06-20 at 8 14 33 pm

screen shot 2017-06-20 at 8 22 40 pm

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.

@sergey-akhalkov
Copy link
Contributor

@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 readme due to App Store review process:

Apps must not force users to rate the app, review the app, download other apps, or other similar actions in order to access functionality, content, or use of the app.

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?

@akki-ng
Copy link
Author

akki-ng commented Jun 20, 2017

@sergey-akhalkov Yeah, You are absolutely right. We must update the readme to avoid such cases for iOS developers. As per codepush's concern I guess we are not violating any terms of android/iOS. Right?

@sergey-akhalkov
Copy link
Contributor

Hi @akki-ng,

As per codepush's concern I guess we are not violating any terms of android/iOS. Right?

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 updateDialog property that also can cause Apple rejection, so we've mentioned about this in the docs as I can remember.

@akki-ng
Copy link
Author

akki-ng commented Jun 25, 2017

sergey-akhalkov any idea about the timelines, when can we merge this PR?

@sergey-akhalkov
Copy link
Contributor

sergey-akhalkov commented Jun 26, 2017

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:

  1. update readme with notes regarding new codePushOnBinaryVersionMismatch method/feature.
  2. update readme with notes I've mentioned above regarding possible apple store rejection.
  3. update typings

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) {
Copy link
Contributor

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

@max-mironov
Copy link
Contributor

Hey @akki-ng, first of all thank you for your contribution to the project, we appreciate it!
At that moment I believe we have two PRs with the same purpose (this one and #920). I think we can go ahead with #920 due to the latter includes typings and readme.
So I'm going to close this PR, please let me know if you have any concerns about this.

@akki-ng
Copy link
Author

akki-ng commented Jul 17, 2017

Hey @max-mironov,
I'm ok with the #920 PR. Thanks for the support. Do I need to sign any CLA for this?

@max-mironov
Copy link
Contributor

@akki-ng thanks for quick reply. I don't think that you need to sign CLA for #920 as it is already marked as cla-signed.

@akki-ng
Copy link
Author

akki-ng commented Jul 17, 2017

@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 .

@disharmonized

@max-mironov
Copy link
Contributor

max-mironov commented Jul 17, 2017

@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.

@akki-ng
Copy link
Author

akki-ng commented Jul 17, 2017

@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.

@max-mironov
Copy link
Contributor

@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).

@akki-ng
Copy link
Author

akki-ng commented Jul 17, 2017

@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'

@max-mironov
Copy link
Contributor

@akki-ng I think so as #920 is based on your commit aa6e989 (https://github.com/Microsoft/react-native-code-push/pull/920/commits).

@akki-ng
Copy link
Author

akki-ng commented Jul 17, 2017

@max-mironov In that case let's roll it out then!

@max-mironov
Copy link
Contributor

@akki-ng I'm hoping it will be included in the next react-native-code-push release.

@TrustDec
Copy link

TrustDec commented Sep 29, 2017

@max-mironov @akki-ng codePushOnBinaryVersionMismatch How to use? Do you have demo to see it? I don't have an updated version of this package. I'm using react, native, 0.48.4, RNCP, 5.1.1-beta

@akki-ng
Copy link
Author

akki-ng commented Sep 29, 2017

@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.
@max-mironov Can we add the above comment in README?

@max-mironov
Copy link
Contributor

@akki-ng sounds good, will try to manage this soon.

@TrustDec
Copy link

TrustDec commented Sep 29, 2017

@akki-ng @max-mironov Thanks very much for help, but I found that the codePushOnBinaryVersionMismatch function was not called elsewhere,

>>> I have submitted a new question

I tried to use the following method, but I still couldn't detect it,The hook function cannot be triggered

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 !!!');
            });
        });

@sergey-akhalkov
Copy link
Contributor

Hi @TrustTheBoy, please take a look at the following:

  1. https://github.com/Microsoft/react-native-code-push/blob/b14654ebd93980c0f32cc28c73344561ed1d36c6/CodePush.js#L479
  2. https://github.com/Microsoft/react-native-code-push/blob/b14654ebd93980c0f32cc28c73344561ed1d36c6/CodePush.js#L79

So I believe your sync method call should look like this:

CodePush.sync(
      {}, //options
      this.codePushStatusDidChange.bind(this),
      this.codePushDownloadDidProgress.bind(this),
      this.codePushOnBinaryVersionMismatch.bind(this)
    );

@TrustDec
Copy link

@sergey-akhalkov I tried to use your method, or not, and the hook function failed to execute

@sergey-akhalkov
Copy link
Contributor

sergey-akhalkov commented Sep 29, 2017

@TrustTheBoy let's continue discussion in #1023 issue please

@TrustDec
Copy link

@akki-ng Can you see that I have failed to perform the replication?>> Demo <<

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants