To run the ./gradlew
script locally, you need to be using a version of Java which is supported by the version of Gradle that this project uses.
The version of Gradle that this project uses is specified by the distributionUrl
in gradle/wrapper/gradle-wrapper.properties. To find out which versions of Java are compatible with this version of Gradle, consult the Gradle compatibility matrix.
If you are using asdf
to manage tool versions, then you can rely on the .tool-versions
file in this repository, which is configured to use an appropriate version of Java.
In order to run the NetworkConnectivityTests
, you will need to be running an instance of the SDK Test Proxy on your development machine. You can do this by executing ./gradlew run
inside the external/sdk-test-proxy
directory.
This repository is structured as a Gradle Multi-Project Build. To run checks, tests and assemble all SDK and app projects from the command line use:
- macOS:
./gradlew check assemble
- Windows:
gradle.bat check assemble
These are the same Gradle tasks that we run in CI.
Before contributing to this repository please read the architectural notes.
We developed and continue to maintain this SDK using Android Studio, so this is the IDE (Integrated Development Environment) we recommend you use.
From the dialog presented by File
> Open...
/ Open an Existing Project
, select the repository root folder and Studio's built-in support for Gradle projects will do the rest.
Android Studio is the official IDE for Android app development and is based on top of IntelliJ IDEA. This means that, more often than not, sources of help you will find in relation to IDE questions or problems you face will be from JetBrains and related to IntelliJ directly. Most of the time these sources of help are also relevant to Android Studio, but your mileage may vary.
Because of IntelliJ's approach to Project Security you will need to explicitly trust the project when you open it. Previewing in safe mode will not give you the full IDE experience.
After cloning this repository for the first time, you will likely find that opening it in Android Studio or attempting to use Gradle from the command line (e.g. ./gradlew tasks
) will produce the following FAILURE:
Could not get unknown property 'MAPBOX_DOWNLOADS_TOKEN' for project ':publishing-sdk' of type org.gradle.api.Project.
This is normal, and is easy to fix.
MapBox's Maps SDK for Android documentation suggests configuring your secret token in ~/.gradle/gradle.properties
, which makes sense as it keeps it well away from the repository itself to avoid accidental checkin.
There are, of course, many other ways to inject project properties into Gradle builds - all of which should work for this MAPBOX_DOWNLOADS_TOKEN
property.
The following secrets need configuring in a similar manner to that described above for the MapBox SDK Dependency MAPBOX_DOWNLOADS_TOKEN
:
ABLY_API_KEY
MAPBOX_ACCESS_TOKEN
GOOGLE_MAPS_API_KEY
The Gradle build scripts react to values assigned to the runtimeSecrets
property.
This is a property unique to the projects in this repository, altering the build configuration depending on the downstream needs of the build, in respect of BuildConfig
availability and values of ABLY_API_KEY
and MAPBOX_ACCESS_TOKEN
(both supplied via Gradle properties).
runtimeSecrets value |
Build Configuration | Notes |
---|---|---|
FOR_ALL_PROJECTS_BECAUSE_WE_ARE_RUNNING_INTEGRATION_TESTS |
Production secrets injected into all projects, for both release and debug build types. |
Allows integration tests (connected checks, the androidTest source set in each project) to have access to these secrets. Used by the emulate workflow. |
USE_DUMMY_EMPTY_STRING_VALUES |
Dummy secrets injected only into app projects. This allows the projects to build without production secrets needing to be supplied via Gradle properties. | This means that any app or live-service integration test builds that attempt to use these secret values at runtime will fail. Used by the check, docs and publishing workflows. |
either undefined or any other value | Production secrets injected only into app projects. | Ensures that they are not accidentally exposed to any of the SDK projects. Used, implicitly, by the assemble workflow. |
It is a little bit hacky and there might be another way to do this in a more Gradle or Android idiomatic manner, however it suits the needs of our project build for the time being and does not change or otherwise alter the SDK products we publish.
For local development purposes, most developers will find that the most helpful general purpose configuration is to put the following line into their ~/.gradle/gradle.properties
file:
runtimeSecrets: FOR_ALL_PROJECTS_BECAUSE_WE_ARE_RUNNING_INTEGRATION_TESTS
There isn't an out-of-the-box command provided by Gradle to provide a readable breakdown of which tasks in the build are configured to rely upon which other tasks. The --dry-run
switch helps a bit, but it provides a flat view which doesn't provide the full picture.
We could have taken the option to include some Groovy code or a plugin in the root project configuration to provide a full task tree view, however it's strictly not needed to be part of the sources within this repository to build the projects as it's only a tool to help with debugging Gradle's configuration.
If such a view is required then we suggest installing this Gradle-global, user-level init script, within ~/.gradle/init.gradle
as described in the Gradle documentation. Once the init script is in place then, for example, the Gradle check
task can be examined using:
./gradlew check taskTree --no-repeat
The taskTree
task requires a preceding task name and can be run per project, a fact that's visible with:
./gradlew tasks --all | grep taskTree
There are a few things that you need to be aware of when writing automated tests.
When writing automated tests using Mapbox's replay engine, you may notice that the first location event appears to be replayed twice when a trip is started.
This is expected, and is due to the fact that our event listeners get registered within Mapbox for both "location updates" and also a "first location" - which tells us where the asset is at the start of the trip. Subsequent location updates will only be received once.
This section defines the names of the GitHub secrets defined to be used by our publishing workflows.
OpenGPG Signatory Credentials to be used by Gradle's Signing Plugin:
MAVEN_SIGNING_KEY_ID
: The public key ID.MAVEN_SIGNING_KEY_PASSWORD
: The passphrase that was used to protect the private key.MAVEN_SIGNING_KEY_RING_FILE_BASE64
: The contents of the secret key ring file that contains the private key, base64 encoded so that it can be injected as a GitHub secret (encode from macOS usingopenssl base64 < signing.key.gpg | pbcopy
).
Details for the Sonatype identity to be used to publish to our Ably's com.ably
project (OSSRH-68447):
OSSRH_USERNAME
: The Sonatype user.OSSRH_PASSWORD
: The password for the Sonatype user.
The primary (Kotlin, not Java) example apps (Publishing and Subscribing) were initially developed with a focus on them being useful to developers working on this codebase to provide them with a test harness for quick, manual, local/desk-bound testing as they worked on features and bug fixes. These example apps, however, also grew to attain functionality that helps us and the wider Ably team do 'in the field' manual testing more akin to QA (Quality Assurance) testing.
In order to allow these example apps to be installed OTA (Over-The-Air) onto the Android devices of manual/QA testers where there is no development environment (e.g. Android Studio) attached we have configured their Gradle projects to support Firebase App Distribution.
How these secrets are used by the Gradle build runtime can be best observed by inspecting
the publish-example-apps
workflow file.
Partially Supported: We have only configured this for the Publishing Example project so far. We will add it to the Subscribing Example App project when we work on #957.
The secrets used to configure the Android app signing configuration are called:
Secret Name | Gradle Build Input Mechanism | Description |
---|---|---|
AAT_SDK_EXAMPLE_APPS_ANDROID_SIGNING_JKS_FILE_BASE64 |
Hydrated (decoded from base64) to file at publishing-example-app/signing.jks |
This is a Java KeyStore file and can be created using Android Studio using the instructions here. Configures the storeFile property. |
AAT_SDK_EXAMPLE_APPS_ANDROID_SIGNING_KEY_ALIAS |
Property with the same name. | Configures the keyAlias property. |
AAT_SDK_EXAMPLE_APPS_ANDROID_SIGNING_KEY_PASSWORD |
Property with the same name. | Configures the keyPassword property. |
AAT_SDK_EXAMPLE_APPS_ANDROID_SIGNING_STORE_PASSWORD |
Property with the same name. | Configures the storePassword property. |
This file is required by the Google Services Gradle Plugin to (optionally) supply the Gradle build runtime with the information it requires to:
- Build Firebase Crashlytics support into the example app runtime
- Build Firebase App Distribution support into the Gradle build runtime
The secret, for the Publishing Example App, is called PUBLISHING_EXAMPLE_APP_GOOGLE_SERVICES_JSON
.
A
Service Account
is required to upload example apps to the Firebase App Distribution service and contains the secret information required by the Gradle build runtime to authorise with that service using
the appDistributionUploadRelease
task
that is provided by
the Firebase App Distribution Gradle plugin.
The secret is called ASSET_TRACKING_SDKS_GSERVICEACCOUNT_PRIVATE_KEY_JSON
.
Creating the Service Account and then providing it the necessary roles and permissions can be done in a number of ways but for our initial setup and testing of this capability was achieved using Google Cloud's IAM and admin Console (Web UI). The Policy troubleshooter tool therein is highly recommended as it was helpful to work out which roles needed to be given to this account in order for it to succeed in authorising with Firebase App Distribution.
For the firebaseappdistro.releases.update
permission for the Firebase project resource we found that the following roles were required for this service account to allow the Gradle task to succeed in uploading to Firebase App Distribution:
- Editor
- Firebase App Distribution Admin
- Owner
Caveat: The initial author of this guidance is not an expert in Firebase or IAM. Your mileage may vary. Stuff changes. It is strongly suggested to read Google Docs yourself for canonical guidance, or consult an expert.
OpenID Connect (OIDC): We should be using this, but we're not yet, but will once we work on #958.
Releases should always be made through a release pull request (PR), which needs to bump the version number and add to the change log. For an example of a previous release PR, see #298.
The release process must include the following steps:
- Ensure that all work intended for this release has landed to
main
- Create a release branch named like
release/1.2.3
- Add a commit to bump the version number - this commit should also include an update to the root
README.md
,where the latest version number is explicitly referenced. You must also bump version code by 1 for each version bump. - Add a commit to update the change log
- Push the release branch to GitHub
- Open a PR for the release against the release branch you just pushed
- Gain approval(s) for the release PR from maintainer(s)
- Land the release PR to
main
- Create a tag named like
v1.2.3
and push it to GitHub - Run the publish workflows:
- These are manually triggered, where you supply the version number so the script publishes only up to that tag
- They must be run from the
main
branch - First workflow: Maven Central
- Second workflow: GitHub Packages
- Create the release on GitHub including populating the release notes
- Create the entry on the Ably Changelog (via headwayapp)
We tend to use github_changelog_generator to collate the information required for a change log update.
Your mileage may vary, but it seems the most reliable method to invoke the generator is something like:
github_changelog_generator -u ably -p ably-asset-tracking-android --since-tag v1.0.0 --output delta.md
and then manually merge the delta contents in to the main change log (where v1.0.0
in this case is the tag for the previous release).
There is always a slight delay after our publish workflow has completed until the release appears at Maven Central, measuring in minutes.
The following sites will get updated once the release is available:
- central.sonatype.com - their newest Web UI (at the time of writing this, at least) so is likely to be the quickest to get updated
- search.maven.org
- mvnrepository.com