Quite some time has passed since the last entry in this series of guides, and today we are going to take a fresh look at things taking into account the more recent SAP Cloud Platform SDK for Android, SAP repository-based shipment, and third-party DevOps services. Please note that I will be using Github for the latter, the reason being that it is a convenient place to both share the sample project and to implement a build job that you can use as a template. This is my personal choice and there really is no reason not to go with any other DevOps platform. There are many more options that all have their pros and cons, e.g. in terms of supported Mobile operating systems or infrastructure extensibility.
Please note that this guide is not necessarily a good starting point for programming or DevOps novices. I am assuming that you are familiar with DevOps, the features and services around SAP Cloud Platform Mobile Services and that you have had at least some experience with the SAP Cloud Platform SDK for Android and general (Android) app development. Also, as mentioned above, you should familiarize yourself with the SAP Repository-Based Shipment Channel and, more importantly, the required permissions you need to obtain the credentials. This guide will skip the fundamentals of licensing and installing software, and instead focus on the integration points between "the average Android project", our SDKs and third-party DevOps services. The good news is that this guide is going to be significantly more condensed than previous instalments.
I am going to assume that you already have an app of some sort - this may either be a "fresh" app straight from Android Studio, one created with our Wizard, or an arbitrary app you just happen to have lying around. Before we go ahead, let me point out that the easiest way to get to a correctly configured way is likely to just use the Wizard: There is a configuration option that, when enabled, will automatically add the below configuration to new projects. So when you are starting from scratch, just make sure to tick the checkbox shown in Figure 1 and you are good to go!
Figure 1: Enabling Repository-Based Shipment in the Wizard
For other projects, start by adding the following configuration snippet to your project "build.gradle" file (i.e. the top-level "build.gradle" file, not the app-module one). You will need to add this in both the "buildscript.dependencies" and "allprojects.dependencies" blocks:
The reason we need to add it in both places is that buildscript dependencies include Gradle plugins, such as our OData proxy class generator. If you are consuming OData back ends, chances are you will need this. The other entry pertains to application runtime dependencies, such as Fiori UI controls. I would also like to point out that we currently have dedicated repositories (i.e. maven URLs) per major SDK release. The URLs above work for the current 3.x Android SDK releases. If you are running older releases, please refer to my original post on the matter.
Please note that this is only one of two options how to consume the Cloud Platform SDK for Android: This will ensure that provided the correct environment configuration this specific project will always be able to draw dependencies from repository-based shipment. Another option is documented that will enable this for all projects on your workstation, but this means that it will not automatically work on other people's workstations or central build servers. For CI scenarios, you always want to ensure that the project is self-contained where possible. Obvious exceptions are secrets, such as the credentials above that we draw from the environment. Since the configuration for environment variables varies between operating systems (and in the case of Mac, even between OS versions/shells and command line vs. GUI apps), I will leave this step as an exercise to the reader.
Let's add a SAP SDK dependency to the project so that we have something that is actually being drawn from the repository. Please note that this step can be omitted if you already use SAP SDKs, such as in Wizard-generated apps. Open the app module build.gradle file (i.e. not the same where we added the repository configuration) and add the following to the "dependencies" block:
Finally, we need to check if everything is set up correctly. Run the following command from a Windows PowerShell or *nix Terminal:
This should print the correct user name you obtained from the repositories management self-service. Now that this is established, make sure you navigate to the Android project root, and run:
After a few seconds, the build should successfully finish.
For release build signing, it is possible to add your release keystore to the repository (which should be acceptable for private repositories) or to supply it via secrets. In this case, we are going to assume that the release keystore is checked in with the source code, so that we can easily follow these steps to set up signing for our app. First, we'll create the workflow file. I'll talk through a few important points, but the final version can be found here. Ideally, just use that as a template to create your own. Please note that you may use arbitrary names for the YAML file, but it must be in the ".github/workflows" folder relative to your Git repository root. As-is, the workflow does the following things:
It runs whenever a change is pushed to master. In complex projects, if you're following something like Git Flow, this is adequate since master would only contain stable changes. You may choose different triggers, however, based on your release processes. Most notably, I limited the job to run only on a specific file tree because the repository has multiple projects in it.
The Docker image we choose for the container is "ubuntu-latest", which conveniently includes a mostly working* Android SDK. You may want to substitute that for a specific Ubuntu version instead of latest since that is a degree of freedom that may render builds unstable.
* I say mostly because as of the time of writing, we need to update the NDK version of the image for the build to pass. This is a minor inconvenience but requires an additional build step.
It starts off with a few standard actions, i.e. checking out the latest source code and installing Java. In this case, the version is rather ancient at Java 8, but this is a necessity of the Android build tools.
The Android project is validated. I have put unit tests and linting here as defaults, but you may want to add additional code scans, coverage reports, instrumented tests etc. Test reports and other things can be picked up and made available by the "Upload Artifact" action.
The release app bundle is built, which is challenging mainly due to proper signing and key store handling. The workflow is designed in a way that avoids having secrets or key stores under source control or printing them in the logs. For that purpose, we leverage Secrets to securely provide those values "from the outside" when the workflow runs. Those secrets include:
The user name and password for SAP repository-based shipment. As explained above, you should obtain those from the self-service. Please note that these credentials need to be refreshed every six months.
The Android signing key store, passwords and alias. This guide explains how you can create your own, as I did for this showcase, but in reality this would be your company's key store that is associated with your developer certificate. You will need to acquire the key store itself and the corresponding passwords and alias name for the release build to function.
Finally, we need to configure the secrets in Github so that the workflow may succeed. By now, you should have all secrets ready - except one: The key store itself. For security reasons, we choose to provide it encoded as secret rather than just checking in the (encrypted) key store file. In order to generate a string representation of the file, open a command line next to the key store file and run:
This will print a Base64 representation of the file. For Windows, see here. Use this value for the "ANDROID_KEY_STORE" secret.
Now that all required data is gathered, we simply need to open the repository settings on Github. The option should be available if you have at least maintainer privileges. Open the "Secrets" settings page and add the keys one by one. The result should look as follows:
Figure 2: Github Secrets configuration
And this is really it! Push the changes with your workflow file to Github and the build should start and, when correctly configured, provide a zip containing the assembled release bundle.
The obvious immediate next question is: How do I get this to my users? Alas, the options here are pretty open-ended, but let me outline a few of them:
Upload to Google Play. This is not the most common use case I see day to day, but this is conveniently enabled by an existing Github Action. You'll need to provide some additional configuration which should be easy enough to come by and you're golden.
Roll out via Mobile Device Management (MDM). This is where things get tricky since there is an abundance of vendors and tools. You will need to review the documentation of your specific tool to learn how you can upload artifacts to the system.
Push it to your favorite QA tool, such as Mobile Services App Catalog, to receive feedback. App Catalog conveniently integrates with Airwatch, too, so that you may easily push your apps to end users once the testers are happy.
Then, there are additional tools that could be added to the workflow to automate additional typical tasks. I mentioned a few types of them, such as additional code scans, but one honorary mention goes to Fastlane, a tool that continues to save countless developer hours otherwise spent building apps or taking localized screenshots. It is particularly interesting when you also consider creating iOS apps, since this is where Fastlane really shines. When you are going to use it there anyway, there is no reason why you wouldn't let it manage your Android builds, too.