react-nativereact-navigationcode-pushreact-native-code-push

React Native codePush rollback after restart


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>"'
  }
}

Solution

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