Proper steps for a React Native iOS release build - ios

This is just a case of lack of documentation thus far, but when creating a production release build of an iOS React Native app, after setting the Build/Archive schemes to be Release instead of debug, do I need to manually create a main.bundle and uncomment the second jsCodeLocation line in AppDelegate.m, or does something handle that for me automatically?
I've been doing both steps manually thus far, but I'm sure there will be a day that I forget to do so, and I wanted to know what the compile and build scripts are doing for me and what I need to do myself.
(Using react-native#0.21 if applicable.)

on our App we have made that our Build System generate App.plist (with some env contextual client ids/tokens/api urls of service) and we have a property boolean that indicates if the app needs to use bundle or not.
Based on this we switch the mode to use (use bundle VS use live reload server).
I submitted some months ago a PR to bring this in the skeleton, this never goes through though, but feel free to implement your own: https://github.com/facebook/react-native/pull/2101
Also one interesting thing we use to generate our App.plist based on env is a script that basically do this: https://twitter.com/greweb/status/687575516862349312
Hope this helps

Related

Avoid React-Native manual changes for iOS production build

I'm following the React-Native documentation for building iOS for production, located here:
https://facebook.github.io/react-native/docs/running-on-device.html#building-your-app-for-production
I find these instructions very strange, because it tells you to manually edit files and xcode settings. It seems extremely annoying and error-prone having to do this every time you want to create a new release.
Is there a reasonable way to automate this or use some kind of conditional for dev/prod?

Best way to access package.json version and build variables in react native app?

I'm building a react native iOS app, and would like to:
1) Display the app's current version from the package.json file in the app itself.
Specifically: Now that I've implemented codepush, I want to display the current app version on the Settings page, so that app users can tell if their app has been upgraded. I currently set the version number in the package.json file and use this shell script to propagate that to the xcode project. If there's a better way to manage/update a projects version number, please let me know!
2) Execute certain .js code based on build variables from xcode.
I have three build configurations (Debug, Staging, Release) setup in xcode, and I would like to specify the updateDialog: true flag to codepush only for Staging builds. I would also like to display on the settings page whether this is a Debug, Staging or Release build.
What is the best way to accomplish these things?
Are there best practices for setting/syncing a project's version number and accessing it within the app, or is this stuff usually just coded by hand?
Fwiw, this answer is relevant, but doesn't say what specific environment variables xcode defines that would help me here, and doesn't speak to the versioning question.
async function getAppVersion() {
const {appVersion} = await codePush.getConfiguration();
const meta = await codePush.getUpdateMetadata();
if (!meta) return {appVersion};
const {label} = meta;
return {appVersion, label};
}
label will contain codepush release label (by default v1, v2...)
For env variables react-native-config maybe can help you. I am using fastlane with increment_build_number (iOS) and handmade fastlane code (Android) to autoincrement build number. To be honest I'm on my own in best practice search.

How can you permanently change iOS app configuration in Meteor Cordova?

Every time I meteor build, I have to open XCode and do the following:
remove and add an item from "Link Binary With Libraries" (Facebook SDK)
add a URL Type (custom URL scheme for my app)
add a "Required device capabilities" to "Custom iOS Target Properties"
How can I edit my Meteor project to have these steps done automatically, and to auto add things to AndroidManifest.xml?
In some way use mobile-config.js or cordova-build-override?
I'm happy to see another guy who is trying to build a hybrid application using Meteor / extending a Meteor Cordova iOS app, since I'm facing the very same issues. So I'm very happy to share my experiences and approaches with you. :-)
So far, I ended up with the following approach:
I created a base template for my iOS app using meteor build (not meteor run ios-device, since I did not know if Meteor does some optimizations for production code).
Then, I copied the whole Xcode project under /platforms/ios to another loaction and used this new project as my "master" project from then on. This project is being enriched with native code, e.g. it also includes the Cocoa Pods I'm needing.
Of course, I also did not want to copy files each and every time I trigger a new Meteor build. At least, I would like to have the Staging/www folder updated, as this is happening quite frequently.
So my first (rather naive) approach was
delete the Staging/www folder in the master project
replace it with a relative link (using Xcode's linking functionality) to the Staging/www folder inside the .meteor/local/.../ios/ project
This approach did not work, since the shell script used in the Meteor Xcode project can't handle these links.
My second approach is to create a symlink on the filesystem level instead. This works as it should, and I'm able to build the project in Xcode as it should.
I could have followed the same approach for the Cordova plugins folder, but I've decided to replace the plugins manually in order to get a better control over them, even it means a bit more effort then.
Having the symlink in place also means that Xcode's version management (and also SVN which I am using for everything) will ignore everything below Staging/www, which is good in my opinion, because I'm already versioning the webapp code in the Meteor project itself.
BTW: I've started a discussion thread on hybrid mobile app on the Meteor forums as well, but so far it did not get too much attraction:
https://forums.meteor.com/t/building-a-hybrid-meteor-cordova-app-share-experiences/8212
Maybe we could follow up on Meteor-specific things there, to have the Meteor community participate in the discussion?
EDIT: I would also like to share an approach that failed completely, at least for me, maybe I was too dumb... Before I used Meteor's Xcode template as the starting point, I also tried it "the other way round", i.e. I started with my already existing Xcode app project and tried to include Meteor's / Cordova's part by hand. Using this approach, I never managed to set everything up correctly. I had lots of troubles and also had to tweak a lot of the compiler / linker flags to even get the code compiling. This grew me a lot of gray hairs. But even after I managed to get everything to compile, Meteor hang during startup - and I never figured out why.
One remaining problem I'm still facing is that Meteor's hot code push functionality seems to have some severe issues on iOS, that are also documented as GitHub issues. It can happen that the iOS app gets completely broken and needs to be reinstalled. I tried the mdg:reload-on-resume package, but this did not work as it should and made things even worse. As far as I can tell from the GitHub discussions, one should better disable hot code push until the Meteor team has addressed these issues. Breaking the app completely due to code pushes is not what my users would expect.
Unfortunately plist values (and assumably AndroidManifest.xml as well) can only be changed by a plugin:
Add entry to iOS .plist file via Cordova config.xml

Xcode using schemes to determine dev/staging/production server URLs

I wish to use Xcode's schemes to determine what server to run my app against. I have an app that fetches its information from a server. Like most people I have a development server, a staging server and a production server.
I wish to create a scheme for each of these where Xcode will inject the correct URL. Do I duplicate the run scheme and add environmental variables? Is this the best way to do things, I don't particularly wish to have #ifdef's in my server class and setting it in code each time I change server. Can anyone point me in the right direction please?
FYI: I'm using Xcode 5.0.2 iOS7 SDK.
[EDIT] Everyone gave some great suggestions but I feel #redent84 answer best suits my needs. Though I found it interesting that none actually suggested using different schemes. [/EDIT]
I recommend you to create different XCode Targets for each environment. I recommend you to change the App Identifier of the Apps, for example, the production app would be com.mycompany.App and the DEVEL version would be com.mycompany.App-DEVEL. This way you can track the Apps separately in HockeyApp or TestFlight, and you can have both applications in the same device at the same time.
Then, add Preprocessor Macros that define the environment for every target. DEVEL for development, for example.
If the URL is hardcoded, simply add a #ifdef instruction to choose the URL:
#ifdef DEVEL
#define ENDPOINT_URL #"http://develserver:8080/EndPoint"
#elif defined(STAGING)
#define ENDPOINT_URL #"http://stagingserver:8080/EndPoint"
#else
#define ENDPOINT_URL #"http://app.mycompany.com/EndPoint"
#endif
This way is less error-prone to distribute a development version, easier to maintain and allows you to add custom code to different versions. For example, you may want to include the version number in the login screen or show alert dialogs for development, but not for distribution version.
Use a key in the plist (for each schema, eg: URL_TO_USE), use define to create a 'shortcut' to get the value.
#define MyURL [[NSBundle mainBundle] objectForInfoDictionaryKey:#"URL_TO_USE"]
EDIT
You must have multiple targets. Each target should point to a different .plist file. See:
How to configure independent sets of runtime settings in XCode
I handle this by setting custom pre-processor defines for each scheme.

Why is there no 'cake watch:ios:dev'?

I am using cordova-brunch in a project and I would really like to not have to re-run the cake build:ios:dev command each time I modify the JavaScript/CoffeScript source. Even more since I usually have to also make changes in the iOS Objective-C code for my hybrid app and I generally rebuild the App from XCode forgetting to rebuild the JS/CS part.
The behaviour is identical for Chapless Brunch and Cider Brunch, but I still don't get what prevents a cake watch:ios:dev functionality. The available cake watch:cordova:dev doesn't solve the problem.

Resources