This post was contributed by Eugene Trapeznikov. Imagine you have finished developing and testing your app and are now ready to submit it for production. The problem is that some of the web service URLs point to the test server and the API keys are configured for the test environment. Before submitting the app to Apple for review, you need to modify all these API keys and URLs to fit the production version. That sounds good, right? But is there a better way to handle development and production builds than changing the relevant values back and forth between the development environment and the production environment? That's exactly what Eugene will discuss with you next. Enter Eugene's tutorial For beginners, some people may wonder why you need to use two separate databases and environments during app development. The reason is that as you continue to build new features or continue to develop your app, you want to separate the existing public version from the production version. It is standard software development practice to develop different versions of software in different development environments, like in our case iPhone app. The development version of the application usually uses a different database (or other system like analytics) than the production one. That is why we should use separate servers and databases for different environments. Developers usually use dummy images or dummy data during testing. It is not uncommon to use test data such as "test comment", "argharghargh" and "one more test comment" in the test environment. Obviously, you don't want your real users to see such messages. In the case of your application using an analytics system, you may even send thousands of events during the testing phase. Similarly, you would not put test data in the same database as production data. That is why it is always recommended to separate development and production environments. When using two separate environments, your application needs to have a way to figure out which environment it should connect to. A common approach is to define a global variable in your main application proxy that will initialize your application into development or production mode.
This approach requires you to change the global variable every time you switch environments. While this approach may be quick and convenient, it has some important limitations. First, because we use one Bundle ID for both development and production environments, you cannot install two versions of your app on a single device. This becomes inconvenient when you need to test the development version of your app while still using the production version of your app on that device. In addition, this approach makes it very likely that the development version of your app will be uploaded to the App Store. If you forget to change this global variable, you will upload the wrong app to your users. I remember one time when I forgot to change the global variable before submitting my app to the App Store, and the user downloaded the development version of my app, which was terrible. In this post, I'll show you a better way to differentiate between development and production builds. Specifically, we'll create a development target in Xcode. This approach works for both new and existing large projects, so you can follow this tutorial with an existing app. By applying this approach, the development and production versions of your app will use the same base code, but can have different icons, bundle IDs and point to different databases. The publishing and submission process will be very simple. Best of all, your testers and managers can install both versions of your app on the same device, so they know exactly which version they are experiencing. How to create a new Target So how do you create a development target in Xcode? I use the sample project "todo" to walk you through the process step by step. You can also use your own project and follow the steps: 1. Go to the project settings in the project navigator. Under the Targets area, right-click an existing target and select `Duplicate`. 2. Xcode will ask you if the new target is for iPad development. For this tutorial, we just select "Duplicate Only". Tip: If your project supports universal devices, Xcode will not prompt the above message. 3. Now we have a new target and build scheme called `todo copy`. Rename it and make it easier to understand.
4. Step 4 is optional, but highly recommended. If you want to easily differentiate between development and production builds, you should use separate icons and launch pages for each version. This will make it clearer to testers which app they are using and prevent them from uploading a development version. Go to `Assets.xcassets` and add a new icon. Right-click the icon > App Icons & Launch Images > New iOS App Icon. Rename the new icon to "AppIcon-Dev" and add your own image. 5. Now go back to the project settings, select your development target, and change the Bundle Identifier. You can simply append "Dev" to the original ID. If you performed step 4, make sure to change the app icon to the one you created in the previous step. 6. Xcode will automatically add a plist file for your target (e.g. todo copy-Info.plist). You can find it in the root folder of your project. Rename it from "copy" to "Dev" and put it under the original plist file. It will be easier for you to manage the files here. 7. Now open the “Build Settings” of your development target, scroll to “Packaging”, and change the value to the development plist file (todo Dev.plist). 8. Finally, we will configure preprocessor macros/compiler flags for production and development targets. We can then use this flag in our code to detect which version the application is running. For Objective-C projects, go to Build Settings and then Apple LLVM 7.0 - Preprocessing. Expand Preprocessor Macros and add a variable in the Rebug and Release areas. For the development target (i.e. todo Dev), set the value to DEVELOPMENT = 1. For the other target, set the value to DEVELOPMENT = 0 for a production build. For Swift projects, the compiler no longer supports preprocessor directives. Instead, it uses compile-time properties and build configurations. Select the development target and add a flag to indicate the development version. Find `Build Setting` and scroll down to the `Swift Compiler - Custom Flags` section. Set the value to `-DDEVELOPMENT` to indicate this target as a development version. Now that you have created and configured your development target, what's next? Using Target and Macros Based on the configured macro DEV_VERSION, we can use it in the code to dynamically compile the project. Here is a simple example: Objective-C:
In Objective-C you can use #if to check the DEVELOPMENT environment and set the URLs/API keys accordingly. Swift:
In Swift, you can still use `#if` to determine the build parameters for dynamic compilation. However, in addition to using `#define` to define basic constants, we can also use `let` to define a global constant in Swift. Tip: Typically, you would put the above code in the app delegate. But it ultimately depends on where you initialize your app settings. Now, when you run your project with the "todo Dev" scheme, you create a development build that automatically sets the server configuration to the development environment. You can now upload your development build to TestFlight or HockeyApp for testers and managers to test. Then if you need to create a production version, you can simply select the "todo" scheme. No code changes are required. Some notes on managing multiple targets 1. When you add new files to the project, don't forget to select both targets to keep your code in sync between the two versions. 2. If you are using CocoaPods, don't forget to add the new target to your podfile. You can specify multiple targets using `link_with`. You can refer to the CocoaPods documentation for further details. Your podfile should look like this:
3. If you use a continuous integration system, such as Travis CI or Jenkins, don’t forget to configure the two targets build and deliver. What do you think of this tutorial? How do you manage your development and production builds? Leave me a comment to share your thoughts. |
<<: iOS A Song of Ice and Fire – Using XPC to pass the sandbox
>>: Every year on this day, Internet companies’ April Fools’ Day “jokes”
With the arrival of the public beta, many early ad...
In general, app operations are divided into two a...
Everyone is familiar with credit cards. Whether i...
Regarding the Uniqlo nude photo scandal, as the f...
According to foreign media reports, researchers f...
Currently, debugging apps in the browser is becom...
Where to cool off in the scorching sun? Where to ...
The Metaverse has remained popular since its laun...
In this article, the author proposes five operati...
In the movie, Ip Man is a master of martial arts,...
After much anticipation, the second wave of Chine...
Produced by: Science Popularization China Author:...
As a growth engineer and a straight man, I focus ...
Recently, the Chinese Academy of Sciences announc...
Chinese scientists develop "miniaturized thr...