Makefile,Dockerfile,README.md: improve build dependency setup and documentation (#114)

- Teach Makefile to install an Android SDK and the components we need
- Make Dockerfile delegate to Makefile for Android SDK setup
- Detect Android Studio and other known SDK paths, and use them if found.
- Update documentation to more consistently point to Android Studio & make.
- Add a task that checks for the SDK components and produces a useful error.
- Build an APK by default.
- Allow TOOLCHAINDIR to be passed in, and strip the first go/ component
  so that it is the path a user would expect.

Updates #cleanup
pull/119/head
James Tucker 10 months ago committed by GitHub
parent 5ca195b109
commit 926613ddae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

4
.gitignore vendored

@ -10,6 +10,10 @@ android/libs
# Output files from the Makefile: # Output files from the Makefile:
tailscale-debug.apk tailscale-debug.apk
tailscale-release.aab tailscale-release.aab
tailscale-fdroid.apk
# Signing key # Signing key
tailscale.jks tailscale.jks
# android sdk dir
./android-sdk

@ -12,26 +12,14 @@ RUN apt-get -y --no-install-recommends install ca-certificates libc6-dev git
RUN apt-get -y install make RUN apt-get -y install make
RUN mkdir -p BUILD RUN mkdir -p build
ENV HOME /build ENV HOME /build
# Get android sdk, ndk, and rest of the stuff needed to build the android app. # Make android sdk location, the later make step will populate it.
WORKDIR $HOME
RUN mkdir android-sdk RUN mkdir android-sdk
ENV ANDROID_HOME $HOME/android-sdk ENV ANDROID_HOME $HOME/android-sdk
WORKDIR $ANDROID_HOME ENV ANDROID_SDK_ROOT $ANDROID_HOME
RUN curl -O https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip
RUN echo 'bd1aa17c7ef10066949c88dc6c9c8d536be27f992a1f3b5a584f9bd2ba5646a0 commandlinetools-linux-9477386_latest.zip' | sha256sum -c
RUN mkdir cmdline-tools && unzip -d cmdline-tools/latest commandlinetools-linux-9477386_latest.zip && mv cmdline-tools/latest/cmdline-tools/* cmdline-tools/latest/
RUN echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --update
RUN echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager 'platforms;android-31'
RUN echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager 'extras;android;m2repository'
RUN echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager 'ndk;23.1.7779620'
RUN echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager 'platform-tools'
RUN echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager 'build-tools;33.0.2'
ENV PATH $PATH:$HOME/bin:$ANDROID_HOME/platform-tools ENV PATH $PATH:$HOME/bin:$ANDROID_HOME/platform-tools
ENV ANDROID_SDK_ROOT /build/android-sdk
# We need some version of Go new enough to support the "embed" package # We need some version of Go new enough to support the "embed" package
# to run "go run tailscale.com/cmd/printdep" to figure out which Tailscale Go # to run "go run tailscale.com/cmd/printdep" to figure out which Tailscale Go
@ -43,6 +31,11 @@ RUN mkdir -p $HOME/tailscale-android
RUN git config --global --add safe.directory $HOME/tailscale-android RUN git config --global --add safe.directory $HOME/tailscale-android
WORKDIR $HOME/tailscale-android WORKDIR $HOME/tailscale-android
# Preload Android SDK
COPY Makefile Makefile
# Get android sdk, ndk, and rest of the stuff needed to build the android app.
RUN make androidsdk
# Preload Gradle # Preload Gradle
COPY android/gradlew android/gradlew COPY android/gradlew android/gradlew
COPY android/gradle android/gradle COPY android/gradle android/gradle

@ -21,15 +21,55 @@ TAILSCALE_COMMIT=$(shell echo $(TAILSCALE_VERSION) | cut -d - -f 2 | cut -d t -f
# Extract the version code from build.gradle. # Extract the version code from build.gradle.
VERSIONCODE=$(lastword $(shell grep versionCode android/build.gradle)) VERSIONCODE=$(lastword $(shell grep versionCode android/build.gradle))
VERSIONCODE_PLUSONE=$(shell expr $(VERSIONCODE) + 1) VERSIONCODE_PLUSONE=$(shell expr $(VERSIONCODE) + 1)
ifeq ($(shell uname),Linux)
ANDROID_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip"
ANDROID_TOOLS_SUM="bd1aa17c7ef10066949c88dc6c9c8d536be27f992a1f3b5a584f9bd2ba5646a0 commandlinetools-linux-9477386_latest.zip"
else
ANDROID_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-mac-9477386_latest.zip"
ANDROID_TOOLS_SUM="2072ffce4f54cdc0e6d2074d2f381e7e579b7d63e915c220b96a7db95b2900ee commandlinetools-mac-9477386_latest.zip"
endif
ANDROID_SDK_PACKAGES='platforms;android-31' 'extras;android;m2repository' 'ndk;23.1.7779620' 'platform-tools' 'build-tools;33.0.2'
# Attempt to find an ANDROID_SDK_ROOT / ANDROID_HOME based either from
# preexisting environment or common locations.
export ANDROID_SDK_ROOT ?= $(shell find $$ANDROID_SDK_ROOT $$ANDROID_HOME $$HOME/Library/Android/sdk $$HOME/Android/Sdk $$HOME/AppData/Local/Android/Sdk /usr/lib/android-sdk -maxdepth 1 -type d 2>/dev/null | head -n 1)
# If ANDROID_SDK_ROOT is still unset, set it to a default location by platform.
ifeq ($(ANDROID_SDK_ROOT),)
ifeq ($(shell uname),Linux)
export ANDROID_SDK_ROOT=$(HOME)/Android/Sdk
else ifeq ($(shell uname),Darwin)
export ANDROID_SDK_ROOT=$(HOME)/Library/Android/sdk
else ifneq ($(WINDIR),))
export ANDROID_SDK_ROOT=$(HOME)/AppData/Local/Android/sdk
else
export ANDROID_SDK_ROOT=$(PWD)/android-sdk
endif
endif
export ANDROID_HOME ?= $(ANDROID_SDK_ROOT)
# Attempt to find Android Studio for Linux configuration, which does not have a
# predetermined location.
ANDROID_STUDIO_ROOT ?= $(shell find ~/android-studio /usr/local/android-studio /opt/android-studio /Applications/Android\ Studio.app $(PROGRAMFILES)/Android/Android\ Studio -type d -maxdepth 1 2>/dev/null | head -n 1)
# Set JAVA_HOME to the Android Studio bundled JDK.
export JAVA_HOME ?= $(shell find $(ANDROID_STUDIO_ROOT)/jre $(ANDROID_STUDIO_ROOT)/jbr $(ANDROID_STUDIO_ROOT)/Contents/jre/Contents/Home -maxdepth 1 -type d 2>/dev/null | head -n 1)
TOOLCHAINREV=$(shell go run tailscale.com/cmd/printdep --go) # Go toolchain path, by default pulled from Tailscale prebuilts pinned to the
TOOLCHAINDIR=${HOME}/.cache/tailscale-android-go-$(TOOLCHAINREV) # version in tailscale.com/cmd/printdep.
TOOLCHAINSUM=$(shell $(TOOLCHAINDIR)/go/bin/go version >/dev/null && echo "okay" || echo "bad") TOOLCHAINDIR ?= ${HOME}/.cache/tailscale-android-go-$(shell go run tailscale.com/cmd/printdep --go)
TOOLCHAINWANT=okay
export PATH := $(TOOLCHAINDIR)/go/bin:$(PATH) export PATH := $(TOOLCHAINDIR)/bin:$(JAVA_HOME)/bin:$(ANDROID_HOME)/cmdline-tools/latest/bin:$(ANDROID_HOME)/platform-tools:$(PATH)
export GOROOT := # Unset export GOROOT := # Unset
all: $(APK) all: $(DEBUG_APK) tailscale-fdroid.apk
env:
@echo PATH=$(PATH)
@echo ANDROID_SDK_ROOT=$(ANDROID_SDK_ROOT)
@echo ANDROID_HOME=$(ANDROID_HOME)
@echo JAVA_HOME=$(JAVA_HOME)
@echo TOOLCHAINDIR=$(TOOLCHAINDIR)
tag_release: tag_release:
sed -i'.bak' 's/versionCode $(VERSIONCODE)/versionCode $(VERSIONCODE_PLUSONE)/' android/build.gradle && rm android/build.gradle.bak sed -i'.bak' 's/versionCode $(VERSIONCODE)/versionCode $(VERSIONCODE_PLUSONE)/' android/build.gradle && rm android/build.gradle.bak
@ -41,41 +81,75 @@ bumposs: toolchain
GOPROXY=direct go get tailscale.com@main GOPROXY=direct go get tailscale.com@main
go mod tidy -compat=1.20 go mod tidy -compat=1.20
toolchain: $(TOOLCHAINDIR)/bin/go:
ifneq ($(TOOLCHAINWANT),$(TOOLCHAINSUM)) @if ! echo $(TOOLCHAINDIR) | grep -q 'tailscale-android-go'; then \
@echo want: $(TOOLCHAINWANT) echo "ERROR: TOOLCHAINDIR=$(TOOLCHAINDIR) is missing bin/go and does not appear to be a tailscale managed path"; \
@echo got: $(TOOLCHAINSUM) exit 1; \
fi
rm -rf ${HOME}/.cache/tailscale-android-go-* rm -rf ${HOME}/.cache/tailscale-android-go-*
mkdir -p $(TOOLCHAINDIR) mkdir -p $(TOOLCHAINDIR)
curl --silent -L $(shell go run tailscale.com/cmd/printdep --go-url) | tar -C $(TOOLCHAINDIR) -zx curl --silent -L $(shell go run tailscale.com/cmd/printdep --go-url) | tar --strip-components=1 -C $(TOOLCHAINDIR) -zx
endif
# Get the commandline tools package, this provides (among other things) the sdkmanager binary.
$(DEBUG_APK): toolchain $(ANDROID_HOME)/cmdline-tools/latest/bin/sdkmanager:
mkdir -p $(ANDROID_HOME)/tmp
mkdir -p $(ANDROID_HOME)/cmdline-tools
(cd $(ANDROID_HOME)/tmp && \
curl --silent -O -L $(ANDROID_TOOLS_URL) && \
echo $(ANDROID_TOOLS_SUM) | sha256sum -c && \
unzip $(shell basename $(ANDROID_TOOLS_URL)))
mv $(ANDROID_HOME)/tmp/cmdline-tools $(ANDROID_HOME)/cmdline-tools/latest
rm -rf $(ANDROID_HOME)/tmp
# Install the set of Android SDK packages we need.
androidsdk: $(ANDROID_HOME)/cmdline-tools/latest/bin/sdkmanager
yes | $(ANDROID_HOME)/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null
$(ANDROID_HOME)/cmdline-tools/latest/bin/sdkmanager --update
$(ANDROID_HOME)/cmdline-tools/latest/bin/sdkmanager $(ANDROID_SDK_PACKAGES)
# Normally in make you would simply take a dependency on the task that provides
# the binaries, however users may have a decision to make as to whether they
# want to install an SDK or use the one from an Android Studio installation.
checkandroidsdk:
@$(ANDROID_HOME)/cmdline-tools/latest/bin/sdkmanager --list_installed | grep -q 'ndk' || (\
echo -e "\n\tERROR: Android SDK not installed.\n\
\tANDROID_HOME=$(ANDROID_HOME)\n\
\tANDROID_SDK_ROOT=$(ANDROID_SDK_ROOT)\n\n\
See README.md for instructions on how to install the prerequisites.\n"; exit 1)
androidpath:
@echo "export ANDROID_HOME=$(ANDROID_HOME)"
@echo "export ANDROID_SDK_ROOT=$(ANDROID_SDK_ROOT)"
@echo 'export PATH=$(ANDROID_HOME)/cmdline-tools/latest/bin:$(ANDROID_HOME)/platform-tools:$$PATH'
toolchain: $(TOOLCHAINDIR)/bin/go
android/libs:
mkdir -p android/libs mkdir -p android/libs
go run gioui.org/cmd/gogio -buildmode archive -target android -appid $(APPID) -tags novulkan,tailscale_go -o $(AAR) github.com/tailscale/tailscale-android/cmd/tailscale
$(AAR): toolchain checkandroidsdk android/libs
go run gioui.org/cmd/gogio \
-ldflags "-X tailscale.com/version.longStamp=$(VERSIONNAME) -X tailscale.com/version.shortStamp=$(VERSIONNAME_SHORT) -X tailscale.com/version.gitCommitStamp=$(TAILSCALE_COMMIT) -X tailscale.com/version.extraGitCommitStamp=$(OUR_VERSION)" \
-buildmode archive -target android -appid $(APPID) -tags novulkan,tailscale_go -o $@ github.com/tailscale/tailscale-android/cmd/tailscale
# tailscale-debug.apk builds a debuggable APK with the Google Play SDK.
$(DEBUG_APK): $(AAR)
(cd android && ./gradlew test assemblePlayDebug) (cd android && ./gradlew test assemblePlayDebug)
mv android/build/outputs/apk/play/debug/android-play-debug.apk $@ mv android/build/outputs/apk/play/debug/android-play-debug.apk $@
rundebug: $(DEBUG_APK) apk: $(DEBUG_APK)
adb install -r $(DEBUG_APK)
run: install
adb shell am start -n com.tailscale.ipn/com.tailscale.ipn.IPNActivity adb shell am start -n com.tailscale.ipn/com.tailscale.ipn.IPNActivity
# tailscale-fdroid.apk builds a non-Google Play SDK, without the Google bits. # tailscale-fdroid.apk builds a non-Google Play SDK, without the Google bits.
# This is effectively what the F-Droid build definition produces. # This is effectively what the F-Droid build definition produces.
# This is useful for testing on e.g. Amazon Fire Stick devices. # This is useful for testing on e.g. Amazon Fire Stick devices.
tailscale-fdroid.apk: toolchain tailscale-fdroid.apk: $(AAR)
mkdir -p android/libs
go run gioui.org/cmd/gogio -buildmode archive -target android -appid $(APPID) -tags novulkan,tailscale_go -o $(AAR) github.com/tailscale/tailscale-android/cmd/tailscale
(cd android && ./gradlew test assembleFdroidDebug) (cd android && ./gradlew test assembleFdroidDebug)
mv android/build/outputs/apk/fdroid/debug/android-fdroid-debug.apk $@ mv android/build/outputs/apk/fdroid/debug/android-fdroid-debug.apk $@
# This target is also used by the F-Droid builder. $(RELEASE_AAB): $(AAR)
release_aar: toolchain
release_aar:
mkdir -p android/libs
go run gioui.org/cmd/gogio -ldflags "-X tailscale.com/version.longStamp=$(VERSIONNAME) -X tailscale.com/version.shortStamp=$(VERSIONNAME_SHORT) -X tailscale.com/version.gitCommitStamp=$(TAILSCALE_COMMIT) -X tailscale.com/version.extraGitCommitStamp=$(OUR_VERSION)" -buildmode archive -target android -appid $(APPID) -tags novulkan,tailscale_go -o $(AAR) github.com/tailscale/tailscale-android/cmd/tailscale
$(RELEASE_AAB): release_aar
(cd android && ./gradlew test bundlePlayRelease) (cd android && ./gradlew test bundlePlayRelease)
mv ./android/build/outputs/bundle/playRelease/android-play-release.aab $@ mv ./android/build/outputs/bundle/playRelease/android-play-release.aab $@
@ -90,6 +164,7 @@ dockershell:
docker run -v $(CURDIR):/build/tailscale-android -it --rm tailscale-android docker run -v $(CURDIR):/build/tailscale-android -it --rm tailscale-android
clean: clean:
rm -rf android/build $(RELEASE_AAB) $(DEBUG_APK) $(AAR) -rm -rf android/build $(DEBUG_APK) $(RELEASE_AAB) $(AAR) tailscale-fdroid.apk
-pkill -f gradle
.PHONY: all clean install $(DEBUG_APK) $(RELEASE_AAB) release_aar release bump_version dockershell .PHONY: all clean install android/lib $(DEBUG_APK) $(RELEASE_AAB) $(AAR) release bump_version dockershell

@ -17,33 +17,63 @@ This repository contains the open source Tailscale Android client.
alt="Get it on Google Play" alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=com.tailscale.ipn) height="80">](https://play.google.com/store/apps/details?id=com.tailscale.ipn)
## Building
[Go](https://golang.org), the [Android ## Preparing a build environment
SDK](https://developer.android.com/studio/releases/platform-tools),
the [Android NDK](https://developer.android.com/ndk) are required. There are several options for setting up a build environment. The Android Studio
path is the most useful path for longer term development.
In all cases you will need:
- Go runtime
- Android SDK
- Android SDK components (`make androidsdk` will install them)
### Android Studio
1. Install a Go runtime (https://go.dev/dl/).
2. Install Android Studio (https://developer.android.com/studio).
3. Start Android Studio, from the Welcome screen select "More Actions" and "SDK Manager".
4. In the SDK manager, select the "SDK Tools" tab and install the "Android SDK Command-line Tools (latest)".
3. Run `make androidsdk` to install the necessary SDK components.
If you would prefer to avoid Android Studio, you can also install an Android
SDK. The makefile detects common paths, so `sudo apt install android-sdk` is
sufficient on Debian / Ubuntu systems. To use an Android SDK installed in a
non-standard location, set the `ANDROID_SDK_ROOT` environment variable to the
path to the SDK.
If you installed Android Studio the tools may not be in your path. To get the
correct tool path, run `make androidpath` and export the provided path in your
shell.
### Docker
If you wish to avoid installing software on your host system, a Docker based development strategy is available, you can build and start a shell with:
```sh ```sh
$ make tailscale-debug.apk make dockershell
$ adb install -r tailscale-debug.apk
``` ```
The `dockershell` target builds a container with the necessary ### Nix
dependencies and runs a shell inside it.
If you have Nix 2.4 or later installed, a Nix development environment can
be set up with:
```sh ```sh
$ make dockershell alias nix='nix --extra-experimental-features "nix-command flakes"'
# make tailscale-debug.apk nix develop
``` ```
If you have Nix 2.4 or later installed, a Nix development environment can ## Building
be set up with
```sh ```sh
$ alias nix='nix --extra-experimental-features "nix-command flakes"' make apk
$ nix develop make install
``` ```
## Building a release
Use `make tag_release` to bump the Android version code, update the version Use `make tag_release` to bump the Android version code, update the version
name, and tag the current commit. name, and tag the current commit.
@ -52,6 +82,7 @@ release candidate builds (currently Go 1.14) in module mode. It might
work in earlier Go versions or in GOPATH mode, but we're making no work in earlier Go versions or in GOPATH mode, but we're making no
effort to keep those working. effort to keep those working.
## Google Sign-In ## Google Sign-In
Google Sign-In support relies on configuring a [Google API Console Google Sign-In support relies on configuring a [Google API Console
@ -97,20 +128,6 @@ adb shell am start -n com.tailscale.ipn/com.tailscale.ipn.IPNActivity
adb shell pm uninstall com.tailscale.ipn adb shell pm uninstall com.tailscale.ipn
``` ```
## Building on macOS
To build from the CLI on macOS:
1. Install Android Studio (when asked which SDKs to install, choose 31 or the current value of targetSdkVersion in `build.gradle`)
2. In Android Studio's home screen: "More Actions" > "SDK Manager", install NDK.
3. You can now close Android Studio, unless you want it to create virtual devices
("More Actions" > "Virtual Device Manager").
4. Then, from CLI:
5. `export JAVA_HOME='/Applications/Android Studio.app/Contents/jbr/Contents/Home'`
6. `export ANDROID_SDK_ROOT=$HOME/Library/Android/sdk`
7. `export PATH=$ANDROID_SDK_ROOT/platform-tools:$PATH` (to allow `adb` and the like to work)
8. `make tailscale-fdroid.apk`, etc
## Bugs ## Bugs
Please file any issues about this code or the hosted service on Please file any issues about this code or the hosted service on

Loading…
Cancel
Save