James Montemagno
James Montemagno

Live, Love, Bike, and Code.

Tags


Twitter


James Montemagno

VS App Center Custom Build Scripts for Production Apps

James MontemagnoJames Montemagno

A few weeks ago I introduced my Mobile App Tasks for VSTS to help developers streamline their build and release pipeline for iOS and Android apps. This collection of tasks contains things that almost every app needs at some point. This includes changing app identifiers or names and most importantly bumping version codes and names. So far, feedback of these tasks has been great:

Tasks

The number one question I get is how would you accomplish this with Visual Studio App Center when building iOS and Android apps.

microsoft-visual-studio-app-center

Do not fear as App Center has a great feature that allows you to run build scripts that are in your app's repo. They even have have great documentation on how to use it. Let's look how we would add some of these to our repo to streamline our App Center Build.

Creating a script

App Center let's you create bash scripts for iOS and Android (Powershell for UWP) that are detected automatically when they are located next to your .sln for iOS and .csproj for Android. Simply create a file with a specific name based on when you want the script to run:

  • Post-clone: appcenter-post-clone.sh -> runs immediately after repo was cloned
  • Pre-build: appcenter-pre-build.sh -> runs just before the app is built
  • Post-build: appcenter-post-build.sh -> runs right after the app was built

These bash scripts can basically do anything and have access to not only built in variables such as the build id or branch, but also any custom environment variables that you may add (which is pretty awesome and I do for all my identifiers).

Bash Scripts!

Yes, bash scripts! Do not fear if you are new to bash because I already wrote ALL of them as part of my VSTS Mobile Tasks, which you can find on my GitHub. I wrote all of the scripts originally in bash, then powershell, and then finally TypeScript, which means you have everything you need.

Setting Any Variable

One thing I like to do is never hard code any of my variables into my source code. Instead I like to swap them out on the build server. This can be accomplished by having a specific string in code that you want to change. For instance, let's say we create a class that looks like this:

Ids.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace MyApp.Helpers
{
    public class Id
    {
        #region AppCenter
        public const string AppCenter = "APP_SECRET";
        #endregion
    }
}

Now, we can use this AppCenter string in our code and swap it out before we build:

#!/usr/bin/env bash

echo "Arguments for updating:"
echo " - AppSecret: $APP_SECRET"

# Updating ids

IdFile=$BUILD_REPOSITORY_LOCALPATH/src/MyApp/Ids.cs

sed -i '' "s/APP_SECRET/$APP_SECRET/g" $IdFile

# Print out file for reference
cat $IdFile

echo "Updated id!"

This is just simple matching of strings, but works great!

Identifiers!

Changing identifiers is nifty when you are working with internal test builds on iOS for Ad-Hoc development that may need a different Id for the App Store. However, you may only want to do this when it is on a specific branch, which means we can introduce logic right into our script:

#!/usr/bin/env bash

# Updating Info.plist

PLIST=$BUILD_REPOSITORY_LOCALPATH/MyApp/iOS/Info.plist

# Check branch and run commands if so:
if [ "$APPCENTER_BRANCH" == "appstore" ]; then
  
    /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.mynewid" $PLIST
  
    /usr/libexec/PlistBuddy -c "Set :CFBundleName  NewBundleName" $PLIST
  
    /usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName  NewBundleDisplayName" $PLIST

fi

# Print out file for reference
cat $PLIST

echo "Updated info.plist!"

Android Manifest Identifiers!

We can do something very similar for Android too:

#!/usr/bin/env bash

# Updating Manifest

MANIFEST=$BUILD_REPOSITORY_LOCALPATH/MyApp/Android/Properties/AndroidManifest.xml

# Check branch and run commands if so:
if [ "$APPCENTER_BRANCH" == "appstore" ]; then

    PACKAGENAME=`grep package ${MANIFEST} | sed 's/.*package\s*=\s*\"\([^\"]*\)\".*/\1/g'`
    if [ -z "${PACKAGENAME}" ] ; then
      echo " [!] Could not find package name!"
      exit 1
    fi
    
    NEWNAME=com.newname
    sed -i.bak "s/package="\"${PACKAGENAME}\""/package="\"${NEWNAME}\""/" ${MANIFEST}
    
    rm -f ${MANIFEST}.bak
fi

# Print out file for reference
cat $MANIFEST

echo "Updated Manfiest!"

Version bumping!

This is actually one of my favorite things my tasks do, which is update the code and name automagically. The nice thing is that App Center will AUTOMATICALLY update your build code for you! This is super nice and can be set to an incrementing build number or to the date/time combo:

Bump

However, this doesn't mean the display code is updated, but do not fear we can script it:

#!/usr/bin/env bash

# Updating Info.plist

PLIST=$BUILD_REPOSITORY_LOCALPATH/MyApp/iOS/Info.plist

/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString 1.0.${APPCENTER_BUILD_ID}" $PLIST

# Print out file for reference
cat $PLIST

echo "Updated info.plist!"

Then we have Android:

#!/usr/bin/env bash

# Updating Manifest

MANIFEST="$BUILD_REPOSITORY_LOCALPATH/MyApp/Android/Properties/AndroidManifest.xml"

VERSIONNAME=`grep versionName ${MANIFEST} | sed 's/.*versionName\s*=\s*\"\([^\"]*\)\".*/\1/g'`

sed -i.bak "s/android:versionName="\"${VERSIONNAME}\""/android:versionName="\"1.0.${APPCENTER_BUILD_ID}\""/" ${MANIFEST}

rm -f ${MANIFEST}.bak

# Print out file for reference
cat $MANIFEST

echo 

There you have it! Bumping and changing version names and app identifiers like a pro!


Tags



Live, Love, Bike, and Code

Checkout my monthly newsletter that you should subscribe to!

Comments