feat: upgrade to maple

In Maple, the plugin API is slightly different: the apk file is built and
stored in the android-app Docker image, then served by a simple Caddy file
server. This makes it easy to distribute the apk to students.
This commit is contained in:
Régis Behmo 2021-11-15 18:00:50 +01:00
parent af495f3e7d
commit e165bf04ea
18 changed files with 102 additions and 93 deletions

View File

@ -2,7 +2,7 @@ variables:
TUTOR_PLUGIN: android
TUTOR_IMAGES: android
TUTOR_PYPI_PACKAGE: tutor-android
OPENEDX_RELEASE: lilac
OPENEDX_RELEASE: maple
GITHUB_REPO: overhangio/tutor-android
include:

View File

@ -13,15 +13,13 @@ Installation
Usage
-----
Enable the plugin::
Enable the plugin and start the platform::
tutor plugins enable android
tutor local quickstart
To build the application in debug mode, run::
tutor android build debug
The ``.apk`` file will then be available in ``$(tutor config printroot)/data/android``. Transfer it to an Android phone to install the application. You should be able to sign in and view available courses.
The ``.apk`` file will then be available for download at http(s)://mobile.LMS_HOST/app.apk. When running locally, this will be: http://mobile.local.overhang.io/app.apk. You can forward this address to your students for download.
Building a custom Android app
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -38,22 +36,23 @@ Releasing an Android app
**Note**: this is an untested feature.
Releasing an Android app on the Play Store requires to build the app in release mode. To do so, edit the ``$TUTOR_ROOT/config.yml`` configuration file and define the following variables::
Releasing an Android app on the Play Store requires to build the app in release mode. To do so, modify the following Tutor settings::
ANDROID_RELEASE_STORE_PASSWORD
ANDROID_RELEASE_KEY_PASSWORD
ANDROID_RELEASE_KEY_ALIAS
tutor config save \
--set ANDROID_RELEASE_STORE_PASSWORD=yourstorepassword \
--set ANDROID_RELEASE_KEY_PASSWORD=yourreleasekeypassword \
--set ANDROID_RELEASE_KEY_ALIAS=yourreleasekeyalias \
--set ANDROID_ENABLE_RELEASE_MODE=true
Then, place your keystore file in ``$(tutor config printroot)/env/plugins/android/apps/app.keystore``. Finally, build the application with::
Then, place your keystore file in ``$(tutor config printroot)/env/plugins/android/build/app/config/app.keystore``. Finally, rebuild the image by starting the "android-app" container::
tutor android build release
tutor local start -d android-app
Customising the Android app
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Customising the application, such as the logo or the background image, is currently not supported. If you are interested by this feature, please tell us about it in the Tutor `discussion forums <https://discuss.overhang.io>`_.
License
-------

View File

@ -39,7 +39,7 @@ setup(
packages=find_packages(exclude=["tests*"]),
include_package_data=True,
python_requires=">=3.5",
install_requires=["tutor>=12.0.0,<13.0.0"],
install_requires=["tutor>=13.0.0,<14.0.0"],
entry_points={
"tutor.plugin.v0": [
"android = tutorandroid.plugin"

View File

@ -1 +1 @@
__version__ = "12.0.1"
__version__ = "13.0.0"

View File

@ -1,51 +0,0 @@
import click
from tutor.commands.context import Context
from tutor.commands.local import LocalJobRunner
from tutor import config as tutor_config
from tutor import env as tutor_env
from tutor import fmt
from tutor.types import Config
@click.group(help="Build an Android app for your Open edX platform")
def android() -> None:
pass
@click.command(help="Build the application")
@click.argument("mode", type=click.Choice(["debug", "release"]))
@click.pass_obj
def build(context: Context, mode: str) -> None:
config = tutor_config.load(context.root)
docker_run(context.root, build_command(config, mode))
fmt.echo_info(
"The {} APK file is available in {}".format(
mode, tutor_env.data_path(context.root, "android")
)
)
def build_command(config: Config, target: str) -> str:
gradle_target = {
"debug": "assembleProdDebuggable",
"release": "assembleProdRelease",
}[target]
apk_folder = {"debug": "debuggable", "release": "release"}[target]
command = """
sed -i "s/APPLICATION_ID = .*/APPLICATION_ID = \\"{{ LMS_HOST|reverse_host|replace("-", "_") }}\\"/g" constants.gradle
./gradlew {gradle_target}
cp OpenEdXMobile/build/outputs/apk/prod/{apk_folder}/*.apk /openedx/data/"""
command = tutor_env.render_str(config, command)
command = command.format(gradle_target=gradle_target, apk_folder=apk_folder)
return command
def docker_run(root: str, command: str) -> None:
config = tutor_config.load(root)
runner = LocalJobRunner(root, config)
runner.run_job("android", command)
android.add_command(build)

View File

@ -0,0 +1,3 @@
{{ ANDROID_APP_HOST }}{$default_site_port} {
import proxy "android-app:8000"
}

View File

@ -0,0 +1,27 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: android-app
labels:
app.kubernetes.io/name: android-app
spec:
selector:
matchLabels:
app.kubernetes.io/name: android-app
template:
metadata:
labels:
app.kubernetes.io/name: android-app
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
containers:
- name: android-app
image: {{ ANDROID_APP_DOCKER_IMAGE }}
imagePullPolicy: Always
ports:
- containerPort: 8000
securityContext:
allowPrivilegeEscalation: false

View File

@ -0,0 +1,12 @@
---
apiVersion: v1
kind: Service
metadata:
name: android-app
spec:
type: NodePort
ports:
- port: 8000
protocol: TCP
selector:
app.kubernetes.io/name: android-app

View File

@ -1,5 +0,0 @@
android-job:
image: {{ ANDROID_DOCKER_IMAGE }}
volumes:
- "../plugins/android/apps:/openedx/config/"
- "../../data/android/:/openedx/data/"

View File

@ -0,0 +1,6 @@
# Android app
android-app:
image: {{ ANDROID_APP_DOCKER_IMAGE }}
build:
context: ../plugins/android/build/app/
restart: unless-stopped

View File

@ -3,7 +3,6 @@ import os
import pkg_resources
from .__about__ import __version__
from .cli import android as android_command
templates = pkg_resources.resource_filename("tutorandroid", "templates")
@ -13,7 +12,11 @@ config = {
"add": {"OAUTH2_SECRET": "{{ 24|random_string }}"},
"defaults": {
"VERSION": __version__,
"APP_HOST": "mobile.{{ LMS_HOST }}",
"APP_VERSION": "2.26.1", # https://github.com/edx/edx-app-android/releases
"DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/openedx-android:{{ ANDROID_VERSION }}",
"APP_DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/openedx-android-app:{{ ANDROID_VERSION }}",
"ENABLE_RELEASE_MODE": False,
"RELEASE_STORE_PASSWORD": "android store password",
"RELEASE_KEY_PASSWORD": "android release key password",
"RELEASE_KEY_ALIAS": "android release key alias",
@ -21,15 +24,15 @@ config = {
}
hooks = {
"build-image": {"android": "{{ ANDROID_DOCKER_IMAGE }}"},
"build-image": {
"android": "{{ ANDROID_DOCKER_IMAGE }}",
"android-app": "{{ ANDROID_APP_DOCKER_IMAGE }}",
},
"remote-image": {"android": "{{ ANDROID_DOCKER_IMAGE }}"},
"init": ["lms"],
}
command = android_command
def patches():
all_patches = {}
patches_dir = pkg_resources.resource_filename("tutorandroid", "patches")

View File

@ -6,35 +6,32 @@ RUN apt update && \
apt upgrade -y && \
apt install -y wget unzip git openjdk-8-jre openjdk-8-jdk
RUN mkdir /openedx
RUN mkdir /app
# Install Android SDK
# Inspired from https://github.com/LiveXP/docker-android-sdk/blob/master/Dockerfile
ENV ANDROID_SDK_VERSION 6200805
ENV ANDROID_SDK_PATH /openedx/android-sdk
ENV ANDROID_HOME /openedx/android-sdk
# Get sdk version from here: https://developer.android.com/studio#command-tools
ENV ANDROID_SDK_VERSION 7583922
ENV ANDROID_SDK_PATH /app/android-sdk
ENV ANDROID_HOME /app/android-sdk
RUN mkdir ${ANDROID_HOME}
WORKDIR /openedx/android-sdk
WORKDIR /app/android-sdk
RUN wget https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip && \
unzip commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip && \
rm commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip
# Accept licenses
# https://developer.android.com/studio/command-line/sdkmanager
ARG ANDROID_API_LEVEL=28
RUN yes | /openedx/android-sdk/tools/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "platforms;android-$ANDROID_API_LEVEL" 1> /dev/null
# Check target version: https://github.com/edx/edx-app-android/blob/master/constants.gradle
ARG ANDROID_API_LEVEL=29
RUN yes | /app/android-sdk/cmdline-tools/bin/sdkmanager --sdk_root=${ANDROID_HOME} --install "platforms;android-$ANDROID_API_LEVEL" 1> /dev/null
# Install android app repo
ARG ANDROID_APP_REPOSITORY=https://github.com/edx/edx-app-android
ARG ANDROID_APP_VERSION=release/2.25.1
RUN git clone $ANDROID_APP_REPOSITORY --branch $ANDROID_APP_VERSION /openedx/edx-app-android
WORKDIR /openedx/edx-app-android
ARG ANDROID_APP_VERSION=release/{{ ANDROID_APP_VERSION }}
RUN git clone $ANDROID_APP_REPOSITORY --branch $ANDROID_APP_VERSION /app/edx-app-android
WORKDIR /app/edx-app-android
# Install gradle and all dependencies
RUN ./gradlew -v
RUN ./gradlew tasks
# User-customized config
COPY ./edx.properties ./OpenEdXMobile/edx.properties
RUN mkdir /openedx/config
RUN ln -s /openedx/config/gradle.properties ./OpenEdXMobile/gradle.properties

View File

@ -1 +0,0 @@
edx.dir = '/openedx/config'

View File

@ -0,0 +1,19 @@
#### Build image with app-specific settings
FROM {{ ANDROID_DOCKER_IMAGE }} as build
# User-customized config
COPY ./config/edx.properties ./OpenEdXMobile/default_config/edx.properties
COPY ./config/tutor.yaml ./OpenEdXMobile/default_config/tutor.yaml
{% if ANDROID_ENABLE_RELEASE_MODE %}
# Add release settings
COPY ./config/gradle.properties ./gradle.properties.tutor
RUN cat ./gradle.properties.tutor >> ./gradle.properties
{% endif %}
RUN sed -i "s/APPLICATION_ID = .*/APPLICATION_ID = \"{{ LMS_HOST|reverse_host|replace("-", "_") }}\"/g" constants.gradle
RUN ./gradlew assembleProd{{ "Release" if ANDROID_ENABLE_RELEASE_MODE else "Debuggable" }}
#### File server to serve apk file
FROM docker.io/caddy:2.4.3-alpine as production
COPY --from=build /app/edx-app-android/OpenEdXMobile/build/outputs/apk/prod/{{ "release" if ANDROID_ENABLE_RELEASE_MODE else "debuggable" }}/edx-{{ "release" if ANDROID_ENABLE_RELEASE_MODE else "debuggable" }}-{{ ANDROID_APP_VERSION }}.apk /srv/app.apk
CMD caddy file-server --listen=:8000 --root=/srv

View File

@ -1,4 +1,4 @@
RELEASE_STORE_FILE=/openedx/config/app.keystore
RELEASE_STORE_FILE=/app/edx-app-android/OpenEdXMobile/app.keystore
RELEASE_STORE_PASSWORD={{ ANDROID_RELEASE_STORE_PASSWORD }}
RELEASE_KEY_PASSWORD={{ ANDROID_RELEASE_KEY_PASSWORD }}
RELEASE_KEY_ALIAS={{ ANDROID_RELEASE_KEY_ALIAS }}