There is a lot of busywork when you are developing for multiple app stores. Each app store is a new listing and has differing requirements for product icons and screenshots. While there is no avoiding this app store busywork, you can and should automate the build process. This is the process of compiling your code into packages for upload to each app store.

This article outlines the steps to build native apps for Apple iTunes, Google Play and Windows Store. My development stack is Windows 10 using C# .NET and Visual Studio 2017 with Xamarin.

It is worth noting that there are great options for build automation on Mac such as Fastlane. I just can’t bring myself to develop on a Mac.

Xamarin Android (.apk)

Building for Android on Windows is a pretty good experience. The tool-chain for building Xamarin Android depends on both the Java SDK and Android SDK. This is mostly handled by the Visual Studio Installer but you do need to update the Android SDK Manager to ensure you have the latest build tools.

In Visual Studio, go to Tools | Android > Android SDK Manager, let it elevate and then click Install packages when it is ready.

Before you can sign the .apk file you need to generate a keystore using the keytool utility (included in the Java SDK). It will ask you a dozen questions before creating a keystore file.

keytool -genkey -v -keystore Demo.keystore -alias Demo -keyalg RSA -keysize 2048 -validity 10000

Now edit your Android .csproj to use the keystore for release builds.

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">

<AndroidKeyStore>True</AndroidKeyStore>

<AndroidSigningKeyStore>Demo.keystore</AndroidSigningKeyStore>

<AndroidSigningStorePass>demo</AndroidSigningStorePass>

<AndroidSigningKeyAlias>Demo</AndroidSigningKeyAlias>

<AndroidSigningKeyPass>demo</AndroidSigningKeyPass>

</PropertyGroup>

Now you are ready to write a script to perform the following steps.

Clean to prevent the use of stale files.

msbuild Demo.sln /p:Configuration=Release;Platform="Any CPU" /t:DemoA:Clean

2. Increment the versionCode in AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="hodgskin.callan.demo" android:versionName="1.0" android:installLocation="auto" android:versionCode="14">

3. Build the project.

msbuild Demo.sln /p:Configuration=Release;Platform="Any CPU" /t:Demo\DemoA

4. Sign the .apk file.

msbuild DemoA.csproj /p:Configuration=Release;Platform="Any CPU" /t:SignAndroidPackage

5. Zip-align and deploy the signed .apk file (included in the Android SDK).

zipalign -f -v 4 "DemoA\bin\Release\DemoA\hodgskin.callan.demo-Signed.apk" "C:\Deployment\DemoA-14.apk"

You now have a signed .apk file that can be uploaded to Google Play!

One more thing you should know. By default your .apk will only include lib files for ARM. This isn’t a huge problem because x86/x64 Android devices are not commonplace. However, there are interesting projects like Android-x86 which mean you can run Android apps in a virtual machine.

Anyway, you can verify the lib files by opening your .apk file with something like 7zip. Under the lib folder you may only see the armeabi-v7a folder. The libomono*.so files are necessary to run your app on different architectures.

lib

|_ armeabi-v7a

|_ libmonosgen-2.0.so

|_ libmonodroid.so

Be mindful that the Xamarin Android project properties UI does not save correctly. When you select all the supported architectures it saves an empty AndroidSupportedAbis element to the .csproj file. Unfortunately, the build process treats this as ARM-only instead of all supported architectures.

To workaround thie issue you need to edit the .csproj manually and explicitly set the supported architectures.

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">

... <AndroidSupportedAbis>armeabi;armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis> ...

</PropertyGroup>

Your .apk file will now support multiple architectures with each set of the included libomono*.so files. It will add around 6MB to your .apk file above just supporting ARM.

lib

|_ x86_64

|_ x86

|_ armeabi-v7a

|_ armeabi

|_ arm64-v8a

Xamarin iOS (.ipa)

The tool-chain for building Xamarin.iOS is irksome and troublesome. This is entirely the fault of Apple for having an obstructive licensing model. But they are unlikely to relax their rules anytime soon so we must simply get on with it.

To build for iOS, you need a Mac. On that Mac, you need the latest Xcode and Visual Studio for Mac. To build for the App Store you need a valid certificate and provisioning profile installed on your Mac. For this article, I am assuming you already have a working environment.

You need to write a script to perform the following steps.

Clean to prevent the use of stale files.

msbuild Demo.sln /p:Configuration=Release;Platform=iPhone /t:DemoI:Clean /p:ServerAddress=MyMac;ServerUser=Callan;ServerPassword=test123

2. Increment the CFBundleVersion number in the info.plist.

<?xml version="1.0" encoding="utf-8"?>

<plist version="1.0">

<dict>

<key>CFBundleDisplayName</key>

<string>Demo App</string>

<key>CFBundleIdentifier</key>

<string>hodgskin.callan.demo</string>

<key>CFBundleShortVersionString</key>

<string>1.0</string>

<key>CFBundleVersion</key>

<string>14</string>

...

3. Build the project.

msbuild Demo.sln /p:Configuration=Release;Platform=iPhone /t:DemoI /p:ServerAddress=MyMac;ServerUser=Callan;ServerPassword=test123

4. Deploy the .ipa file.

copy DemoI\bin\iPhone\Release\DemoI.ipa C:\Deployment\DemoI-14.ipa

5. Zip and deploy the debug symbols for future use in HockeyApp.

7z a C:\Deployment\DemoI-14.app.dSYM.zip DemoI\bin\iPhone\Release\DemoI.app.dSYM\Contents\

You now have a .ipa file for upload to Apple iTunes Connect using the App Loader on your Mac!

If you care about performance you can also turn on the LLVM optimizing compiler by editing the .csproj file. It seems to be disabled in the Xamarin iOS project properties UI for some reason. Perhaps it has been flagged as unstable by the Xamarin team but I haven’t had any issues with my apps. But it has definitely and noticeably improved the performance of my apps.

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">

... <BuildIpa>True</BuildIpa>

<CodesignKey>iPhone Distribution</CodesignKey>

<MtouchUseLlvm>True</MtouchUseLlvm>

<MtouchUseThumb>False</MtouchUseThumb>

<MtouchUseSGen>True</MtouchUseSGen> ...

</PropertyGroup>

Universal Windows (.appxupload)

It is a little tedious to automate the build process for Windows Store apps. There is a decent manual wizard which you can access from your project and then Store > Create App Packages. However, performing the same steps from the command line necessitates fiddly work in the Configuration Manager.

Note that you need to associate your project with the Windows Store. Make sure the very first time you build is using the Create App Packages wizard.

You need to bring up the Configuration Manager under the Release configuration and edit for x86, x64 and ARM platforms. To make the build work from the command line you need to un-tick any project that is not required for the Universal Windows app. Otherwise, msbuild will try to build more than your target project and the compile is likely to fail.

This figure shows the build settings for the InvManual app

Remember that you need to maintain these settings for each of the platforms as you add new projects!

You are now ready to write a script to automate the build process.

Clean to prevent the use of stale files.

msbuild Demo.sln /p:Configuration=Release;Platform=x86 /t:DemoU:Clean

msbuild Demo.sln /p:Configuration=Release;Platform=x64 /t:DemoU:Clean

msbuild Demo.sln /p:Configuration=Release;Platform=ARM /t:DemoU:Clean

2. Increment the Version number in the Package.appxmanifest.

<?xml version="1.0" encoding="utf-8"?>

<Package>

<Identity Name="808CallanHodgskin.Demo" Version="1.0.14.0" />

...

3. Build the project (note: this step is slow, around 20 minutes for my apps).

msbuild Demo.sln /p:Configuration=Release;AppxBundle=Always;BuildAppxUploadPackageForUap=true;AppxBundlePlatforms=x86|x64|ARM; /t:DemoU

4. Deploy the .appxupload file.

copy DemoU\AppPackages\DemoU_1.0.14.0_x86_x64_ARM_bundle.appxupload C:\Deployment\DemoU-14.appxupload

You now have a .appxupload file ready for upload to the Windows Store.