5

I'm trying to implement AppCenter CodePush to update Javascript code without having to go through the App Store review process.

I've followed both the iOS and Android steps mentioned here to setup multi deployment environments: https://github.com/microsoft/react-native-code-push/blob/master/docs/multi-deployment-testing-ios.md https://github.com/microsoft/react-native-code-push/blob/master/docs/multi-deployment-testing-android.md

Versions

"react-native": "0.59.10"

"react-native-code-push": "^5.6.1"

I tried on Android with react-native run-android --variant release and on iOS I changed my RUN and Archive scheme to STAGING. But in both cases they seem to fetch my bundle like so [CodePush] Loading JS bundle from "assets://index.android.bundle" and not from the CodePush repo. This is the only output I see (CodePush related).

I made a codePush release like so: appcenter codepush release-react -a name/appName-1 -d Staging . This command succeeded, I see it on the iOS and Android staging environment with the correct version.

componentDidMount

componentDidMount() {
    codePush.notifyApplicationReady();
    ...
    codePush.sync({
      updateDialog: true,
      installMode: codePush.InstallMode.IMMEDIATE
    });
  }

Export App

App = codePush({
  checkFrequency: codePush.CheckFrequency.ON_APP_RESUME
})(App);

AppRegistry.registerComponent("myApp", () => App);

Info.plist

CodePushDeploymentKey: $(CODEPUSH_KEY)

android/app/build.gradle

buildTypes {
        debug {
            buildConfigField "String", "CODEPUSH_KEY", '""'
        }

        releaseStaging {
            buildConfigField "String", "CODEPUSH_KEY", '"my_code"'
            matchingFallbacks = ['release']
        }
        release {
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            signingConfig signingConfigs.release
            buildConfigField "String", "CODEPUSH_KEY", '"my_code"'
        }
    }

My build-settings contain the codePush Release and staging code's.

enter image description here

I also tried upgrading the CodePush Staging releases to production, but that did not solve my problem.

appcenter codepush deployment list -a Name/MyApp always returns 0 (1 pending). enter image description here

UPDATE It asks to update the app, after approving it successfully updates the app. But when I restart the app, it rollbacked to the previous version.

UPDATE 2 AppDelgate.m changes:

#import <CodePush/CodePush.h>

#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [CodePush bundleURL];
#endif

MainApplication.java changes:

import com.microsoft.codepush.react.CodePush;
@Override
protected String getJSBundleFile() {
  return CodePush.getJSBundleFile();
}

@Override
protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(
    .. 
    new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG),

build.gradle changes:

buildTypes {
  debug {
    buildConfigField "String", "CODEPUSH_KEY", '""'
  }

  releaseStaging {
    buildConfigField "String", "CODEPUSH_KEY", '"<staging_key>"'
    matchingFallbacks = ['release']
  }

  release {
    ..
    buildConfigField "String", "CODEPUSH_KEY", '"<prod_key>"'
  }
}
Kevin Etore
  • 1,046
  • 3
  • 14
  • 32
  • 1
    Are there any js errors in the updated app? Usually codepush will automatically roleback to the previous version if there is a fatal error within the udpated js bundle. – Leo Aug 07 '19 at 13:28
  • @Leo No, I just simply added a few static text elements to the Codepush release, to sort of understand and implement the Codepush functionality. – Kevin Etore Aug 07 '19 at 13:50
  • I've seen that Codepush compares local bundle with the server one, If there is no diff it won't download the bundle again even if it never downloaded(For the first release). This is two I have seen : [CodePush] Loading JS bundle from "assets://index.android.bundle" [CodePush] Reporting binary update (). And for the rollback after updating, Is rollback count in the appcenter console increased. – Bharath Kumar Aug 09 '19 at 10:24
  • @BharathKumar Regarding the Codepush compares > I noticed that as well. And the Rollback issue was/is weird because the rollback count did not increase. But in the end, we managed to fix the issue (see the answer below). – Kevin Etore Aug 09 '19 at 13:01

3 Answers3

6

Are you testing this in the simulator?

If so, doing a reload basically simulates a crash in the eyes of CodePush.

If you are running in the simulator CodePush will behave differently than it would on a real device that is not tied to a packager. The best way to test it is to do a build and upload that build to the store for distribution to your testing pool.

Then you can download and install your build through the Google play store, or testflight for iOS, and test your CodePush installation there.


EDIT:


After a chat, and making the following code changes, we got things working:

First, create an options object, and use it in our codePush calls:

const options = { 
  updateDialog: true, 
  installMode: codePush.InstallMode.IMMEDIATE, 
  checkFrequency: codePush.CheckFrequency.ON_APP_RESUME 
}; 

Then we could call codePush sync as follows: codePush.sync(options);

Lastly, instead of assigning the codePush setup to App, we moved it all into one line:

AppRegistry.registerComponent("myApp", () => 
  codePush(options)(App) 
);

Not being a codePush expert, I don't know if the options part was required, though I think having differing options at different points may have caused inconsistencies.

I do think that calling App = codePush(options)(App) was causing problems.

Either way, the combination of these two things have fixed the problem.

Doug Watkins
  • 1,387
  • 12
  • 19
  • Hi! I've tested it both the simulator (running it in on staging and release mode) and I created a release version of the app (tested on both iOS and Android). I changed `updateDialog` to `false`, and after a few seconds, the app restarts and I see my changes from the Codepush release. But after I restart and open the app the "Codepush release is gone" and I'm back to the older version. – Kevin Etore Aug 07 '19 at 15:52
  • Are you using the AppCenter code push, or the stand alone code push? Also, just to make sure I'm on the same page, by release version you mean you uploaded the app to the play store or TestFlight and downloaded it through there to test. Lastly, are you seeing 'rollbacks' in your codepush dashboard? – Doug Watkins Aug 07 '19 at 16:21
  • One more thing, what changes did you make to your Android MainApplication.java file, and your iOS AppDelagate.m file? – Doug Watkins Aug 07 '19 at 16:25
  • Mind joining me here? https://chat.stackoverflow.com/rooms/197626/codepush-react-native – Kevin Etore Aug 07 '19 at 16:27
  • I've just updated my question with the MainApplication.java and AppDelegate.m changes. I'm using the AppCenter Codepush (with `appcenter-cli`) and within my Codepush dashboard, I don't see any rollbacks or installs which is strange (with a 100% rollout). – Kevin Etore Aug 07 '19 at 16:40
  • And by release I meant, creating a new release with `./gradlew assembleRelease` and installed that on an Android device. Uploading the APK to the Play Store and installing it from there shouldn't make a difference, the current issue feels non-related to either the App Store or TestFlight. – Kevin Etore Aug 07 '19 at 16:43
  • Are you also setting up/instantiating AppCenter in your MainApplication and AppDelegate? – Doug Watkins Aug 07 '19 at 18:29
  • I've added a bit more context here: https://chat.stackoverflow.com/rooms/197626/codepush-react-native I've updated my question with both the MainApplication and AppDelegate with the related AppCenter code. I'm almost certain that those 2 files are correctly implemented. – Kevin Etore Aug 07 '19 at 20:04
1

I had the same problem, so I just wrote down the codePush.notifyAppReady() on my app landing page, and make sure you do it before checking for a new update

componentDidMount(): void {
        codePush.notifyAppReady()
        this.checkUpdate();
}

checkUpdate = async () => {
    const updateData: RemotePackage | null = await codePush.checkForUpdate()
    if (updateData && !updateData.failedInstall) {
        //your code
        this.setState({
            isMandatory: updateData.isMandatory,
            whatsNew: updateData.description,
            showAppUpdateDialog: true
        })
    }
}
Ankit Pandey
  • 220
  • 5
  • 9
0

In my case, I was using codePush.sync manually. And in the docs of codepush, they say:

Notifies the CodePush runtime that a freshly installed update should be considered successful, and therefore, an automatic client-side rollback isn't necessary. It is mandatory to call this function somewhere in the code of the updated bundle. Otherwise, when the app next restarts, the CodePush runtime will assume that the installed update has failed and roll back to the previous version. This behavior exists to help ensure that your end users aren't blocked by a broken update.

And they suggest to use notifyAppReady after successful update. However, i couldn't find an appropriate place to call this with react-navigation. Instead, in the root of navigation component, created this variable

const codePushOptions = { checkFrequency: codePush.CheckFrequency.MANUAL };

and component exported as

export default codePush(codePushOptions)(App);
tufanlodos
  • 121
  • 1
  • 5