#!/bin/bash # This is intended to be run within a opengisch/qfield-sdk docker container. # # docker run -v $(pwd):/usr/src/qfield opengisch/qfield-sdk /usr/src/qfield/scripts/docker-build.sh # # The result will be put into `build-docker/android-build/build/outputs/apk/out-debug.apk` # # # ANDROID_NDK_PLATFORM and QT_VERSION are defined in docker-qt-crystax # # APK_VERSION_CODE (MMmmFFNNA: major,minor,fix,number,architecture_index, e.g. 010203040 from v1.2.3-rc4 arm7) is required. # APP_VERSION (e.g. v1.2.3, v1.2.3-rc4) is needed when a new version is published. # APP_VERSION_STR ("v1.2.3 - Release Name", v1.2.3-rc4, PR1234, master-dev) is required. Human readable name. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" source ${DIR}/version_number.sh set -e if [[ -z $APK_VERSION_CODE ]]; then echo "*** ERROR MISSING APK_VERSION_CODE ENVIRONMENT VARIABLE" exit 2 fi if [[ -z $APP_VERSION_STR ]]; then echo "*** ERROR MISSING APP_VERSION_STR" exit 2 fi if [[ $( echo "${APK_VERSION_CODE} > 030000000" | bc ) == 1 ]]; then echo "*** ERROR TOO BIG VERSION CODE ${APK_VERSION_CODE}" echo "Remove this check if QField is now 2.x" exit 1 fi SOURCE_DIR=/usr/src/qfield if [[ -z ${BUILD_FOLDER+x} ]]; then BUILD_DIR=${SOURCE_DIR}/build-docker else BUILD_DIR=${SOURCE_DIR}/${BUILD_FOLDER} fi # Set default values if missing [[ -z ${ARCH} ]] && ARCH=armv7 [[ -z ${APP_NAME} ]] && APP_NAME="QField" [[ -z ${APP_PACKAGE_NAME} ]] && APP_PACKAGE_NAME="qfield" INSTALL_DIR=${BUILD_DIR}/out QT_ANDROID=${QT_ANDROID_BASE}/android echo "Package name ${APP_PACKAGE_NAME}" echo "ANDROID_MINIMUM_PLATFORM: ${ANDROID_MINIMUM_PLATFORM}" echo "ANDROID_TARGET_PLATFORM: ${ANDROID_TARGET_PLATFORM}" if [[ -n ${APP_ICON} ]]; then # replace icon echo "Replacing icon with ${APP_ICON}" sed -i "s|icons/qfield_logo.svg|icons/${APP_ICON}.svg|" ${SOURCE_DIR}/images/images.qrc sed -i "s|@drawable/qfield_logo|@drawable/${APP_ICON}|g" ${SOURCE_DIR}/android/res/layout/unpacking_dialog.xml sed -i "s|@drawable/qfield_logo|@drawable/${APP_ICON}|g" ${SOURCE_DIR}/cmake/AndroidManifest.xml.in sed -i "s|@drawable/qfield_logo|@drawable/${APP_ICON}|g" ${SOURCE_DIR}/android/src/ch/opengis/qfield/QFieldProjectActivity.java fi if [[ "X${APP_PACKAGE_NAME}" != "Xqfield" ]]; then grep "ch.opengis.qfield" -l -r ${SOURCE_DIR}/android/ | xargs sed -i "s/ch.opengis.qfield/ch.opengis.${APP_PACKAGE_NAME}/g" grep "ch\.opengis\.qfield" -l -r ${SOURCE_DIR}/src/ | xargs sed -i "s/ch\.opengis\.qfield/ch.opengis.${APP_PACKAGE_NAME}/g" sed -i "s/ch_opengis_qfield/ch_opengis_${APP_PACKAGE_NAME//_/_1}/g" ${SOURCE_DIR}/src/core/platforms/android/androidplatformutilities.cpp mv ${SOURCE_DIR}/android/src/ch/opengis/qfield ${SOURCE_DIR}/android/src/ch/opengis/${APP_PACKAGE_NAME} sed -i "s|QField|${APP_NAME}|" ${SOURCE_DIR}/android/res/values/strings.xml fi mkdir -p ${BUILD_DIR}/.gradle # androiddeployqt needs gradle and downloads it to /root/.gradle. By linking it to the build folder, this will be cached between builds. ln -sfn ${BUILD_DIR}/.gradle $HOME/.gradle pushd ${BUILD_DIR} if [ "X${ARCH}" == "Xx86" ]; then export ANDROID_ARCH=x86 export SHORTARCH=x86 elif [ "X${ARCH}" == "Xarmv7" ]; then export ANDROID_ARCH=armeabi-v7a export SHORTARCH=arm elif [ "X${ARCH}" == "Xarm64_v8a" ]; then export ANDROID_ARCH=arm64-v8a export SHORTARCH=arm64 elif [ "X${ARCH}" == "Xx86_64" ]; then export ANDROID_ARCH=x86_64 export SHORTARCH=x86_64 else echo "Error: Please report issue to enable support for arch (${ARCH})." exit 1 fi export STAGE_PATH=/home/osgeo4a/${ANDROID_ARCH} export ANDROID_CMAKE_LINKER_FLAGS="-fuse-ld=lld" cmake \ -G Ninja \ -DAPK_VERSION_CODE=${APK_VERSION_CODE} \ -DAPP_VERSION=${APP_VERSION} \ -DAPP_VERSION_STR=${APP_VERSION_STR} \ -DAPP_PACKAGE_NAME=${APP_PACKAGE_NAME} \ -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} \ -DQt5_DIR:PATH=${QT_ANDROID_BASE}/android/lib/cmake/Qt5 \ -DANDROID_DEPLOY_QT=${QT_ANDROID_BASE}/android/bin/androiddeployqt \ -DCMAKE_FIND_ROOT_PATH:PATH=${ANDROID_NDK_ROOT}\;${QT_ANDROID_BASE}/android/\;/home/osgeo4a/${ANDROID_ARCH} \ -DANDROID_LINKER_FLAGS="${ANDROID_CMAKE_LINKER_FLAGS}" \ -DANDROID_ABI=${ANDROID_ARCH} \ -DANDROID_BUILD_ABI_${ANDROID_ARCH}=ON \ -DQGIS_CORE_LIBRARY=/home/osgeo4a/${ANDROID_ARCH}/lib/libqgis_core_${ANDROID_ARCH}.so \ -DQGIS_ANALYSIS_LIBRARY=/home/osgeo4a/${ANDROID_ARCH}/lib/libqgis_analysis_${ANDROID_ARCH}.so \ -DQGIS_INCLUDE_DIR=/home/osgeo4a/${ANDROID_ARCH}/include/qgis/ \ -DSQLITE3_INCLUDE_DIR:PATH=/home/osgeo4a/${ANDROID_ARCH}/include/ \ -DOSGEO4A_STAGE_DIR:PATH=/home/osgeo4a/ \ -DANDROID_SDK=${ANDROID_SDK_ROOT}/ \ -DANDROID_NDK=${ANDROID_NDK_ROOT}/ \ -DANDROID_STL:STRING=c++_shared \ -DANDROID_PLATFORM=${ANDROID_MINIMUM_PLATFORM} \ `# This one is for NDK -> we need to link against the minimum supported version` \ -DANDROID_TARGET_PLATFORM=${ANDROID_TARGET_PLATFORM} \ `# This one is for the APK, it ends up in the AndroidManifest.xml` \ -DENABLE_TESTS=OFF \ .. ninja # Patch the input file for androiddeployqt with the build tools revision # See https://forum.qt.io/topic/112578/unable-to-sign-android-app-wrong-path-for-zipalign # Temporary workaround (fingers crossed) cat <<< "$(jq ". += { \"sdkBuildToolsRevision\" : \"29.0.2\" }" < android_deployment_settings.json)" > android_deployment_settings_patched.json if [ -n "${KEYNAME}" ] && [ -n "${KEYPASS}" ] && [ -n "${STOREPASS}" ]; then ${QT_ANDROID}/bin/androiddeployqt \ --sign ${SOURCE_DIR}/keystore.p12 "${KEYNAME}" \ --storepass "${STOREPASS}" \ --keypass "${KEYPASS}" \ --input ${BUILD_DIR}/android_deployment_settings_patched.json \ --output ${BUILD_DIR}/android-build \ --deployment bundled \ --android-platform android-${ANDROID_TARGET_PLATFORM} \ --gradle else echo "-- Not signing the apk, KEYNAME, KEYPASS or STOREPASS is not set" ${QT_ANDROID}/bin/androiddeployqt \ --input ${BUILD_DIR}/android_deployment_settings_patched.json \ --output ${BUILD_DIR}/android-build \ --deployment bundled \ --android-platform android-${ANDROID_TARGET_PLATFORM} \ --gradle fi popd