OpenMiInk/third_party/ci-notary-service/doc/apksigner.md
Hellings b8c8ff98e2 Hi
2026-10-16 09:05:56 -04:00

5.5 KiB

apksigner.py - An APK Signing Service

Provides code signing for APKs.

Prerequisites

The service needs an SFTP server for exchanging data with the clients.

Additionally, for signing APKs you need

  • a key store file containing the certificate to sign the APKs with,
  • a file containing the password to unlock the key store.

Installation

Install an Android SDK

apksigner.py needs the tools apksigner, zipalign, and apkanalyzer from an Android SDK. The following instructions are based on the installation of the Android SDK in KDE's Android Docker image. See below for an alternative setup using KDE's Android Docker image.

export NDK_VERSION=22.1.7171670
export SDK_PLATFORM=android-33
export SDK_BUILD_TOOLS=30.0.3
export SDK_PACKAGES="tools platform-tools"

export ANDROID_HOME=~/android-sdk
export ANDROID_SDK_ROOT=${ANDROID_HOME}
export PATH=${ANDROID_HOME}/cmdline-tools/tools/bin:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH}

curl -Lo /tmp/sdk-tools.zip 'https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip'
mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools
unzip -q /tmp/sdk-tools.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools
rm -f /tmp/sdk-tools.zip

yes | sdkmanager --licenses
sdkmanager --verbose "platforms;${SDK_PLATFORM}" "build-tools;${SDK_BUILD_TOOLS}" "ndk;${NDK_VERSION}" ${SDK_PACKAGES}
sdkmanager --uninstall --verbose emulator

Install the Service

Clone this repository on a server that shall provide the service, create a virtual environment, and install the requirements.

git clone https://invent.kde.org/sysadmin/ci-notary-service.git apksigner
cd apksigner
python3 -m venv .venv
. .venv/bin/activate
pip3 install -r requirements.txt

Configure the Service

Copy apksigner.sample.ini to apksigner.ini and replace the example values with the appropriate values for your installation.

Then copy apksigner-projects.sample.yaml to apksigner-projects.yaml and specify the settings for the projects you want to sign APKs for.

Run the Service

Activate the virtual environment and start apksigner.py.

cd ~/apksigner
. .venv/bin/activate
python3 apksigner.py --id workerA --config apksigner.ini

where you replace workerA with a unique alpha-numeric ID for each instance of apksigner.py you start.

Use the Service to Sign an APK

Clone this repository on the client, create a virtual environment, and install the requirements.

git clone https://invent.kde.org/sysadmin/ci-notary-service.git apksigner
cd apksigner
python3 -m venv .venv
. .venv/bin/activate
pip3 install -r requirements.txt

Copy signapk.sample.ini to signapk.ini and replace the example values with the appropriate values for your installation. In particular, the value for BasePath must match the corresponding value in the settings of the service.

Then run signapk.py to sign the APK

python3 signapk.py --config signapk.ini <apk>

Managing the Service with systemd

We set up the service under the user's control with a per-user systemd instance.

Copy apksigner-user.sample.service to ~/.config/systemd/user/apksigner-user.service and modify it as needed. The example uses the username as ID of the service worker. Make sure that the ID is unique if you run multiple service workers.

Start the service with

systemctl --user start apksigner-user.service

If you want the service to be started automatically, then enable autostart with

systemctl --user enable apksigner-user.service

Note: By default, the systemd user instance and thus the user-managed services are started after the first login of a user and killed after the last session of the user is closed. To start the user instance right after boot, and keep the systemd user instance running after the last session closes you have to enable lingering for the user:

loginctl enable-linger USERNAME

For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User.

Running the Service with KDE's Android Docker Image

We assume that you have already created a suitable apksigner.ini and apksigner-projects.yaml and put them in the working copy of this repository.

The correct values for apksigner.ini for KDE's Android Docker image are

[ApkSigning]
KeyStore = /keystore.jks
KeyStorePass = file:/keystorepass
SDKToolsPath = /opt/android-sdk/build-tools/30.0.2
APKAnalyzerPath = /opt/android-sdk/cmdline-tools/tools/bin/apkanalyzer

[General]
ProjectSettings = apksigner-projects.yaml

Start a Docker container from inside the working copy of this repository passing in the working copy, the known_hosts file, the files with the KeyStore and the password to unlock the KeyStore, and the socket of the SSH agent:

docker run -it --rm \
    -v $(pwd):/apksigner \
    -v <known_hosts_file>:/home/user/.ssh/known_hosts \
    -v <keystorefile>:/keystore.jks -v <keystorepassfile>:/keystorepass \
    -v $SSH_AUTH_SOCK:/ssh-agent --env SSH_AUTH_SOCK=/ssh-agent \
    invent-registry.kde.org/sysadmin/ci-images/android-qt515

Then inside the container run:

python3 -m venv ~/.venv
. ~/.venv/bin/activate
cd /apksigner
pip3 install -r requirements.txt
python3 apksigner.py --id workerA --config apksigner.ini

Details

To protect the private SSH key we forward the SSH agent into the Docker container. Alternatively, you can mount a file holding a private OpenSSH RSA key into the container.