190 lines
6.2 KiB
Markdown
190 lines
6.2 KiB
Markdown
<!--
|
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
# SPDX-FileCopyrightText: 2023 KDE e.V.
|
|
# SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
|
|
-->
|
|
|
|
# googleplaypublisher.py - A Google Play Publishing Service
|
|
|
|
This services publishs AABs and APKs in Google Play.
|
|
|
|
## Prerequisites
|
|
|
|
The service needs an SFTP server for exchanging data with the clients.
|
|
|
|
## Installation
|
|
|
|
### Install an Android SDK
|
|
|
|
`googleplaypublisher.py` need the `apkanalyzer` tool from an Android SDK.
|
|
The following instructions are based on the installation of
|
|
the Android SDK in KDE's Android Docker image.
|
|
|
|
```sh
|
|
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 Fastlane Supply
|
|
|
|
This service uses [Fastlane](https://docs.fastlane.tools)
|
|
for interaction with Google Play.
|
|
|
|
```sh
|
|
# writeable base directory
|
|
FASTLANE_INSTALL_PREFIX=~
|
|
# install location for the fastlane tool
|
|
FASTLANE_DIR=$FASTLANE_INSTALL_PREFIX/fastlane
|
|
# executable name of Ruby Bundler
|
|
BUNDLE_EXECUTABLE=bundle3.0
|
|
|
|
# setup bundler to no try to install things in the global prefix
|
|
export BUNDLE_EXECUTABLE
|
|
export BUNDLE_PATH=$FASTLANE_INSTALL_PREFIX/vendor/bundle
|
|
export BUNDLE_APP_CONFIG=$FASTLANE_INSTALL_PREFIX/.bundle
|
|
$BUNDLE_EXECUTABLE config set --local path $BUNDLE_PATH
|
|
|
|
# install/update fastlane
|
|
mkdir -p $FASTLANE_DIR
|
|
pushd $FASTLANE_DIR
|
|
|
|
cat >Gemfile <<EOF
|
|
source "https://rubygems.org"
|
|
gem "fastlane"
|
|
EOF
|
|
|
|
$BUNDLE_EXECUTABLE install
|
|
|
|
popd
|
|
```
|
|
|
|
### Install Bundletool
|
|
|
|
Bundletool is needed if you want to publish AABs. Download the jar file from the
|
|
[GitHub repository](https://github.com/google/bundletool/releases).
|
|
|
|
### Install the Service
|
|
|
|
Clone this repository on a server that shall provide the service,
|
|
create a virtual environment, and install the requirements.
|
|
|
|
```sh
|
|
git clone https://invent.kde.org/sysadmin/ci-notary-service.git googleplaypublisher
|
|
cd googleplaypublisher
|
|
python3 -m venv .venv
|
|
. .venv/bin/activate
|
|
pip3 install -r requirements.txt
|
|
```
|
|
|
|
### Configure the Service
|
|
|
|
Copy `googleplaypublisher.sample.ini` to `googleplaypublisher.ini` and replace the example values
|
|
with the appropriate values for your installation.
|
|
|
|
Then copy `googleplaypublisher-projects.sample.yaml` to `googleplaypublisher-projects.yaml` and
|
|
specify the settings for the projects you want to publish AABs or APKs for.
|
|
|
|
## Run the Service
|
|
|
|
Activate the virtual environment and start `googleplaypublisher.py`.
|
|
|
|
```sh
|
|
cd ~/googleplaypublisher
|
|
. .venv/bin/activate
|
|
python3 googleplaypublisher.py --id workerA --config googleplaypublisher.ini
|
|
```
|
|
|
|
where you replace `workerA` with a unique alpha-numeric ID for each instance
|
|
of `googleplaypublisher.py` you start.
|
|
|
|
## Use the Service to Publish an AAB or one or more APKs
|
|
|
|
Clone this repository on the client, create a virtual environment, and install
|
|
the requirements.
|
|
|
|
```sh
|
|
git clone https://invent.kde.org/sysadmin/ci-notary-service.git googleplaypublisher
|
|
cd googleplaypublisher
|
|
python3 -m venv .venv
|
|
. .venv/bin/activate
|
|
pip3 install -r requirements.txt
|
|
```
|
|
|
|
Copy `publishongoogleplay.sample.ini` to `publishongoogleplay.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 `publishongoogleplay.py` to publish an (unsigned) AAB or one or more signed APKs
|
|
|
|
```sh
|
|
python3 publishongoogleplay.py --config publishongoogleplay.ini --fastlane <fastlane> <aab or apk>...
|
|
```
|
|
|
|
where `<aab or apk>...` is the AAB or the APKs you want to publish and `<fastlane>` is the
|
|
fastlane zip file containing the meta data for the app.
|
|
|
|
## Manage the Service with systemd
|
|
|
|
We set up the service under the user's control with a per-user systemd instance.
|
|
|
|
Copy `googleplaypublisher-user.sample.service` to `~/.config/systemd/user/googleplaypublisher-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
|
|
|
|
```sh
|
|
systemctl --user start googleplaypublisher-user.service
|
|
```
|
|
|
|
If you want the service to be started automatically, then enable autostart with
|
|
|
|
```sh
|
|
systemctl --user enable googleplaypublisher-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:
|
|
|
|
```sh
|
|
loginctl enable-linger USERNAME
|
|
```
|
|
|
|
For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User.
|
|
|
|
## Trouble Shooting
|
|
|
|
The following lists errors that occurred when trying to publish a new app on Google Play.
|
|
|
|
### Downloading existing metadata fails with `undefined method 'name' for nil:NilClass` in `block in latest_version`
|
|
|
|
This happens if there is no release in the production track. As workaround one can
|
|
create a production release but save it as draft. If you already created a release
|
|
in another track then you can promote this release to the production track. It is
|
|
automatically saved as draft when you promote it.
|
|
|
|
### Uploading metadata fails with `undefined method 'flat_map' for nil:NilClass` in `track_version_codes`
|
|
|
|
This happens if there is no release in the beta (aka Open Testing) track. As workaround one can
|
|
create a beta release but save it as draft. If you already created a release
|
|
in another testing track then you can promote this release to the beta track. It is
|
|
automatically saved as draft when you promote it.
|