How to cache gradle dependencies in docker when building for android - android

I am trying to build an Android Studio project inside docker using gradle.
Gradle goes through a long process of downloading my dependencies. I would like to cache this step inside docker, so that it is not repeated every time I build.
I am unhappy with the underlying snippet from my Dockerfile (full file below). It requires that I copy my resource directory. Everytime I change a string or a resource, all of my dependencies will be downloaded again! (Because docker cache will be invalidated)
COPY my-android-project/app/src/main/res app/src/main/res
This line will trigger alot of redundant dependency downloads by docker. How can I remove it from my dockerfile? I would appreciate a Dockerfile example with even a trivial "empty activity" Android Studio project...
# https://medium.com/#AndreSand/building-android-with-docker-8dbf717f54d4
FROM gradle:5.4.1-jdk8
USER root
ENV SDK_URL="https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip" \
ANDROID_HOME="/usr/local/android-sdk" \
ANDROID_VERSION=29 \
ANDROID_BUILD_TOOLS_VERSION=29.0.2
# Download Android SDK
RUN mkdir "$ANDROID_HOME" .android \
&& cd "$ANDROID_HOME" \
&& curl -o sdk.zip $SDK_URL \
&& unzip sdk.zip \
&& rm sdk.zip \
&& mkdir "$ANDROID_HOME/licenses" || true \
&& echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_HOME/licenses/android-sdk-license"
# && yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses
# Install Android Build Tool and Libraries
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
"platforms;android-${ANDROID_VERSION}" \
"platform-tools"
# Install Build Essentials
RUN apt-get update && apt-get install build-essential -y && apt-get install file -y && apt-get install apt-utils -y
RUN mkdir my-android-project
WORKDIR my-android-project
# Fix gradle cache directory to work outside of profile (required for docker)
RUN mkdir -p /opt/gradle/.gradle
ENV GRADLE_USER_HOME=/opt/gradle/.gradle
# Cache dependencies so that they are not downloaded every time the code changes
COPY my-android-project/gradle* ./
COPY my-android-project/build.gradle .
COPY my-android-project/settings.gradle .
COPY my-android-project/gradle/ ./gradle/
COPY my-android-project/gradle/ ./gradle/
COPY my-android-project/app/build.gradle app/build.gradle
COPY my-android-project/app/src/main/AndroidManifest.xml app/src/main/AndroidManifest.xml
#
####
# I am unhappy with this, as the dependencies will be downloaded again
# If I change any strings, icons, or IDs inside this folder
# How do I prevent having to copy this folder?
###
#
COPY my-android-project/app/src/main/res app/src/main/res
RUN find
# Running gradle instead of gradlew to prevent redundant update of gradle version
# to save time: if you need another version of gradle, please install it in the docker image prioir to running this line
RUN gradle --no-daemon build
# Build the actual files
COPY my-android-project .
# Running gradle instead of gradlew to prevent redundant update of gradle version
# to save time: if you need another version of gradle, please install it in the docker image prioir to running this line
# --offline to make sure no further dependenies are being downloaded
RUN gradle --no-daemon --offline build

Related

Sending build context to docker daemon becomes greater than 250 gb for android

I am trying to build a docker image for android, below is my docker file
FROM ubuntu:18.04
LABEL maintainer="Javier Santos"
ENV VERSION_SDK_TOOLS "4333796"
ENV ANDROID_HOME "/sdk"
ENV PATH "$PATH:${ANDROID_HOME}/tools"
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -qq update
RUN apt-get install -y locales
RUN locale-gen en_US.UTF-8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
RUN apt-get install -qqy --no-install-recommends \
bzip2 \
curl \
git-core \
html2text \
openjdk-8-jdk \
libc6-i386 \
lib32stdc++6 \
lib32gcc1 \
lib32ncurses5 \
lib32z1 \
unzip \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN rm -f /etc/ssl/certs/java/cacerts; \
/var/lib/dpkg/info/ca-certificates-java.postinst configure
RUN curl -s https://dl.google.com/android/repository/sdk-tools-linux-${VERSION_SDK_TOOLS}.zip > /sdk.zip && \
unzip /sdk.zip -d /sdk && \
rm -v /sdk.zip
RUN mkdir -p $ANDROID_HOME/licenses/ \
&& echo "8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e" > $ANDROID_HOME/licenses/android-sdk-license \
&& echo "84831b9409646a918e30573bab4c9c91346d8abd" > $ANDROID_HOME/licenses/android-sdk-preview-license
RUN yes | $ANDROID_HOME/tools/bin/sdkmanager "platforms;android-28"
ADD packages.txt /sdk
RUN mkdir -p /root/.android && \
touch /root/.android/repositories.cfg && \
${ANDROID_HOME}/tools/bin/sdkmanager --update
RUN while read -r package; do PACKAGES="${PACKAGES}${package} "; done < /sdk/packages.txt && \
${ANDROID_HOME}/tools/bin/sdkmanager ${PACKAGES}
But when I am building this, then Sending build context to Docker daemon is getting larger from 250GB and still increasing, Is this normal, or I am doing something wrong, please suggest, thanks in advance
I have taken reference from this link https://hub.docker.com/r/javiersantos/android-ci
The build context is not inside your Dockerfile, it's the path passed at the end of the build command, often a . to indicate the current directory. When building with compose it defaults to the current directory. So if this is growing, you have files in that context directory that are growing between builds.
With buildkit, this behavior changes, only sending the requested files rather than the full context. You can enable that by running export DOCKER_BUILDKIT=1 in the shell that runs the docker build command. You can also default this feature to enabled by setting the following in /etc/docker/daemon.json and then reloading the docker engine (often systemctl reload docker):
{
"features": {"buildkit": true }
}
Considering your build only adds a single file, probably the best option is to configure a .dockerignore in the root of your context (the same folder with the packages.txt file) with the following:
*
!packages.txt
The * ignores everything, and the !packages.txt reincludes that file back into the context.

dlopen failed for privileged app when upgrade gradle build tools from 3.6.1 to 4.1.0

I have an app which locate in /system/priv-app/MyTestApp.
The android source code environment is Android P (API 28).
At first, the MyTestApp.apk was build with gradle build tools 3.6.1. Then I upgrade it to 4.1.0 and build a new MyTestApp.apk and prebuilt it in the rom. So the crash happens.
E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/priv-app/MyTestApp/MyTestApp.apk!/lib/armeabi-v7a/libmytest.so" not found
E AndroidRuntime: at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
E AndroidRuntime: at java.lang.System.loadLibrary(System.java:1669)
I pull the file /system/priv-app/MyTestApp/MyTestApp.apk, extract the file and found that the libmytest.so exists. It definitely caused by gradle build tools upgrade. But I can't find the reason. Could anyone give some help?
After looking to the source code, I found that in bionic/linker/linker.cpp
if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
close(fd);
return -1;
}
entry.offset % PAGE_SIZE != 0 this condition fails.
So I guess there's something wrong with zipalign of AGP 4.1+.
Still looking into it.
Android build system will uncompress dex files embedded in apk for privileged apps as long as the property DONT_UNCOMPRESS_PRIV_APPS_DEXS not defined. The uncompress definition is as below
# Uncompress dex files embedded in an apk.
#
define uncompress-dexs
$(hide) if (zipinfo $# '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then \
tmpdir=$#.tmpdir; \
rm -rf $$tmpdir && mkdir $$tmpdir; \
unzip -q $# '*.dex' -d $$tmpdir && \
zip -qd $# '*.dex' && \
( cd $$tmpdir && find . -type f | sort | zip -qD -X -0 ../$(notdir $#) -# ) && \
rm -rf $$tmpdir; \
fi
endef
When apk build with AGP 4.0, after uncompress-dexs, it can be success verified by zipalign tool.
zipalign -v -c -p 4 MyTestApp.apk
But when build with AGP 4.1+ (also include 7.0-alpha), it can't be verified by zipalign tool.
But I haven't find the reason yet. Just guess that there is something new change about apk archive in AGP 4.1+.
android.useNewApkCreator=false
Add this line in gradle.properties can solve this issue.
But since AGP 3.6+, the default value of this property is true. So it should not be the difference between AGP 4.0 and AGP 4.1.
I'm so confused. There maybe some else conditions to make effect.
refer to lastest code, the uncompress-dexs method is like below
https://android.googlesource.com/platform/build/+/master/core/definitions.mk#2385
# Uncompress dex files embedded in an apk.
#
define uncompress-dexs
if (zipinfo $# '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then \
$(ZIP2ZIP) -i $# -o $#.tmp -0 "classes*.dex" && \
mv -f $#.tmp $# ; \
fi
endef

How to generate libpjsua2.so for x86 abi in jnilibs

I want to test the app with android 10 in emulator.So for that I only have "armeabi", "armeabi-v7a","arm64-v8a" in jnilibs. But running app with android 10 device(Emulator), requires x86 abi. So for that first I have downloaded ndk for x86.And the second thing is I want to generate libpjsua2.so for x86 abi.
I am using pjsip library.
I have referred to https://trac.pjsip.org/repos/wiki/Getting-Started/Android. What I have tried is,
1) Downloaded latest pjsip version and extracted in folder.
2) Followed the steps given in pjsip website as below,
$ cd /path/to/your/pjsip/dir
$ export ANDROID_NDK_ROOT=/path_to_android_ndk_dir
$ ./configure-android
$ make dep && make clean && make
$ cd /path/to/your/pjsip/dir
$ make clean
# cleanup pjsua sample app
$ cd pjsip-apps/src/pjsua/android/jni
$ make clean
# also cleanup pjsua2 sample app (SWIG)
$ cd /path/to/your/pjsip/dir
$ cd pjsip-apps/src/swig
$ make clean
$ cd pjsip-apps/src/swig
$ make clean
TARGET_ABI=x86 ./configure-android --use-ndk-cflags
Got error when reached above code,
LDFLAGS = --sysroot= -L/libs/x86/
LIBS = -lgnustl_static -lc -lgcc -ldl
AR = /home/Android/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++
RANLIB = /home/Android/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++
TARGET_HOST = llvm-linux-android
TARGET_ABI = x86
checking build system type... x86_64-unknown-linux-gnu
checking host system type... Invalid configuration `llvm-linux-android': machine `llvm' not recognized
aconfigure: error: /bin/sh ./config.sub llvm-linux-android failed
In my pjsip2.7 folder I found a folder named llvm but that is a empty folder. I doesn't know What is that. I am using cent os 7. Why I am getting this error? What do I need to do to overcome this.
Try compile with this builder
replace in ./config.cong you are using 2.10
# PJSIP Version to download
PJSIP_VERSION=2.10
./prepare-build-system
and then
./build

Docker can not find Android SDK and NDK directory

I've created a docker container in order to run my gradle tasks on it.
I'm downloading the sdk inside it, but when I run a task from outside it says that the sdk folder can not be found because it's getting the path I have in the local.properties file of the project. Which is pointing to my machine sdk folder. How can I specify the sdk folder inside the docker image? Thanks.
Docker image build file:
FROM openjdk:8
ENV SDK_URL="https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip" \
ANDROID_HOME="/usr/local/android-sdk" \
ANDROID_NDK_HOME="/usr/local/android-sdk/ndk-bundle" \
ANDROID_VERSION=26 \
ANDROID_BUILD_TOOLS_VERSION=26.0.2
# Download Android SDK
RUN mkdir "$ANDROID_HOME" .android \
&& cd "$ANDROID_HOME" \
&& curl -o sdk.zip $SDK_URL \
&& unzip sdk.zip \
&& rm sdk.zip \
&& yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses
# add to PATH
ENV PATH ${PATH}:${ANDROID_HOME}
ENV ANDROID_NDK_HOME /usr/local/android-ndk
ENV ANDROID_NDK_VERSION r19
ENV NDK_URL="https://dl.google.com/android/repository/android-ndk-${ANDROID_NDK_VERSION}-linux-x86_64.zip"
# Download Android NDK
RUN mkdir "$ANDROID_NDK_HOME" \
&& cd "$ANDROID_NDK_HOME" \
&& curl -o ndk.zip $NDK_URL \
&& unzip ndk.zip \
&& rm ndk.zip
# add to PATH
ENV PATH ${PATH}:${ANDROID_NDK_HOME}
# Install Android Build Tool and Libraries
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
"platforms;android-${ANDROID_VERSION}" \
"platform-tools"
RUN mkdir /application
WORKDIR /application
This is how I run the task:
docker run -it --rm -v "$PWD":/application packsdkandroiddocker.image sh -c "$#" ./gradlew clean
And this is the error I get:
NDK is missing a "platforms" directory. If you are using NDK, verify
the ndk.dir is set to a valid NDK directory. It is currently set to
/Users/adalpari/Library/Android/sdk/ndk-bundle. If you are not using
NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties
to remove this warning.
FAILURE: Build failed with an exception.
What went wrong: A problem occurred configuring project ':app'.
The SDK directory '/Users/adalpari/Library/Android/sdk' does not exist.
I think you need to remove local.properties file from your root folder as SDK is then searched locally which container cannot access.

android jrtplib

jni/jrtplib/include/jrtplib3/rtpsessionsources.h:50: error: non-static reference member 'jrtplib::RTPSession& jrtplib::RTPSessionSources::rtpsession', can't use default assignment operator
link to rtpsessionsource.h
http://research.edm.uhasselt.be/jori/jrtplib/documentation/rtpsessionsources_8h_source.html
anyone, please help me.
All depends on how you wanna to build jrtplib
I see 3 options here
use existing build script from https://github.com/jimjh/JRTPLib-for-Android
because jrtplib based on cmake build system, you can use https://github.com/taka-no-me/android-cmake
write own Android.mk
Personally I used second option and my build script looks like this
#!/bin/bash
LIB=jrtplib-3.9.1
BUILD=$(PWD)/build
CMAKE_TOOLCHAIN=$(PWD)/android-cmake
BUILD_TYPE=Debug
mkdir -p $BUILD/armeabi-v7a
cd $BUILD/armeabi-v7a
cmake -DCMAKE_TOOLCHAIN_FILE=$CMAKE_TOOLCHAIN/android.toolchain.cmake \
-DANDROID_NDK=$ANDROID_NDK_ROOT -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DANDROID_ABI="armeabi-v7a with NEON" \
-DJRTPLIB_COMPILE_STATIC=ON \
$LIB
cmake --build .
cd $ROOT
mkdir -p build/x86
cd $BUILD/x86
cmake -DCMAKE_TOOLCHAIN_FILE=$CMAKE_TOOLCHAIN/android.toolchain.cmake \
-DANDROID_NDK=$ANDROID_NDK_ROOT -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DANDROID_ABI="x86" \
-DJRTPLIB_COMPILE_STATIC=ON \
$LIB
cmake --build .
PS I have build without jthread support

Categories

Resources