Search code examples
iosreact-nativecode-push

iOS react native app does not update from CodePush server


I've followed the instructions to set up CodePush properly. First, I push to AppCenter:

$ appcenter codepush release-react -a myUser/appName -d Production
Detecting ios app version:

Using the target binary version value "1.0" from "ios/reactnative/Info.plist".

Running "react-native bundle" command:

node node_modules/react-native/local-cli/cli.js bundle --assets-dest /var/folders/gy/737c70fj7tq3pwdw758glxz00000gp/T/code-push118924-95814-1e6qqdj.df3g/CodePush --bundle-output /var/folders/gy/737c70fj7tq3pwdw758glxz00000gp/T/code-push118924-95814-1e6qqdj.df3g/CodePush/main.jsbundle --dev false --entry-file index.js --platform ios
Loading dependency graph, done.
bundle: Writing bundle output to: /var/folders/gy/737c70fj7tq3pwdw758glxz00000gp/T/code-push118924-95814-1e6qqdj.df3g/CodePush/main.jsbundle
bundle: Done writing bundle output
bundle: Copying 6 asset files
bundle: Done copying assets

Releasing update contents to CodePush:

Successfully released an update containing the "/var/folders/gy/737c70fj7tq3pwdw758glxz00000gp/T/code-push118924-95814-1e6qqdj.df3g/CodePush" directory to the "Production" deployment of the "appName" app.

Second, I go to the AppCenter website, select the successfully pushed version, and do a force roll out to every app.

I've tried to restart the app, reinstall the app, etc...but the app does not update from CodePush servers.

In my XCode console, I see:

loading - codepush2018-10-24 12:10:10.837955+0200 reactnative[5546:3916480] 
[CodePush] Loading JS bundle from file:///Users/myUser/Library/Developer/CoreSimulator/Devices/4E7D0B07-B6B2-4D3C-B5B8-F28F3DA47077/data/Containers/Bundle/Application/081FD17C-B182-488D-B2D1-C786A3B25AAB/reactnative.app/main.jsbundle

Does this mean that CodePush is loading from local?

I believe I am running the release scheme correctly:

release mode

class App extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
        codePush.sync({
            updateDialog: true,
            installMode: codePush.InstallMode.IMMEDIATE
        });
    }
    render(){
        return <Main screenProps={this.props} />
    }
}
const codePushOptions = { checkFrequency: codePush.CheckFrequency.ON_APP_RESUME };
const ConnectedApp = codePush(codePushOptions)(connect(state => state)(App))

firebase.auth().onAuthStateChanged(auth => {
    if(auth){
        store.dispatch(setUser(auth))
    }else{
        store.dispatch(logout())
    }
})

export default () => (
    <Provider store={store}> 
        <ConnectedApp />
    </Provider>
)

I also do not see the updateDialog: true when App mounts.


Solution

  • The Code Push keys must be same to the environment to which the application is being released and the one to which the application is built in order to receive the changes.

    There are two possible solutions in order to avoid this conflict.

    • Define separate Build Schemes.
    • Add a custom script that changes Code Push keys with the environment change.

    Build Schemes / Types

    Android

    android {
        ...
        buildTypes {
            releaseStaging {
                ...
                buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_STAGING_KEY>"'
                ...
            }
            release {
                ...
                buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"'
                ...
            }
        }
        ...
    }
    

    Source

    In the android/app/build.gradle you can defined the various buildTypes and build the app based on it

    IOS

    Under the Info tab click the + button within Configurations and Duplicate "Release" Configuration and set its name to Staging

    Now you can configure the User Defined Settings and define a new setting CODEPUSH_KEY and set ${CODEPUSH_KEY} variable to the different schemes.

    Elaborated steps are explained here: Source

    Custom Script

    Alternatively, if you don't want to add more Build Schemes / Types, you can add a custom script that changes keys based on the environment.

    change-environment.sh

    #!/usr/bin/env bash
    
    #################################
    # Change the environment variable
    #################################
    
    environment=$1
    # Read Directory Path
    parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
    cd "$parent_path"
    rm ../.env
    # Set NODE_ENV in your .env file based on the script
    echo "NODE_ENV=${environment}" > ../.env
    
    
    #################################
    # Change the code push key
    #################################
    
    if [ "$environment" = "staging" ]
    then
        echo "Change Code Push Key - Staging"
        sed -i '' -E 's/CODEPUSH_KEY ?= ?".+"/CODEPUSH_KEY = "${YOUR_STAGING_IOS_CODEPUSH_KEY}"/' ../ios/YourProj.xcodeproj/project.pbxproj
        sed -i '' -E 's/buildConfigField "String", "CODEPUSH_KEY", '\''".+"'\''/buildConfigField "String", "CODEPUSH_KEY", '\''"${YOUR_STAGING_ANDROID_CODEPUSH_KEY}"'\''/' ../android/app/build.gradle
    elif [ "$environment" = "production" ]
    then
        echo "Change Code Push Key - Production"
        sed -i '' -E 's/CODEPUSH_KEY ?= ?".+"/CODEPUSH_KEY = "${YOUR_PRODUCTION_IOS_CODEPUSH_KEY}"/' ../ios/YourProj.xcodeproj/project.pbxproj
        sed -i '' -E 's/buildConfigField "String", "CODEPUSH_KEY", '\''".+"'\''/buildConfigField "String", "CODEPUSH_KEY", '\''"${YOUR_PRODUCTION_ANDROID_CODEPUSH_KEY}"'\''/' ../android/app/build.gradle
    fi
    

    Now you can run .${SCRIPT_PATH}/change-environment.sh ${ENV}

    Example: ./change-environment.sh staging

    This script changes the buildConfigField in android buildTypes and CODEPUSH_KEY User Defined Settings to the pre defined schemes in ios.

    It would be convenient combine this script with the react native's packager start command in your package.json

    "start": "./change-environment.sh development && node node_modules/react-native/local-cli/cli.js start",
    "start:staging": "./change-environment.sh staging && node node_modules/react-native/local-cli/cli.js start",
    "start:production": "./change-environment.sh production && node node_modules/react-native/local-cli/cli.js start",