Tailscale Android Client

repository·main·Indexed 25 days ago

https://github.com/tailscale/tailscale-android

An open-source implementation of the Tailscale service for Android devices providing private WireGuard® networking. This documentation covers building the APK via Android Studio, Docker, or Nix, developing for Fire Stick TV, and using the LocalAPI Client to manage connectivity, login profiles, Taildrop file transfers, and MDM settings.

Tokens
3.5K
Snippets
10
Records
23
Agent score
82%

What's inside tailscale-android

  1. Set up a Nix development environment

    main

    If you have Nix 2.4 or later, you can use a Nix flake to manage the environment. The flake provides Java, make, curl, and git, and uses a repo-local Android SDK located in ./android-sdk.

    Interactive Shell

    To enter the development environment:

    alias nix='nix --extra-experimental-features "nix-command flakes"'
    nix develop

    One-shot Commands

    To run commands without entering an interactive shell:

    nix develop --command make androidsdk
    nix develop --command make tailscale-debug

    Fast Kotlin Iteration

    To iterate on Kotlin code quickly without running the full gomobile bind step:

    nix develop --command bash -lc 'cd android && ./gradlew ktfmtCheck compileDebugKotlin'

    Note: On first use, you must install the Android SDK components via make androidsdk. The resulting debug APK will be written to ./tailscale-debug.apk.

    alias nix='nix --extra-experimental-features "nix-command flakes"'
    nix develop
    
    # Install SDK components
    make androidsdk
    
    # Build debug APK
    make tailscale-debug
  2. Set up a Docker-based build environment

    main

    To build without installing dependencies on your host system, use the provided Docker recipes. You can start an interactive shell with the pre-configured environment using:

    make docker-shell

    Note that Docker recipes preserve the image but remove the container upon completion. If you change the toolchain or build environment, you may need to rebuild the cached images.

    make docker-shell
  3. Build a release

    main

    To prepare a release, use make tag_release. This command performs the following:

    1. Bumps the Android version code.
    2. Updates the version name.
    3. Tags the current commit.

    Go Version Support: The project guarantees support for the latest Go release and any Go beta or release candidate builds (e.g., Go 1.14) in module mode.

    make tag_release
  4. Prepare an Android Studio build environment

    main

    To set up a long-term development environment using Android Studio, follow these steps:

    1. Install Go: Download and install a Go runtime from go.dev.
    2. Install Android Studio: Download from the official site.
    3. Install Command-line Tools: Open Android Studio, go to More Actions > SDK Manager > SDK Tools tab, and install Android SDK Command-line Tools (latest).
    4. Install SDK Components: Run make androidsdk in the repository root.

    Environment Variables and Paths

    • SDK Location: If using a non-standard Android SDK location, set the ANDROID_SDK_ROOT environment variable.
    • Tool Path: If Android Studio tools are not in your system PATH, run make androidpath and export the resulting path to your shell.

    Code Formatting

    Use the ktmft plugin with default settings to autoformat Java, Kotlin, and XML files. It is recommended to enable "Format on Save" in Android Studio.

    make androidsdk
    # To find the tool path:
    make androidpath
  5. Obtain Tailscale Android APKs

    main

    You can download Tailscale APKs through several channels depending on your needs:

    • Stable Releases: Available via the Tailscale Packages Stable Track.
    • Unstable Releases: Available via the Tailscale Packages Unstable Track.
    • Google Play Store: For automatic updates and compact APKs.
    • Amazon Appstore: For Amazon Fire tablets and Fire TV devices.
    • F-Droid: Maintains independently-built APKs from this repository's source code.
  6. Develop on a Fire Stick TV

    main

    To develop on a Fire Stick TV, first enable developer options on the device:

    • Settings > My Fire TV > Developer Options > ADB Debugging > ON.

    Then use the following ADB commands to connect, install, and manage the app:

    # Connect to the device
    adb connect 10.2.200.213:5555
    
    # Install the APK
    adb install -r tailscale-fdroid.apk
    
    # Start the MainActivity
    adb shell am start -n com.tailscale.ipn/com.tailscale.ipn.MainActivity
    
    # Uninstall the app
    adb shell pm uninstall com.tailscale.ipn
    adb connect 10.2.200.213:5555
    adb install -r tailscale-fdroid.apk
    adb shell am start -n com.tailscale.ipn/com.tailscale.ipn.MainActivity
    adb shell pm uninstall com.tailscale.ipn
  7. Understand Tailscale Android connection modes

    main

    The Tailscale Android client uses ConnectionMode to represent the current state of the network connection. This determines how traffic is being routed between nodes. Understanding these modes helps in troubleshooting connectivity issues:

    • NotConnected: The client is not currently connected to the Tailscale network.
    • Derp: The connection is being routed through a DERP (Detoured Encrypted Routing Protocol) relay. This mode includes a relayName identifying the specific relay being used.
    • Direct: A direct peer-to-peer connection has been established between nodes, providing the best performance.
    • PeerRelay: The connection is being routed through another peer in the Tailscale network rather than a DERP relay.
  8. Understand the Health state data model

    main

    The Health.State model represents the current health status of the Tailscale Android client. It contains a map of Warnings, where each key is a WarnableCode (a unique string identifier) and the value is an UnhealthyState object or null if the state is healthy.

    An UnhealthyState describes a specific issue and includes:

    • WarnableCode: The unique identifier for the warning.
    • Severity: The impact level (low, medium, or high).
    • Title: A short summary of the issue.
    • Text: A detailed description.
    • ImpactsConnectivity: A boolean indicating if the issue affects network connectivity.
    • DependsOn: A list of other WarnableCode strings that this issue depends on. If any of these dependency codes are currently present in the active warnings, this state may be considered hiddenByDependencies.
  9. Manage Tailscale login profiles

    main

    The Client allows managing multiple login profiles (e.g., for different tailnets):

    • profiles(responseHandler: (Result<List<IpnLocal.LoginProfile>>) -> Unit): Lists all available login profiles.
    • currentProfile(responseHandler: (Result<IpnLocal.LoginProfile>) -> Unit): Gets the currently active profile.
    • addProfile(responseHandler: (Result<String>) -> Unit): Creates a new profile.
    • deleteProfile(profile: IpnLocal.LoginProfile, responseHandler: (Result<String>) -> Unit): Deletes a specific profile.
    • switchProfile(profile: IpnLocal.LoginProfile, responseHandler: (Result<String>) -> Unit): Switches the active connection to the specified profile.
  10. Define MDM settings using MDMSetting subclasses

    main

    MDM (Mobile Device Management) settings in the Tailscale Android client are defined using the MDMSetting<T> abstraction. These settings can be populated from either an Android Bundle (typically passed via an intent) or from SharedPreferences.

    To implement a specific setting type, use one of the provided subclasses:

    • BooleanMDMSetting: For boolean flags.
    • StringMDMSetting: For nullable strings.
    • StringArrayListMDMSetting: For lists of strings (retrieved as String[] or ArrayList<String> from Bundles, or StringSet from Prefs).
    • AlwaysNeverUserDecidesMDMSetting: For settings using the AlwaysNeverUserDecides enum.
    • ShowHideMDMSetting: For settings using the ShowHide enum.

    Each setting maintains a flow of type MutableStateFlow<SettingState<T>>, which tracks the current value and whether the value isSet (i.e., whether it was explicitly provided in the Bundle or Prefs vs using the defaultValue).

  11. Get Tailscale bug reports and lock status

    main

    Use these methods for diagnostic and security features:

    • bugReportId(responseHandler: BugReportIdHandler): Requests a unique ID for generating a bug report.
    • tailnetLockStatus(responseHandler: TailnetLockStatusResponseHandler): Checks the status of Tailnet Lock (IpnState.NetworkLockStatus).
    • fileTargets(responseHandler: (Result<List<Ipn.FileTarget>>) -> Unit): Retrieves available file targets.