Build time / dynamic configurations per environment (mobile-config, etc.)

How can mobile-config.js be dynamically changed per environment without manually editing it pre-build each time?
For example, we want to differentiate the app name on our app icon between Dev and Prod versions - so:

App.info({
  name: 'AppNameDev',
  version: '0.2.0'
});

and then for production:

App.info({
  name: 'AppName',
  version: '0.2.0'
});

We’d also like to be able to have ONE source of truth for the version and display that in app. Meaning we’d either need to be able to dynamically set the version in mobile-config as well (preferred) OR read in mobile-config to the app / everywhere else and use that as the single source of truth.

Looking more broadly, we use raix for push notifications and that has a config.push.json file and we have the same issue there.

We made a config package local to our app where we put all our configuration and used Meteor.settings / environment variable to set the environment and dynamically set configuration accordingly (api keys, etc. that are different between dev and prod) and that’s been working great. But that’s run time only? We need a way to do the same for build time.

Config ={};
Config.ENV =false;

//http://stackoverflow.com/questions/14184643/detecting-environment-with-meteor-js
Meteor.methods({
  getEnvironment: function() {
    var env ='dev';   //DEFAULT
    if(Meteor.isServer) {
      if(process.env !==undefined && process.env.ENV !==undefined) {
        env =process.env.ENV;
      }
      else if(Meteor.settings !==undefined && Meteor.settings.env !==undefined) {
        env =Meteor.settings.env;
      }
      Config.ENV =env;
      console.log('Config.ENV: '+Config.ENV);
    }
    return env;
  }
});

if(Meteor.isClient) {
  Meteor.call("getEnvironment", function(err, result) {
    Config.ENV =result;
    console.log('Config.ENV: '+Config.ENV);
  });
}

Config.appInfo =function(params) {
  var ret ={
    name: 'AppNameDev'
  };
  if(Config.ENV ==='prod') {
    ret.name ='AppName';
  }
  return ret;
};

So basically, how to automate builds for different environments? I.e. for use with Continuous Integration and just in general to reduce manual (error prone) steps when building for different environments.

In past (non meteor) apps I’ve used Grunt with Grunt.template to dynamically handle this for build time.

2 Likes

Luke,

We had the same problem when trying to specify our Facebook App test ID vs production ID. The problem is that I believe mobile-config.js is in regular node land and is read before Meteor even gets started. While definitely not ideal, I solved this with mobile-config.js code that looked like this:

if (this.process.env.NODE_ENV === 'production') {
  App.configurePlugin('com.phonegap.plugins.facebookconnect', {
    APP_ID: 'XXXXXX', // production FB app ID
    APP_NAME: 'My App'
  });
}
else {
  App.configurePlugin('com.phonegap.plugins.facebookconnect', {
    APP_ID: 'XXXXXX', // test FB app ID
    APP_NAME: 'My App Development'
  });
}

Then, I ran meteor like this:

$ NODE_ENV=production meteor build ../<app-name>-build --server http://<app-server> --mobile-settings settings.json

I put that long command in my package.json file and run it like this:

$ npm run build

[1] https://github.com/Differential/meteor-mobile-cookbook/blob/master/iOS/Building.md
[2] http://blog.differential.com/use-package-json-in-your-meteor-app-for-fun-profit/

HTH,
Gerard

6 Likes

Thanks @hellogerard - that works!
One related question - the app name is now updating properly based on the environment but the SAME app is getting replaced - do you know how to have SEPARATE apps on the device (one dev, one prod) rather than them just overwriting each other?

I could be wrong but I believe the key is the Bundle ID (for iOS). Every app on your phone has to have a unique Bundle ID. If two apps have the same Bundle ID, they are the same app.

Right @hellogerard - but what about for Android? And even for iOS is there a way to set this within meteor / mobile-config?

You can just set it here

App.info({
  //id: 'com.idwjia7uevfv491fvrh8f', //- prod
  id: 'com.fl8r.dev.loc', // - dev
})

Oh awesome, thanks @stanp

I found this to be very useful, however, I noticed after some failed build attempts that if (this.process.env.NODE_ENV === 'production') { always evaluates to true during a mobile build. To work around this I set MOBILE_BUILD instead of NODE_ENV so that I could test for it in the mobile-config.js file.