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:
The number one question I get is how would you accomplish this with Visual Studio App Center when building iOS and Android apps.
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:
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!