Visual Studio Team Services (formerly Visual Studio Online) and Team Foundation Services 2015 supports a cross-platform build system that allows you to easily configure builds that run on Windows, Linux, and even OSX. Visual Studio Team Services comes with a cloud hosted build agent that runs on Windows and iOS apps can be built either by integrating your own Mac or using MacinCloud’s VS Team Services build agent plan.
Beyond just building, new HockeyAppand CodePush integrations enable you to round out your DevOps story with continuous beta distribution and crash reporting. HockeyApp is a service that allows you to deploy and collect feedback about an app from internal or external beta testers and offers top notch crash reporting both beta and production apps. CodePush is a new service in open beta that enables Apache Cordova / PhoneGap and React Native apps to update JavaScript, CSS, HTML, and other static content without an app store deployment! This is extremely useful for situations where you want to update your JavaScript app code or static content frequently during testing or even rapidly deliver fixes in a public app store environment without going through a full app store submission process.
In honor of PhoneGap Day US 2016 we will use Cordova / PhoneGap projects as a backdrop for discussing these great features but is worth noting that most of these same capabilities are available for native Android, iOS, Windows, and even Xamarin projects. In a future post we’ll even outline how to apply these capabilities and more to React Native.
Given iOS can be a difficult platform to automate, this post will focus on building and deploying the iOS version of a Cordova app using Team Services. That said, the steps outlined here are similar when targeting Android though you can use the Team Services “Hosted” build pool rather than MacinCloud or your own Mac. Note you can also use an on-premises TFS 2015 instance if you prefer.
1. Initial Setup
If you have not done so already, you’ll need to create a VS Team Services account and integrate a cross-platform agent on a Mac to build iOS. In this case we’ll use one in MacinCloud.
- First, sign up for Visual Studio Team Services.
- Next, you’ll likely want to either configure an on-premises Mac as a build agent or sign up for MacinCloud’s VS Team Services. Check out our previous post for details on setup instructions for MacinCloud. You also can opt to use PhoneGap Build if you are already using the service.
- Finally, you can opt to upload your app source code to a VS Team Services Git repo. Otherwise you can configure your build to pull code from an existing TFS, GitHub, external Git, or Subversion repository instead.
2. Configure Automated Builds & Unit Tests
The following is an abridged summary for setting up Cordova / PhoneGap build steps that is covered in more detail in our documentation. Note that there are also Xcode, Android, and Xamarin build steps that can be used in place of the Cordova ones outlined here. For iOS apps you can take a look at the detailed Xcode Build tutorial for more information.
To build a Cordova app, follow these steps:
- Install the Cordova Extension for Visual Studio Team Services. See here for alternate installation instructions for an on-premises TFS server.
- Next create a build definition, by going to the Build tab in your Team Services project and clicking the “+” icon to create a new build definition. Select the Empty template.
- Click Add Build Step… and select Cordova Build from the Buildcategory. Use the following settings:
- Platform: ios
- Configuration: debug or releas
- Cordova Version: This is pulled from taco.json if you are using VS Tools for Apache Cordova or the TACO CLI. Otherwise you’ll want to enter a version here
- iOS: See securing your signing keys for details. Cordova auto-matches by default but you can override with files or different identities
- Advanced > Working Directory: Location of your Cordova project in the source repo.
- Since we’re building iOS, we want to be sure our Cordova command is run on a Mac. Click Add demand… under the Demands section of the General tab and add a demand that xcodeexists and updatethe Default agent queue to the queue your MacinCloud or on-prem Mac is connected to (ex: default).
If you prefer, you can also use a series of PhoneGap Commandbuild steps provided by the Cordova Extension instead to use PhoneGap Build if you’ve already configured your app for use with that service. See the PhoneGap CLI reference for more information on the commands required to trigger a build. You’ll still be able to take advantage of other VSTS features like using Gulp to run tests or modify the contents of the “www” folder before transmission.
However, you should be aware that the PhoneGap Build service does not support all Cordova/PhoneGap CLI features. In addition, you will need to add a Command Line task under the Utilities category and use curl to download your ipa since the PhoneGap CLI does not automatically download the result of a remote build. We’ll continue to assume you used the Cordova Build task for the purposes of this blog post.
Running Unit Tests
Since we’re doing continuous delivery, we’ll also need add in some unit tests. In this case we’ll run a set of Jasmine tests using Gulp, Karma, and PhantomJS.
- Add this sample code to your project to get you started and add it to source control. See this article for more information on authoring tests.
- Add the npm step from the Package category with the with install as the Commandand --no-optional under Advanced > Arguments. You may also need to add --force if you encounter EPERM errors.
- Add the Gulp step from the Build category and configure it to run the test task.
- Add the Publish Test Results task from the Test category and use _results/*.xml for Test Results Files and be sure to check Control Options > Always Run.
- Move these to the top of your build definition.
- Finally, you may need to set Advanced > Working Directory and adjust the Gulp File Path and Test Results Files config settings for the above tasks if your Cordova project is not in the root of your source code repo.
3. Add Continuous Beta Distribution to HockeyApp
Now that we have our build and unit tests and running, let’s layer in the ability to deploy automatically to HockeyApp so beta testers can easily access your updated app. We’ll outline a simple configuration here, but you can take a look at HockeyApp documentation for more configuration options.
- First, if you have not already, sign up for HockeyApp. It’s free to start!
- Install the HockeyApp Extension for VS Team Services. See here for alternate instructions for on-premises TFS instances.
- Go to Account Settings on the HockeyApp site, choose API Tokens, and grab the details of your access token.
- Back on the Team Services site, go to the control panel (via the gear icon in the upper right hand corner) and click on Services tab.
- Click New Service Endpoint, select HockeyApp, and enter a name along with your access token.
- Next, go back to the build definition you created above and add the HockeyApp build step from the Deploycategory and move it after Cordova Build. Use the following settings:
- HockeyApp Connection: Select the name of the service endpoint you created above.
- Binary File Path: Path to where the ipa will land. By default this is bin/ ios/
/ for the Cordova Build task..ipa - Symbols File Path: This is needed for native crash statistics which we will configure later. By default these land in bin/ ios/
/ for the Cordova Build task..dSYM - There are a number of additional settings including the ability to simply deploy the binary to HockeyApp and then manually “publish” it to end users later. We’ll leave the defaults for now.
Now, you probably don’t want all of your dev builds getting deployed and published to end users, so simple way avoid this problem is to use a beta branch. We’ll setup CI to occur any time a commit happens in the beta branch so a simple merge / PR operation can be used to deploy.
- Create a branch that will contain the final bits you want to deploy to your beta users. We’ll call that branch beta here.
- In your build definition, click on the Repository tab and update Default branch to beta.
- Click on the Triggers tab and check Continuous Integration.
Now, the next time you commit a change to the beta branch your app will be automatically tested, built, and deployed to HockeyApp! In a future post we’ll cover how Release Management can be used to extend this concept and introduce manual gates or even deploy to app stores.
4. Add HockeyApp Update Notifications, Crash Reporting, and Feedback
Beyond just configuring app distribution, you can also notify or force users to update their app, add in crash reporting capabilities for any environment, and even wire in an integrated beta user feedback experience all via the HockeyApp SDK. Though not available today, you will soon also be able to use HockeyApp to log JavaScript exceptions too! [CL1]
The HockeyApp SDK is available for Android, iOS, and Windows and cross-platform tools like Cordova, Unity, and Xamarin. Given PhoneGap Day, we’ll briefly describe how to add these capabilities to your Cordova / PhoneGap app.
- Add the cordova-plugin-hockeyappto your Cordova project using either the Git URI from Visual Studioor by typing the following from the command line using the Cordova, Ionic, TACO, or PhoneGap CLIs:
- cordova plugin add cordova-plugin-hockeyapp
- Next, update your app code to initialize HockeyApp after the deviceready event fires as follows (replacing appId with the appropriate value from in the HockeyApp portal for your app):
- hockeyapp.start(onSuccessCallback, onErrorCallback, appId);
Commit the resulting code to source control and you’re good to go!
5. Add CodePush
Since we’re building a Cordova app, let’s also take advantage of CodePush. CodePush will allow us to do completely out-of-band updates of our app as long as there’s no native code that needs to be updated (ex: a new Cordova plugin). You can quickly push fixes to apps from app stores without re-submitting the entire app. VS Team Services can then use HockeyApp to make the latest version of your native client available to your beta testers and CodePush will constantly keep them in sync after the initial install.
CodePush is only available for Cordova/PhoneGap and React Native apps targeting Android and/or iOS, so if you’re using Xamarin or building a native app you should skip these steps.
- Install the CodePush CLI, register, and add your app to the service. From the command type (replacing
with your app’s name): - npm install -g code-push-cli@lates
- code-push registe
- code-push app add
- code-push access-key add "VSTS CI
- Addcordova-plugin-code-push to your Cordova project using either the Git URIfrom Visual Studio or by typing the following from the command line using the Cordova, Ionic, TACO, or PhoneGap CLIs:
- cordova plugin add cordova-plugin-code-push
- You’ll now need to make some changes to config.xml and your app’s devicereadyevent handler to cause the app to update out-of-band. See the CodePush getting started guide and the sample app for details.
- Commit the resulting code to source control.
- Back in Team Services, Install the CodePush Extension for Visual Studio Team Services. See here for alternate instructions for on-premises TFS instances.
- In your build definition from above, add the CodePush task from the Deploy category after the Cordova Build task. Use the following settings:
- Access Key: The access key you generated above.
- App Name: The app name you specified above.
- Package Path: This will be platforms/ios/www under your Cordova project folder for iOS or platforms/android/assets/www for Android.
- App Store Version: A semver compliant version number for the version of your native app (what a user downloads from HockeyApp or an app store). Ex: 1.0.0
- Deployment Name: Environment the app update is targeting. Given we’re focusing on beta here you should use Staging (the default) or beta as the name.
That’s it! The next time you commit to the beta branch not only will a new version of the native iOS app be generated and published to HockeyApp but users running the specified versions of the native app can be updated automatically!
Summary & Future
We’re committed to making it simple to add Continuous Integration and Continues Delivery practices into your mobile app workflow. We hope that you find the continuous delivery capabilities enabled by VS Team Services, HockeyApp, and CodePush useful!
There’s even more to come. The VS Team Services Release Management feature set introduces the concept of a release that moves from environment to environment and layers in the ability to setup manual gates in a continuous delivery pipeline. While frequently thought about in the context of web applications, in the app context release management really equates to managing the publishing and deployment of a dev, alpha/beta, and app store (internal or external) version of your app to end users. We’ve outlined how to handle beta distribution and what comes next is automatic deployment into app stores and this is where having the ability to specify manual gates and approvals is critical. We’ll cover some exciting developments in this space along with talking about the increasingly popular React Native platform in a future post.
We’re always interested in your feedback on how we can make things even better, so please contact us via UserVoice and let us know about your ideas and suggestions! You can also connect directly with the HockeyApp team via their site and Twitter, the CodePush team via email or on Discord, the Cordova team via email, StackOverflow, or Twitter, and MacinCloud via email or Twitter with any questions, issues, or suggestions you may have.
Get started with Visual Studio Team Services, HockeyApp, CodePush, and MacinCloud today!