├── .github
├── docker_build_image.sh
├── docker_push_image.sh
├── versions.env
└── workflows
│ ├── post_merge_deploy.yml
│ └── pre_merge_checks.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── android_base
├── Dockerfile
├── README.md
└── tools
│ ├── cacerts
│ └── start_emulator.sh
├── android_bazel
├── Dockerfile
└── README.md
├── android_ndk
├── Dockerfile
└── README.md
├── android_studio
├── Dockerfile
├── README.md
├── android_studio_ask_screenshot.png
├── docker_as.sh
├── docker_install.sh
└── setup_container.sh
└── local_build.sh
/.github/docker_build_image.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | docker build ${DOCKER_FILE_PATH} --build-arg IMAGE_VERSION="${IMAGE_VERSION}" --build-arg NDK_VERSION="${NDK_VERSION}" --build-arg BAZELISK_VERSION="${BAZELISK_VERSION}" --compress -t "menny/${IMAGE_NAME}:${IMAGE_VERSION}-raw"
5 |
6 | SQUASH_MSG=""
7 | if [[ "SQUASH" == "${SQUASH_IMAGE}" ]]; then
8 | # Squashing
9 | pip install docker-squash
10 |
11 | echo "** Docker images on machine:"
12 | docker images
13 | echo "******"
14 |
15 | echo "** Docker history for menny/${IMAGE_NAME}:${IMAGE_VERSION}:"
16 | docker history "menny/${IMAGE_NAME}:${IMAGE_VERSION}-raw"
17 | echo "******"
18 |
19 | COMMITS_COUNT="$(docker history menny/${IMAGE_NAME}:${IMAGE_VERSION}-raw | grep 'buildkit.dockerfile' | wc -l)"
20 | IMAGE_SIZE_RAW=$(docker inspect -f "{{ .Size }}" "menny/${IMAGE_NAME}:${IMAGE_VERSION}-raw")
21 | echo "** docker-squash $COMMITS_COUNT layers"
22 | docker-squash -f "$COMMITS_COUNT" -t "menny/${IMAGE_NAME}:${IMAGE_VERSION}" menny/${IMAGE_NAME}:${IMAGE_VERSION}-raw
23 | echo "******"
24 |
25 | echo "** Docker images on machine after squash:"
26 | docker images
27 | echo "******"
28 | SQUASH_MSG=" Layers ${COMMITS_COUNT}. Size before squashing: ${IMAGE_SIZE_RAW}"
29 | else
30 | echo "Skipping squashing"
31 | SQUASH_MSG=" No squash."
32 | docker tag "menny/${IMAGE_NAME}:${IMAGE_VERSION}-raw" "menny/${IMAGE_NAME}:${IMAGE_VERSION}"
33 | fi
34 |
35 | IMAGE_SIZE_RAW=$(docker inspect -f "{{ .Size }}" menny/${IMAGE_NAME}:${IMAGE_VERSION})
36 | IMAGE_SIZE=$(echo $IMAGE_SIZE_RAW | numfmt --to=si)
37 | PREVIOUS_SIZE="$(docker manifest inspect menny/${IMAGE_NAME}:latest | jq -r '.config.size + ([.layers[].size] | add)')"
38 | SIZE_MESSAGE="Image size for \`menny/${IMAGE_NAME}:${IMAGE_VERSION}\` is ${IMAGE_SIZE} (or $IMAGE_SIZE_RAW bytes).${SQUASH_MSG} Previous (compressed) size was ${PREVIOUS_SIZE}."
39 |
40 | echo "${SIZE_MESSAGE}"
41 |
42 | if [[ -n "$GITHUB_COMMENT_URL" ]]; then
43 | JSON_DATA=$(jq --null-input --arg body "${SIZE_MESSAGE}" '{ "body": $body }')
44 | curl -s -X POST \
45 | $GITHUB_COMMENT_URL \
46 | -H "Content-Type: application/json" \
47 | -H "Authorization: token $GITHUB_TOKEN" \
48 | --data "${JSON_DATA}" > /dev/null
49 | fi
50 |
--------------------------------------------------------------------------------
/.github/docker_push_image.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | PREVIOUS_SIZE="$(docker manifest inspect menny/${IMAGE_NAME}:latest | jq -r '.config.size + ([.layers[].size] | add)')"
5 |
6 | docker image tag menny/${IMAGE_NAME}:${IMAGE_VERSION} menny/${IMAGE_NAME}:latest
7 | docker image tag menny/${IMAGE_NAME}:${IMAGE_VERSION} ghcr.io/menny/${IMAGE_NAME}:${IMAGE_VERSION}
8 | docker image tag menny/${IMAGE_NAME}:${IMAGE_VERSION} ghcr.io/menny/${IMAGE_NAME}:latest
9 |
10 | docker push menny/${IMAGE_NAME}:${IMAGE_VERSION}
11 | docker push menny/${IMAGE_NAME}:latest
12 | docker push ghcr.io/menny/${IMAGE_NAME}:${IMAGE_VERSION}
13 | docker push ghcr.io/menny/${IMAGE_NAME}:latest
14 |
15 | # removing to ensure we're pull the right size
16 | docker rmi menny/${IMAGE_NAME}:latest
17 | CURRENT_SIZE="$(docker manifest inspect menny/${IMAGE_NAME}:latest | jq -r '.config.size + ([.layers[].size] | add)')"
18 |
19 | SIZES_MSG="Pushed image 'menny/${IMAGE_NAME}:${IMAGE_VERSION}'. Previous size was ${PREVIOUS_SIZE} and current is ${CURRENT_SIZE}."
20 |
21 | echo "$SIZES_MSG"
22 |
23 | if [[ -n "$GITHUB_COMMENT_URL" ]]; then
24 | JSON_DATA=$(jq --null-input --arg body "${SIZE_MESSAGE}" '{ "body": $body }')
25 | curl -s -X POST \
26 | $GITHUB_COMMENT_URL \
27 | -H "Content-Type: application/json" \
28 | -H "Authorization: token $GITHUB_TOKEN" \
29 | --data "${JSON_DATA}" > /dev/null
30 | fi
31 |
--------------------------------------------------------------------------------
/.github/versions.env:
--------------------------------------------------------------------------------
1 | IMAGE_VERSION=1.21.2
2 | NDK_VERSION=27.2.12479018
3 | BAZELISK_VERSION=v1.24.0
4 |
--------------------------------------------------------------------------------
/.github/workflows/post_merge_deploy.yml:
--------------------------------------------------------------------------------
1 | name: post_merge_deploy
2 | on:
3 | push:
4 | branches:
5 | - main
6 | env:
7 | TERM: dumb
8 | jobs:
9 | build_base:
10 | runs-on: ubuntu-24.04
11 | steps:
12 | - uses: actions/checkout@v3.5.0
13 | - name: Log in to Docker Hub
14 | uses: docker/login-action@v2.1.0
15 | with:
16 | username: ${{ secrets.DOCKER_USER }}
17 | password: ${{ secrets.DOCKER_PASS }}
18 | - name: Log in to the Container registry
19 | uses: docker/login-action@v2.1.0
20 | with:
21 | registry: ghcr.io
22 | username: ${{ github.actor }}
23 | password: ${{ secrets.GITHUB_TOKEN }}
24 | - name: Set versions
25 | uses: tw3lveparsecs/github-actions-set-variables@latest
26 | with:
27 | envFilePath: .github/versions.env
28 | - name: base image
29 | env:
30 | IMAGE_NAME: android_base
31 | DOCKER_FILE_PATH: android_base/.
32 | SQUASH_IMAGE: NO
33 | run: |
34 | ./.github/docker_build_image.sh
35 | ./.github/docker_push_image.sh
36 | - name: generic image
37 | env:
38 | IMAGE_NAME: android
39 | DOCKER_FILE_PATH: .
40 | run: |
41 | ./.github/docker_build_image.sh
42 | ./.github/docker_push_image.sh
43 | build_specialized_images:
44 | strategy:
45 | matrix:
46 | type: [android_ndk, android_bazel]
47 | include:
48 | - type: android_ndk
49 | squash: NO
50 | - type: android_bazel
51 | squash: NO
52 | runs-on: ubuntu-24.04
53 | needs:
54 | - build_base
55 | env:
56 | IMAGE_NAME: ${{ matrix.type }}
57 | DOCKER_FILE_PATH: ${{ matrix.type }}/.
58 | SQUASH_IMAGE: ${{ matrix.squash }}
59 | steps:
60 | - uses: actions/checkout@v3.5.0
61 | - name: Log in to Docker Hub
62 | uses: docker/login-action@v2.1.0
63 | with:
64 | username: ${{ secrets.DOCKER_USER }}
65 | password: ${{ secrets.DOCKER_PASS }}
66 | - name: Log in to the Container registry
67 | uses: docker/login-action@v2.1.0
68 | with:
69 | registry: ghcr.io
70 | username: ${{ github.actor }}
71 | password: ${{ secrets.GITHUB_TOKEN }}
72 | - name: Set versions
73 | uses: tw3lveparsecs/github-actions-set-variables@latest
74 | with:
75 | envFilePath: .github/versions.env
76 | - run: ./.github/docker_build_image.sh
77 | - run: ./.github/docker_push_image.sh
78 | green:
79 | runs-on: ubuntu-24.04
80 | needs:
81 | - build_base
82 | - build_specialized_images
83 | steps:
84 | - name: ready
85 | run: echo "DONE"
86 | tag_at_repo:
87 | runs-on: ubuntu-24.04
88 | needs:
89 | - green
90 | steps:
91 | - uses: actions/checkout@v3.5.0
92 | - name: Set versions
93 | uses: tw3lveparsecs/github-actions-set-variables@latest
94 | with:
95 | envFilePath: .github/versions.env
96 | - uses: avakar/tag-and-release@v1
97 | with:
98 | tag_name: ${{ env.IMAGE_VERSION }}
99 | body: >
100 | **Base**: image with JDK17, Android SDK Manager ([Dockerfile](https://github.com/menny/docker_android/blob/${{ env.IMAGE_VERSION }}/android_base/Dockerfile)):
101 | ```
102 | docker pull ghcr.io/menny/android_base:${{ env.IMAGE_VERSION }}
103 | ```
104 |
105 | **Android**: Base + Build Tools, Platform level 35 ([Dockerfile](https://github.com/menny/docker_android/blob/${{ env.IMAGE_VERSION }}/Dockerfile)):
106 | ```
107 | docker pull ghcr.io/menny/android:${{ env.IMAGE_VERSION }}
108 | ```
109 |
110 | **NDK**: Android + NDK ${{ env.NDK_VERSION }} ([Dockerfile](https://github.com/menny/docker_android/blob/${{ env.IMAGE_VERSION }}/android_ndk/Dockerfile)):
111 | ```
112 | docker pull ghcr.io/menny/android_ndk:${{ env.IMAGE_VERSION }}
113 | ```
114 |
115 | **Bazel**: Android + Bazelisk ${{ env.BAZELISK_VERSION }} and Go ([Dockerfile](https://github.com/menny/docker_android/blob/${{ env.IMAGE_VERSION }}/android_bazel/Dockerfile)):
116 | ```
117 | docker pull ghcr.io/menny/android_bazel:${{ env.IMAGE_VERSION }}
118 | ```
119 |
120 |
121 | env:
122 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
123 |
--------------------------------------------------------------------------------
/.github/workflows/pre_merge_checks.yml:
--------------------------------------------------------------------------------
1 | name: pre_merge_checks
2 | on:
3 | pull_request:
4 | branches:
5 | - '*'
6 |
7 | env:
8 | TERM: dumb
9 | IMAGE_VERSION: 9.99.9
10 | jobs:
11 | sanity:
12 | runs-on: ubuntu-24.04
13 | env:
14 | GITHUB_COMMENT_URL: ${{ github.event.pull_request.comments_url }}
15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
16 | steps:
17 | - uses: actions/checkout@v3.5.0
18 | - name: lint
19 | uses: luke142367/Docker-Lint-Action@v1.1.1
20 | with:
21 | target: Dockerfile android_base/Dockerfile android_bazel/Dockerfile android_ndk/Dockerfile
22 | env:
23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 | - name: Set versions
25 | uses: tw3lveparsecs/github-actions-set-variables@latest
26 | with:
27 | envFilePath: .github/versions.env
28 | - name: Base Android image
29 | env:
30 | SQUASH_IMAGE: SQUASH
31 | run: IMAGE_NAME="android_base" DOCKER_FILE_PATH="android_base/." ./.github/docker_build_image.sh
32 | - name: Android image with some tools
33 | run: IMAGE_NAME="android" DOCKER_FILE_PATH="." ./.github/docker_build_image.sh
34 | - name: Android image with Bazel tools
35 | run: IMAGE_NAME="android_bazel" DOCKER_FILE_PATH="android_bazel/." ./.github/docker_build_image.sh
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG IMAGE_VERSION
2 | FROM menny/android_base:${IMAGE_VERSION}
3 |
4 | ARG IMAGE_VERSION
5 |
6 | LABEL description="A general use Android docker for CI"
7 | LABEL version="${IMAGE_VERSION}"
8 | LABEL maintainer="menny@evendanan.net"
9 |
10 | # Install sdk elements (list from "sdkmanager --list")
11 | RUN sdkmanager "build-tools;35.0.0"
12 |
13 | RUN sdkmanager "platforms;android-35"
14 |
15 | #accepting licenses
16 | RUN yes | sdkmanager --licenses
17 |
18 | RUN sdkmanager --version
19 |
20 | WORKDIR /opt/workspace
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dockerfile for Android CI
2 | Latest release:  [](https://github.com/menny/docker_android/releases)
3 | My general usage Docker images for Android CI.
4 | These images are available in Docker Hub and [ghcr.io](https://github.com/menny?tab=packages&repo_name=docker_android).
5 |
6 | ## Contains:
7 |
8 | * Based on `ubuntu:jammy` 24.04
9 | * with wget, curl, zip, python, pip, git, make, gcc (and other build-essential)
10 | * Corretto JDK17 - https://github.com/corretto/corretto-17/releases
11 | * cmdline tools 16.0
12 | * Platform tools 35.0.0
13 | * Build Tools 35.0.0
14 | * SDK API 35
15 | * Compressed and squashed into one layer (where makes sense).
16 |
17 |
18 | **NOTE:** This image does not contain NDK. You can use [this](https://github.com/menny/docker_android/tree/master/android_ndk) for an image with the latest NDK. Also, check out a _Proof-of-Concept_ [Docker image](https://github.com/menny/docker_android/tree/master/android_studio) that has Android Studio running inside Docker!
19 |
20 | # Other images:
21 |
22 | * An even slimmer [image](android_base/) (without the APIs and Build-Tools).
23 | * Android latest SDK and latest NDK [image](android_ndk/).
24 | * Android latest SDK and latest Bazel [image](android_bazel/).
25 |
26 | ## Accepting licenses
27 | Getting an error when building Android with this Docker image? Something like this:
28 | ```
29 | FAILURE: Build failed with an exception.
30 |
31 | * What went wrong:
32 | A problem occurred configuring project ':app'.
33 | > You have not accepted the license agreements of the following SDK components:
34 | [Android SDK Platform 25, Android SDK Build-Tools 25.0.1].
35 | Before building your project, you need to accept the license agreements and complete the installation of the missing components using the Android Studio SDK Manager.
36 | Alternatively, to learn how to transfer the license agreements from one workstation to another, go to http://d.android.com/r/studio-ui/export-licenses.html
37 | ```
38 | You'll need to create licenses folder with license files under `${ANDROID_HOME}`. Accept the licenses on you local machine
39 | then create the same files inside the Docker image, using your CI script. Something like this:
40 | ```
41 | echo -e "8933bad161af4178b1185d1a37fbf41ea5269c55\c" > ${ANDROID_HOME}/licenses/android-sdk-license
42 | echo -e "79120722343a6f314e0719f863036c702b0e6b2a\n84831b9409646a918e30573bab4c9c91346d8abd\c" > ${ANDROID_HOME}/licenses/android-sdk-preview-license
43 | echo -e "8403addf88ab4874007e1c1e80a0025bf2550a37\c" > ${ANDROID_HOME}/licenses/intel-android-sysimage-license
44 | ```
45 | Also, due to a known [bug](https://code.google.com/p/android/issues/detail?id=2123090), you'll need to run `gradle` twice. So:
46 | ```
47 | ./gradlew dependencies || true
48 | ./gradlew clean
49 | ```
50 |
51 | ## Common commands
52 | Build image: `docker build -t menny/android:latest .`
53 |
54 | Pull from Docker Hub: `docker pull menny/android:latest`
55 |
56 | To run image (and attach to STDIN/STDOUT): `docker run -i -t menny/android:latest`
57 |
58 | ## General Docker commands:
59 | To stop *all* Docker containers: `docker stop $(docker ps -a -q)`
60 |
61 | To remove *all* Docker containers: `docker rm -f $(docker ps -a -q)`
62 |
63 | To remove *all* Docker images: `docker rmi -f $(docker images -q)`
64 |
--------------------------------------------------------------------------------
/android_base/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:jammy@sha256:f470988096c4d77efac9740a1b6700823681af518a17fad30111430b95dfbffa
2 | ARG IMAGE_VERSION
3 |
4 | LABEL description="A general use Android docker for CI"
5 | LABEL version="${IMAGE_VERSION}"
6 | LABEL maintainer="menny@evendanan.net"
7 |
8 | # disable interactive functions
9 | ENV DEBIAN_FRONTEND=noninteractive
10 | ENV TERM=dumb
11 |
12 | # Install Deps and build-essential
13 | RUN apt-get update \
14 | && apt-get install -y --allow-remove-essential --allow-change-held-packages --no-install-recommends \
15 | locales software-properties-common ca-certificates build-essential zlib1g-dev \
16 | pkg-config file \
17 | python3 python3-pip python3-lxml python3-yaml libxml2-utils yamllint \
18 | wget curl nano rsync zip psmisc rsyslog jq unzip \
19 | imagemagick librsvg2-bin \
20 | java-common \
21 | && add-apt-repository ppa:git-core/ppa -y \
22 | && apt-get install git -y --allow-remove-essential --allow-change-held-packages --no-install-recommends \
23 | && apt-get clean \
24 | && rm -rf /var/lib/apt/lists/*
25 |
26 | RUN touch /var/log/kern.log ; chown syslog:adm /var/log/kern.log
27 |
28 | RUN locale-gen en_US.UTF-8
29 | ENV LANG=en_US.UTF-8
30 | ENV LANGUAGE=en_US:en
31 | ENV LC_ALL=en_US.UTF-8
32 |
33 | RUN mkdir -p /opt
34 | WORKDIR /opt
35 | COPY tools /opt/tools
36 | RUN chmod +x /opt/tools/start_emulator.sh
37 |
38 | # Setup environment
39 | ENV ANDROID_HOME=/opt/android-sdk-linux
40 | ENV PATH=${PATH}:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools
41 |
42 | # Setup Java
43 | RUN curl https://corretto.aws/downloads/resources/17.0.10.8.1/java-17-amazon-corretto-jdk_17.0.10.8-1_amd64.deb -o jdk-corretto.deb \
44 | && dpkg --install jdk-corretto.deb \
45 | && rm jdk-corretto.deb
46 |
47 | RUN java -version
48 |
49 | # Install Android SDK
50 | RUN curl https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -o downloaded_sdk.zip \
51 | && mkdir -p /opt/android-sdk-linux/cmdline-tools \
52 | && unzip downloaded_sdk.zip -d /opt/android-sdk-linux/cmdline-tools \
53 | && rm -f downloaded_sdk.zip \
54 | && mv /opt/android-sdk-linux/cmdline-tools/cmdline-tools /opt/android-sdk-linux/cmdline-tools/latest
55 |
56 | #accepting licenses
57 | RUN yes | sdkmanager --licenses
58 |
59 | # Install sdk elements (list from "sdkmanager --list")
60 | RUN sdkmanager --list
61 |
62 | RUN sdkmanager "cmdline-tools;16.0"
63 | RUN sdkmanager "platform-tools"
64 |
65 | #accepting licenses
66 | RUN yes | sdkmanager --licenses
67 |
68 | RUN sdkmanager --version
69 |
70 | # GO to workspace
71 | RUN mkdir -p /opt/workspace
72 | WORKDIR /opt/workspace
73 |
--------------------------------------------------------------------------------
/android_base/README.md:
--------------------------------------------------------------------------------
1 | # Dockerfile for Android CI [](https://circleci.com/gh/menny/docker_android/tree/master)
2 | My general usage (very up-to-date) Docker image for Android CI. Without anything other than the bare SDK.
3 |
4 | ## Contains:
5 |
6 | * Based on `ubuntu:jammy` 22.04
7 | * with wget, curl, zip, python, python3, pip, rsyslog, git, make, gcc (and other build-essential)
8 | * Corretto JDK17 - https://github.com/corretto/corretto-17/releases
9 | * Compressed and squashed into one layer.
10 |
11 | ## Accepting licenses
12 | Getting an error when building Android with this Docker image? Something like this:
13 | ```
14 | FAILURE: Build failed with an exception.
15 |
16 | * What went wrong:
17 | A problem occurred configuring project ':app'.
18 | > You have not accepted the license agreements of the following SDK components:
19 | [Android SDK Platform 25, Android SDK Build-Tools 25.0.1].
20 | Before building your project, you need to accept the license agreements and complete the installation of the missing components using the Android Studio SDK Manager.
21 | Alternatively, to learn how to transfer the license agreements from one workstation to another, go to http://d.android.com/r/studio-ui/export-licenses.html
22 | ```
23 | You'll need to create licenses folder with license files under `${ANDROID_HOME}`. Accept the licenses on you local machine
24 | then create the same files inside the Docker image, using your CI script. Something like this:
25 | ```
26 | echo -e "8933bad161af4178b1185d1a37fbf41ea5269c55\c" > ${ANDROID_HOME}/licenses/android-sdk-license
27 | echo -e "79120722343a6f314e0719f863036c702b0e6b2a\n84831b9409646a918e30573bab4c9c91346d8abd\c" > ${ANDROID_HOME}/licenses/android-sdk-preview-license
28 | echo -e "8403addf88ab4874007e1c1e80a0025bf2550a37\c" > ${ANDROID_HOME}/licenses/intel-android-sysimage-license
29 | ```
30 | Also, due to a known [bug](https://code.google.com/p/android/issues/detail?id=2123090), you'll need to run `gradle` twice. So:
31 | ```
32 | ./gradlew dependencies || true
33 | ./gradlew clean
34 | ```
35 |
36 | ## Common commands
37 | Build image: `docker build -t menny/android_base:latest .`
38 |
39 | Pull from Docker Hub: `docker pull menny/android_base:latest`
40 |
41 | To run image (and attach to STDIN/STDOUT): `docker run -i -t menny/android_base:latest`
42 |
43 | ## General Docker commands:
44 | To stop *all* Docker containers: `docker stop $(docker ps -a -q)`
45 |
46 | To remove *all* Docker containers: `docker rm -f $(docker ps -a -q)`
47 |
48 | To remove *all* Docker images: `docker rmi -f $(docker images -q)`
49 |
--------------------------------------------------------------------------------
/android_base/tools/cacerts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/menny/docker_android/704858e5cdeca23b326f4f2eac917d0c58b2f14a/android_base/tools/cacerts
--------------------------------------------------------------------------------
/android_base/tools/start_emulator.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DEFAULT_API=23
4 | BUILD_TOOLS="23.0.3"
5 |
6 | function print_help_and_exit() {
7 | echo "./start_emulator.sh [options]"
8 | echo "Options:"
9 | echo "--api=[api level] : starts an x86 emulator of a specific API level. Default value is ${DEFAULT_API}."
10 | echo "--tablet : starts an x86 emulator with a Nexus 9 configutation. Default is Nexus 5."
11 | echo "--update : Updates your local SDK. Default is not to update."
12 | echo "--headless : Runs the emulator in a headless (CI) mode. Default is with UI (non-headless)."
13 | exit 0
14 | }
15 |
16 | API=$DEFAULT_API
17 | IS_TABLET=0
18 | UPDATE_SDK=0
19 | HEADLESS=0
20 |
21 | for i in "$@"
22 | do
23 | case $i in
24 | --api=*)
25 | API="${i#*=}"
26 | ;;
27 | --tablet)
28 | IS_TABLET=1
29 | ;;
30 | --help|-h)
31 | print_help_and_exit
32 | ;;
33 | --update_sdk)
34 | UPDATE_SDK=1
35 | ;;
36 | --headless)
37 | HEADLESS=1
38 | ;;
39 | *)
40 | # unknown option
41 | echo "unknown argument ${i}"
42 | print_help_and_exit
43 | ;;
44 | esac
45 | done
46 |
47 | REQUIRED_ADD_ON="addon-google_apis-google-${API}"
48 | REQUIRED_SYS_IMG="sys-img-x86-addon-google_apis-google-${API}"
49 |
50 | TARGET_NAME="Google Inc.:Google APIs:${API}"
51 | TARGET_ID_NUMNER_TEXT=$(android list targets | grep "${TARGET_NAME}" | egrep -o "id: [0-9]+")
52 | if [ -z "${TARGET_ID_NUMNER_TEXT}" ]; then
53 | echo "Could not find System image for API ${API}. Forcing SDK update."
54 | UPDATE_SDK=1
55 | fi
56 |
57 | if [ ${UPDATE_SDK} -eq 1 ]; then
58 | echo "Fetching required SDK packages for emulator with API ${API} and is-tablet=${IS_TABLET}"
59 |
60 | android update sdk --all --no-ui --filter platform-tools,build-tools-${BUILD_TOOLS},extra-intel-Hardware_Accelerated_Execution_Manager,android-${DEFAULT_API},addon-google_apis-google-${DEFAULT_API},${REQUIRED_ADD_ON},extra-android-support,extra-android-m2repository,extra-google-m2repository,extra-google-google_play_services,${REQUIRED_SYS_IMG}
61 | fi
62 |
63 | TARGET_ID_NUMNER_TEXT=$(android list targets | grep "${TARGET_NAME}" | egrep -o "id: [0-9]+")
64 | TARGET_ID_NUMNER=${TARGET_ID_NUMNER_TEXT:4}
65 |
66 | if [ ${IS_TABLET} -eq 1 ]; then
67 | DEV_WIDTH="2048"
68 | DEV_HEIGHT="1536"
69 | DPI="320"
70 | ORIENTATION="landscape"
71 | AVD_NAME="Tablet_${API}"
72 | else
73 | DEV_WIDTH="1080"
74 | DEV_HEIGHT="1900"
75 | ORIENTATION="portrait"
76 | DPI="420"
77 | AVD_NAME="Phone_${API}"
78 | fi
79 |
80 | #checking if we have this emulator already created
81 | if [ -z "$(android list avd -c | grep ${AVD_NAME})" ]; then
82 | echo "Creating emulator with target-id ${TARGET_ID_NUMNER}, API ${API} and is-tablet=${IS_TABLET}"
83 | android create avd --name "${AVD_NAME}" --target ${TARGET_ID_NUMNER} -c 200M -s ${DEV_WIDTH}x${DEV_HEIGHT} --tag google_apis --abi x86
84 | #tweaking
85 | echo "hw.gpu.enabled=yes
86 | hw.gpu.mode=auto
87 | hw.keyboard=yes
88 | hw.lcd.density=420
89 | hw.mainKeys=no
90 | hw.ramSize=1536
91 | hw.sdCard=yes
92 | hw.sensors.orientation=yes
93 | hw.sensors.proximity=yes
94 | hw.lcd.width=${DEV_WIDTH}
95 | hw.lcd.height=${DEV_HEIGHT}
96 | hw.trackBall=no
97 | runtime.network.latency=none
98 | runtime.network.speed=full
99 | runtime.scalefactor=auto
100 | vm.heapSize=64" >> "${HOME}/.android/avd/${AVD_NAME}.avd/config.ini"
101 | fi
102 |
103 | echo "Starting emulator with API ${API} and is-tablet=${IS_TABLET}..."
104 | HEADLESS_ARGS=""
105 | if [ ${HEADLESS} -eq 1 ]; then
106 | echo "Headless mode!"
107 | #-noaudio removed till emulator bug fixed
108 | HEADLESS_ARGS="-no-skin -no-window"
109 | fi
110 | #>/dev/null 2>&1 &
111 | emulator -avd ${AVD_NAME} ${HEADLESS_ARGS}
112 |
--------------------------------------------------------------------------------
/android_bazel/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG IMAGE_VERSION
2 | FROM menny/android:${IMAGE_VERSION}
3 |
4 | ARG IMAGE_VERSION
5 | ARG BAZELISK_VERSION
6 |
7 | LABEL description="A general use Android docker for CI with Bazelisk version ${BAZELISK_VERSION}"
8 | LABEL version="${IMAGE_VERSION}-${BAZELISK_VERSION}"
9 | LABEL maintainer="menny@evendanan.net"
10 |
11 | WORKDIR /opt
12 |
13 | # removing unsupported OpenJDK arg
14 | ENV JAVA_TOOL_OPTIONS=""
15 |
16 | # Install Go (required by Bazelisk)
17 | RUN apt update \
18 | && apt install -y --allow-remove-essential --allow-change-held-packages \
19 | golang \
20 | && apt-get clean \
21 | && rm -rf /var/lib/apt/lists/*
22 |
23 | # Install bazelisk
24 | RUN mkdir /opt/bazelisk
25 | ADD https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-amd64 /opt/bazelisk/
26 | RUN mv /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazelisk
27 | RUN chmod +x /opt/bazelisk/bazelisk
28 | RUN /opt/bazelisk/bazelisk version
29 | RUN ln -s /opt/bazelisk/bazelisk /opt/bazelisk/bazel
30 | ENV PATH ${PATH}:/opt/bazelisk
31 | # this will ensure we installed correctly, and will extract the installation
32 | RUN bazelisk version
33 | RUN bazel version
34 | # GO to workspace
35 | WORKDIR /opt/workspace
36 |
--------------------------------------------------------------------------------
/android_bazel/README.md:
--------------------------------------------------------------------------------
1 | # Dockerfile for Android CI with Bazel [](https://circleci.com/gh/menny/docker_android/tree/master)
2 | My general usage (very up-to-date) Docker image for Android with latest Bazelisk
3 |
4 | ## Contains:
5 |
6 | * All the good staff from the [General Android image](https://github.com/menny/docker_android/blob/master/README.md)
7 | * Go 1.14
8 | * Bazelisk v1.10.1
9 |
10 | ## Accepting licenses
11 | [Read](https://github.com/menny/docker_android/blob/master/README.md#accepting-licenses) about this at the general Android Docker image.
12 |
13 | ## Common commands
14 | Build image: `docker build -t menny/android_bazel:latest .`
15 |
16 | Pull from Docker Hub: `docker pull menny/android_bazel:latest`
--------------------------------------------------------------------------------
/android_ndk/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG IMAGE_VERSION
2 | FROM menny/android:${IMAGE_VERSION}
3 |
4 | ARG IMAGE_VERSION
5 | ARG NDK_VERSION
6 | LABEL description="A general use Android docker for CI with NDK ${NDK_VERSION}"
7 | LABEL version="${IMAGE_VERSION}"
8 | LABEL maintainer="menny@evendanan.net"
9 |
10 | WORKDIR /opt
11 |
12 | # Install Android NDK
13 | RUN sdkmanager "ndk;${NDK_VERSION}"
14 | RUN sdkmanager "cmake;3.31.0"
15 | RUN cat /opt/android-sdk-linux/ndk/${NDK_VERSION}/source.properties
16 |
17 | # GO to workspace
18 | WORKDIR /opt/workspace
19 |
--------------------------------------------------------------------------------
/android_ndk/README.md:
--------------------------------------------------------------------------------
1 | # Dockerfile for Android CI with NDK [](https://circleci.com/gh/menny/docker_android/tree/master)
2 | My general usage (very up-to-date) Docker image for Android with latest NDK
3 |
4 | ## Contains:
5 |
6 | * All the good staff from the [General Android image](https://github.com/menny/docker_android/blob/master/README.md)
7 | * NDK 23.0.7599858
8 |
9 | ## Accepting licenses
10 | [Read](https://github.com/menny/docker_android/blob/master/README.md#accepting-licenses) about this at the general Android Docker image.
11 |
12 | ## Common commands
13 | Build image: `docker build -t menny/android_ndk:latest .`
14 |
15 | Pull from Docker Hub: `docker pull menny/android_ndk:latest`
--------------------------------------------------------------------------------
/android_studio/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM menny/android_ndk:1.8.2
2 |
3 | MAINTAINER Menny Even-Danan "menny@evendanan.net"
4 | LABEL version="1.8.2-3.0.0-RC1"
5 | LABEL description="A Docker image with Android build enviroment and Android Studio"
6 |
7 | WORKDIR /opt
8 |
9 | #ideas taken from https://hub.docker.com/r/dlsniper/docker-intellij/~/dockerfile/
10 |
11 | # Install Android Studio
12 | RUN wget --output-document=android-studio-linux.zip --quiet https://dl.google.com/dl/android/studio/ide-zips/3.0.0.16/android-studio-ide-171.4392136-linux.zip && \
13 | unzip android-studio-linux.zip && \
14 | rm -f android-studio-linux.zip
15 |
16 | #adding adding sources
17 | RUN sdkmanager "sources;android-26"
18 |
19 | # support for X-server
20 | RUN sed 's/main$/main universe/' -i /etc/apt/sources.list && \
21 | apt-get update -qq && \
22 | apt-get install -qq -y --fix-missing software-properties-common git libxext-dev libxrender-dev libxslt1.1 \
23 | libxtst-dev libgtk2.0-0 libcanberra-gtk-module unzip wget && \
24 | apt-get clean -qq -y && \
25 | apt-get autoclean -qq -y && \
26 | apt-get autoremove -qq -y && \
27 | rm -rf /tmp/*
28 |
29 | # Links2 web-browser.
30 | RUN apt-get install -qq -y --fix-missing links2 && \
31 | apt-get clean -qq -y && \
32 | apt-get autoclean -qq -y && \
33 | apt-get autoremove -qq -y && \
34 | rm -rf /tmp/*
35 |
--------------------------------------------------------------------------------
/android_studio/README.md:
--------------------------------------------------------------------------------
1 | # Dockerfile for Android development with NDK and Android Studio
2 | Docker image for desktop development using Android Studio, based on menny/android_ndk image.
3 |
4 | Like this (artifacts only in the screenshot, not in real life):
5 |
6 | 
7 |
8 | ## Contains:
9 |
10 | * All the good staff from the [General Android image](https://github.com/menny/docker_android/blob/master/README.md).
11 | * All the good staff from the [NDK Android image](https://github.com/menny/docker_android/blob/master/android_ndk/README.md).
12 | * Android Studio 3.0.0 RC1.
13 | * API 26 Sources.
14 | * X11 support.
15 | * [Links2](http://links.twibright.com/) - A very basic web-browser.
16 |
17 | ## Accepting licenses
18 | [Read](https://github.com/menny/docker_android/blob/master/README.md#accepting-licenses) about this at the general Android Docker image.
19 |
20 | ## Common Docker commands
21 | Build image: `docker build -t menny/android_studio:latest .`
22 |
23 | Pull from Docker Hub: `docker pull menny/android_studio:latest`
24 |
25 | ## How To Use
26 | To work with the Android Studio inside this Docker image, you'll need to run it and direct its X11 connection to the local (host) machine X-Server.
27 |
28 | _Note:_ The following instructions come from [here](https://fredrikaverpil.github.io/2016/07/31/docker-for-mac-and-gui-applications/) and [here](https://hub.docker.com/r/dlsniper/docker-intellij/).
29 |
30 | I assume you have an X-Server, and it accepts network connections.
31 |
32 | ### Running on Mac
33 | If you have a Mac, you will need to install `xquartz`. Run:
34 | ```
35 | brew cask install xquartz
36 | ```
37 | Start `xquartz`:
38 | ```
39 | open -a XQuartz
40 | ```
41 | And allow network connections in the _Preferences_ window. More details [here](https://fredrikaverpil.github.io/2016/07/31/docker-for-mac-and-gui-applications/).
42 | Add your machine's local IP to `xhost`:
43 | ```
44 | ip=$(ifconfig en0 | grep inet | awk '$1=="inet" {print $2}')
45 | /opt/X11/bin/xhost + $ip
46 | ```
47 | And run Android Studio:
48 | ```
49 | docker run -d -e DISPLAY=$ip:0 -v /tmp/.X11-unix:/tmp/.X11-unix menny/android_studio:1.8.1 /opt/android-studio/bin/studio.sh
50 | ```
51 |
52 | ### Running on Linux -- did not verify
53 | Probably just:
54 | ```
55 | docker run -d -e DISPLAY=$ip:0 -v /tmp/.X11-unix:/tmp/.X11-unix menny/android_studio:1.8.1 /opt/android-studio/bin/studio.sh
56 | ```
57 |
58 | ### Running on Windows
59 | No idea.
60 |
61 | ## Pro Tip
62 | The process above will give you a blank installation of Android Studio. It's a nice PoC, but the downside is that every time you start the Docker image, you start in the same blank state.
63 | My work-flow is as follow:
64 |
65 | 1. Start the Docker image
66 | 2. Installation wizard will come up, follow all steps. Let it download what it needs.
67 | 3. At this point, you might want copy your `id_rsa` keys into the Docker image, that's in case you need those keys for cloning your repo.
68 |
69 | ```
70 | docker exec -it hardcore_meninsky bash
71 | ```
72 |
73 | This will open a `bash` terminal inside the running Docker image (use `docker ps --all` to find the image name, in my example the name was `hardcore_meninsky`). Run these commands:
74 |
75 | ```
76 | mkdir -p /root/.ssh
77 | chmod 0700 /root/.ssh
78 | exit
79 | ```
80 |
81 | Back in the host terminal, copy the ssh keys into the image:
82 |
83 | ```
84 | docker cp ~/.ssh/id_rsa hardcore_meninsky:/root/.ssh/
85 | docker cp ~/.ssh/id_rsa.pub hardcore_meninsky:/root/.ssh/
86 | ```
87 |
88 | 4. Checkout your repo using the _Import from source control_ option.
89 | 5. Once your repo is loaded, setup Android Studio with everything you need (plugins, settings, code style, etc).
90 | 6. You might also want to download the sources for the Android SDK. Maybe compile the app once to make sure everything is fine.
91 | 7. You might also want to setup the `local.properties` file in your checkout repo. Add the SDK and NDK paths:
92 |
93 | ```
94 | ndk.dir=/opt/android-ndk-linux
95 | sdk.dir=/opt/android-sdk-linux
96 | ```
97 |
98 | 8. Quit Android Studio.
99 | 9. In the host machine's terminal run `docker ps --all`. You'll see the Android Studio container (probably the top-most) in exited status. Copy it's name (last column). For example:
100 |
101 | ```
102 | ➜ docker ps --all
103 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
104 | daffb7bbee3f menny/android_studio:1.8.1 "/opt/android-stud..." 21 minutes ago Exited (0) 11 seconds ago hardcore_meninsky
105 | ```
106 |
107 | 10. Commit that container into a new tag (let's say _warm_android_studio_): `docker commit hardcore_meninsky warm_android_studio`. This might take a while.
108 | 11. You're done! Next time, you can run your warm image: `docker run -d -e DISPLAY=$ip:0 -v /tmp/.X11-unix:/tmp/.X11-unix warm_android_studio`
109 | 12. Or you can also start the same container again: `docker start hardcore_meninsky`. This will start the container with all the changes you made.
110 |
111 | ### More Pro Tips
112 |
113 | - You can setup your container with `local.properties` values and copying rsa keys by calling `./setup_container.sh [container name] [repo folder]`.
114 | - You can use the execution script `docker_as.sh`. This script will start a new container from `menny/android_studio`, or restart an already created container.
--------------------------------------------------------------------------------
/android_studio/android_studio_ask_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/menny/docker_android/704858e5cdeca23b326f4f2eac917d0c58b2f14a/android_studio/android_studio_ask_screenshot.png
--------------------------------------------------------------------------------
/android_studio/docker_as.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | if pgrep -x "Docker" > /dev/null
3 | then
4 | echo "Docker ready."
5 | else
6 | echo "Please start Docker and run this again."
7 | exit 1
8 | fi
9 |
10 | if [ "Darwin" == "`uname`" ]
11 | then
12 | if pgrep -x "Xquartz" > /dev/null
13 | then
14 | echo "Quartz ready."
15 | else
16 | echo "Starting Quartz..."
17 | if [ open -a XQuartz ]
18 | then
19 | echo "Done."
20 | else
21 | echo "Failed to start XQuartz. Install via 'brew cask install xquartz'"
22 | exit 1
23 | fi
24 | fi
25 | else
26 | echo "At this moment, this script only supports macOS."
27 | exit 1
28 | fi
29 |
30 | export ip=$(ifconfig en0 | grep inet | awk '$1=="inet" {print $2}')
31 | /opt/X11/bin/xhost + $ip
32 |
33 | if [ "new" == "$1" ]; then
34 | shift # past action
35 |
36 | BASE_RUN_COMMAND="docker run -d --privileged --network=host -e DISPLAY=$ip:0 -v /tmp/.X11-unix:/tmp/.X11-unix "
37 | IMAGE_NAME="menny/android_studio:1.8.2-3.0.0-RC1"
38 | ADDITIONAL_ARGS=""
39 |
40 | while [[ $# -gt 0 ]]
41 | do
42 | key="$1"
43 | case $key in
44 | -i|--image)
45 | IMAGE_NAME="$2"
46 | shift # past argument
47 | shift # past value
48 | if [ "" == "$IMAGE_NAME" ]; then
49 | echo "Please provide an image name to start, or omit the -i argument to use the default."
50 | exit 1
51 | fi
52 | ;;
53 | -a|--docker_args)
54 | ADDITIONAL_ARGS="$2"
55 | shift # past argument
56 | shift # past value
57 | ;;
58 | *) # unknown option
59 | echo "Uknown option '$key' for action 'new'. Valid options:"
60 | echo "-i|--image [image name]"
61 | echo "-a|--docker_args [additional docker args]"
62 | exit 1
63 | ;;
64 | esac
65 | done
66 | ${BASE_RUN_COMMAND} ${ADDITIONAL_ARGS} ${IMAGE_NAME} /opt/android-studio/bin/studio.sh
67 | exit 0
68 | elif [ "start" == "$1" ]; then
69 | if [ "" == "$2" ]; then
70 | echo "Please provide a container to start. Pick one:"
71 | docker ps --all
72 | exit 1
73 | else
74 | docker start $2
75 | docker exec -e DISPLAY=$ip:0 $2 /opt/android-studio/bin/studio.sh
76 | exit 0
77 | fi
78 | else
79 | echo "Unknown action, or none provided. Possible:"
80 | echo "docker_as.sh new -i|--image [image name] -a|--docker_args [additional docker args]"
81 | echo "docker_as.sh start [container name]"
82 | exit 1
83 | fi
84 |
--------------------------------------------------------------------------------
/android_studio/docker_install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | if [ "" == "$1" ]
3 | then
4 | echo "Please provide the container name to setup as the first argument."
5 | docker ps
6 | exit 1
7 | fi
8 |
9 | if [ "" == "$2" ]
10 | then
11 | echo "Please provide the path to the clone folder (for example '/root/StudioProjects/AnySoftKeyboard'."
12 | exit 1
13 | fi
14 |
15 | if pgrep -x "Docker" > /dev/null
16 | then
17 | echo "Docker ready."
18 | else
19 | echo "Please start Docker and run this again."
20 | exit 1
21 | fi
22 |
23 | docker exec -it ${1} bash -c "cd ${2} && ./gradlew :app:assembleDebug"
24 | docker cp ${1}:${2}/app/build/outputs/apk/debug/app-debug.apk ${TMPDIR}/app-debug.apk
25 | adb install -r ${TMPDIR}/app-debug.apk
26 |
--------------------------------------------------------------------------------
/android_studio/setup_container.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | if [ "" == "$1" ]
3 | then
4 | echo "Please provide the container name to setup as the first argument."
5 | docker ps
6 | exit 1
7 | fi
8 |
9 | if [ "" == "$2" ]
10 | then
11 | echo "Please provide the path to the clone folder (for example '/root/StudioProjects/AnySoftKeyboard'."
12 | exit 1
13 | fi
14 |
15 | if pgrep -x "Docker" > /dev/null
16 | then
17 | echo "Docker ready."
18 | else
19 | echo "Please start Docker and run this again."
20 | exit 1
21 | fi
22 |
23 | docker exec -it ${1} mkdir -p /root/.ssh
24 | docker exec -it ${1} chmod 0700 /root/.ssh
25 | docker cp ~/.ssh/id_rsa ${1}:/root/.ssh/
26 | docker cp ~/.ssh/id_rsa.pub ${1}:/root/.ssh/
27 |
28 |
29 | sdk.dir=/opt/android-sdk-linux
30 | docker exec -it ${1} ndk.dir=/opt/android-ndk-linux >> ${2}/local.properties
31 | docker exec -it ${1} sdk.dir=/opt/android-sdk-linux >> ${2}/local.properties
--------------------------------------------------------------------------------
/local_build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | IMAGE_VERSION="$1"
6 | NDK_VERSION="$2"
7 |
8 | if [[ -z "$IMAGE_VERSION" ]]; then
9 | echo "Provide image version as the first argument"
10 | exit 1
11 | fi
12 | if [[ -z "$NDK_VERSION" ]]; then
13 | echo "Provide NDK_VERSION version as the second argument"
14 | exit 1
15 | fi
16 | if [[ -z "$IMAGE_VERSION" ]]; then
17 | echo "Provide image version as the first argument"
18 | exit 1
19 | fi
20 |
21 | function build_image() {
22 | local image_name="$1"
23 | docker build . --build-arg IMAGE_VERSION="${IMAGE_VERSION}" --build-arg NDK_VERSION="${NDK_VERSION}" --compress -t "menny/${image_name}:${IMAGE_VERSION}"
24 | }
25 |
26 | pushd android_base
27 | build_image android_base
28 | popd
29 |
30 | build_image android
31 |
32 | pushd android_ndk
33 | build_image android_ndk
34 | popd
35 |
--------------------------------------------------------------------------------