diff --git a/.clang-format-ignore b/.clang-format-ignore
index 97e66e0aa..52ac9b665 100644
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -7,6 +7,9 @@ cmake-build-*/*
libtransmission/version.h
web/node_modules/*
+# android
+android/*
+
# third-party maintained projects
third-party/*
diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml
index a2590a2d8..e0945a780 100644
--- a/.github/workflows/actions.yml
+++ b/.github/workflows/actions.yml
@@ -12,6 +12,7 @@ jobs:
what-to-make:
runs-on: ubuntu-22.04
outputs:
+ make-android: ${{ steps.check-main-push.outputs.is-main-push == '1' || steps.check-diffs.outputs.android-changed == '1' }}
make-cli: ${{ steps.check-main-push.outputs.is-main-push == '1' || steps.check-diffs.outputs.cli-changed == '1' }}
make-daemon: ${{ steps.check-main-push.outputs.is-main-push == '1' || steps.check-diffs.outputs.daemon-changed == '1' }}
make-dist: ${{ steps.check-main-push.outputs.is-main-push == '1' || steps.check-diffs.outputs.dist-changed == '1' }}
@@ -53,6 +54,7 @@ jobs:
git diff --exit-code "$MERGE_BASE" -- "$@"
echo "$name-changed=$?" >> "$GITHUB_OUTPUT"
}
+ get_changes android CMakeLists.txt cmake third-party libtransmission android
get_changes cli CMakeLists.txt cmake Transmission.xcodeproj third-party libtransmission cli
get_changes any-code CMakeLists.txt cmake Transmission.xcodeproj libtransmission cli daemon gtk macosx qt utils tests web third-party
get_changes our-code CMakeLists.txt cmake Transmission.xcodeproj libtransmission cli daemon gtk macosx qt utils tests web
@@ -793,3 +795,53 @@ jobs:
with:
name: binaries-${{ github.job }}
path: pfx/**/*
+
+ android:
+ needs: [ what-to-make ]
+ if: ${{ needs.what-to-make.outputs.make-android == 'true' }}
+ runs-on: ubuntu-22.04
+ env:
+ VCPKG_DEFAULT_TRIPLET: arm64-android
+ steps:
+ - name: Get Dependencies
+ run: |
+ set -ex
+ sudo apt-get update
+ sudo apt-get install -y --no-install-recommends \
+ ninja-build
+
+ - name: Get Source
+ uses: actions/checkout@v3
+ with:
+ submodules: recursive
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: Setup Gradle
+ uses: gradle/gradle-build-action@v2
+ with:
+ gradle-version: 7.6
+
+ - name: Setup Android SDK
+ uses: android-actions/setup-android@v3
+
+ - name: Install NDK
+ run: sdkmanager "ndk;26.1.10909125"
+
+ - name: Setup vcpkg
+ uses: lukka/run-vcpkg@v11
+ with:
+ vcpkgGitCommitId: 53bef8994c541b6561884a8395ea35715ece75db # 2024.01.12
+
+ - name: Install vcpkg packages
+ run: |
+ vcpkg install openssl curl
+
+ - name: Build Transmission
+ working-directory: ./android
+ run: |
+ gradle build
diff --git a/.gitignore b/.gitignore
index fa2bc39f9..ef369248b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,9 @@ node_modules/
/third-party/miniupnp/miniupnpcstrings.h
/third-party/suffixes_dafsa.h
/web/public_html/transmission-app.js.map
+/android/.cxx
+/android/.gradle
+/android/build
# clangd compile commands
compile_commands.json
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 339260cc7..fda16eeac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,6 +18,10 @@ if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
FORCE)
endif()
+if(VCPKG_TARGET_ANDROID)
+ include(cmake/VcpkgAndroid.cmake)
+endif()
+
project(transmission)
set(TR_THIRD_PARTY_DIR_NAME third-party)
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 000000000..04fd2e2ca
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,69 @@
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath "com.android.tools.build:gradle:7.2.1"
+ }
+}
+
+apply plugin: "com.android.library"
+
+
+def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
+
+def getExtOrDefault(name) {
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["Transmission_" + name]
+}
+
+def getExtOrIntegerDefault(name) {
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Transmission_" + name]).toInteger()
+}
+
+android {
+ ndkVersion getExtOrDefault("ndkVersion")
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
+
+ defaultConfig {
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
+ externalNativeBuild {
+ cmake {
+ abiFilters "arm64-v8a"
+ arguments "-DVCPKG_TARGET_ANDROID=ON", "-DWITH_CRYPTO=openssl"
+ }
+ }
+ }
+ externalNativeBuild {
+ cmake {
+ version "3.22.1"
+ path "../CMakeLists.txt"
+ }
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ }
+ }
+
+ lintOptions {
+ disable "GradleCompatible"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ buildFeatures {
+ prefab true
+ }
+}
+
+repositories {
+ mavenCentral()
+ google()
+}
+
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 000000000..a450253b4
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,6 @@
+Transmission_kotlinVersion=1.7.0
+# quotactl is defined from >= 26
+Transmission_minSdkVersion=26
+Transmission_targetSdkVersion=31
+Transmission_compileSdkVersion=31
+Transmission_ndkVersion=26.1.10909125
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..42defb2ac
--- /dev/null
+++ b/android/src/main/AndroidManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/cmake/TrMacros.cmake b/cmake/TrMacros.cmake
index fc914c708..797b655b5 100644
--- a/cmake/TrMacros.cmake
+++ b/cmake/TrMacros.cmake
@@ -159,6 +159,7 @@ macro(tr_add_external_auto_library ID DIRNAME LIBNAME)
set(${ID}_LIBRARIES ${${ID}_LIBRARY})
set(${ID}_EXT_PROJ_CMAKE_ARGS)
+
if(APPLE)
string(REPLACE ";" "$" ${ID}_CMAKE_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}")
list(APPEND ${ID}_EXT_PROJ_CMAKE_ARGS
@@ -167,6 +168,21 @@ macro(tr_add_external_auto_library ID DIRNAME LIBNAME)
"-DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT}")
endif()
+ if(ANDROID)
+ list(APPEND ${ID}_EXT_PROJ_CMAKE_ARGS
+ "-DANDROID_PLATFORM=${ANDROID_PLATFORM}"
+ "-DANDROID_NDK=${ANDROID_NDK}"
+ "-DANDROID_ABI=${ANDROID_ABI}"
+ "-DANDROID_STL=${ANDROID_STL}"
+ "-DCMAKE_ANDROID_NDK=${CMAKE_ANDROID_NDK}"
+ "-DCMAKE_ANDROID_ARCH_ABI=${CMAKE_ANDROID_ARCH_ABI}")
+ endif()
+
+ if(VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
+ list(APPEND ${ID}_EXT_PROJ_CMAKE_ARGS
+ "-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
+ endif()
+
ExternalProject_Add(
${${ID}_UPSTREAM_TARGET}
PREFIX "${TR_THIRD_PARTY_BINARY_DIR}/${DIRNAME}.bld"
diff --git a/cmake/VcpkgAndroid.cmake b/cmake/VcpkgAndroid.cmake
new file mode 100644
index 000000000..02e47599b
--- /dev/null
+++ b/cmake/VcpkgAndroid.cmake
@@ -0,0 +1,100 @@
+# Copied from https://github.com/microsoft/vcpkg-docs/blob/main/vcpkg/examples/vcpkg_android_example_cmake_script/cmake/vcpkg_android.cmake
+#
+# vcpkg_android.cmake
+#
+# Helper script when using vcpkg with cmake. It should be triggered via the variable VCPKG_TARGET_ANDROID
+#
+# For example:
+# if (VCPKG_TARGET_ANDROID)
+# include("cmake/vcpkg_android.cmake")
+# endif()
+#
+# This script will:
+# 1 & 2. check the presence of needed env variables: ANDROID_NDK_HOME and VCPKG_ROOT
+# 3. set VCPKG_TARGET_TRIPLET according to ANDROID_ABI
+# 4. Combine vcpkg and Android toolchains by setting CMAKE_TOOLCHAIN_FILE
+# and VCPKG_CHAINLOAD_TOOLCHAIN_FILE
+
+# Note: VCPKG_TARGET_ANDROID is not an official vcpkg variable.
+# it is introduced for the need of this script
+
+if (VCPKG_TARGET_ANDROID)
+
+ #
+ # 1. Check the presence of environment variable ANDROID_NDK_HOME
+ #
+ if (NOT DEFINED ENV{ANDROID_NDK_HOME})
+ message(FATAL_ERROR "
+ Please set an environment variable ANDROID_NDK_HOME
+ For example:
+ export ANDROID_NDK_HOME=/home/your-account/Android/Sdk/ndk-bundle
+ Or:
+ export ANDROID_NDK_HOME=/home/your-account/Android/android-ndk-r21b
+ ")
+ endif()
+
+ #
+ # 2. Check the presence of environment variable VCPKG_ROOT
+ #
+ if (NOT DEFINED ENV{VCPKG_ROOT})
+ message(FATAL_ERROR "
+ Please set an environment variable VCPKG_ROOT
+ For example:
+ export VCPKG_ROOT=/path/to/vcpkg
+ ")
+ endif()
+
+
+ #
+ # 3. Set VCPKG_TARGET_TRIPLET according to ANDROID_ABI
+ #
+ # There are four different Android ABI, each of which maps to
+ # a vcpkg triplet. The following table outlines the mapping from vcpkg architectures to android architectures
+ #
+ # |VCPKG_TARGET_TRIPLET | ANDROID_ABI |
+ # |---------------------------|----------------------|
+ # |arm64-android | arm64-v8a |
+ # |arm-android | armeabi-v7a |
+ # |x64-android | x86_64 |
+ # |x86-android | x86 |
+ #
+ # The variable must be stored in the cache in order to successfully the two toolchains.
+ #
+ if (ANDROID_ABI MATCHES "arm64-v8a")
+ set(VCPKG_TARGET_TRIPLET "arm64-android" CACHE STRING "" FORCE)
+ elseif(ANDROID_ABI MATCHES "armeabi-v7a")
+ set(VCPKG_TARGET_TRIPLET "arm-android" CACHE STRING "" FORCE)
+ elseif(ANDROID_ABI MATCHES "x86_64")
+ set(VCPKG_TARGET_TRIPLET "x64-android" CACHE STRING "" FORCE)
+ elseif(ANDROID_ABI MATCHES "x86")
+ set(VCPKG_TARGET_TRIPLET "x86-android" CACHE STRING "" FORCE)
+ else()
+ message(FATAL_ERROR "
+ Please specify ANDROID_ABI
+ For example
+ cmake ... -DANDROID_ABI=armeabi-v7a
+
+ Possible ABIs are: arm64-v8a, armeabi-v7a, x64-android, x86-android
+ ")
+ endif()
+ message("vcpkg_android.cmake: VCPKG_TARGET_TRIPLET was set to ${VCPKG_TARGET_TRIPLET}")
+
+
+ #
+ # 4. Combine vcpkg and Android toolchains
+ #
+
+ # vcpkg and android both provide dedicated toolchains:
+ #
+ # vcpkg_toolchain_file=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
+ # android_toolchain_file=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake
+ #
+ # When using vcpkg, the vcpkg toolchain shall be specified first.
+ # However, vcpkg provides a way to preload and additional toolchain,
+ # with the VCPKG_CHAINLOAD_TOOLCHAIN_FILE option.
+ set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE $ENV{ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake)
+ set(CMAKE_TOOLCHAIN_FILE $ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
+ message("vcpkg_android.cmake: CMAKE_TOOLCHAIN_FILE was set to ${CMAKE_TOOLCHAIN_FILE}")
+ message("vcpkg_android.cmake: VCPKG_CHAINLOAD_TOOLCHAIN_FILE was set to ${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
+
+endif(VCPKG_TARGET_ANDROID)
diff --git a/libtransmission/CMakeLists.txt b/libtransmission/CMakeLists.txt
index 639974f02..c7192d62d 100644
--- a/libtransmission/CMakeLists.txt
+++ b/libtransmission/CMakeLists.txt
@@ -271,6 +271,10 @@ target_include_directories(${TR_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_BINARY_DIR}/..)
+if(ANDROID)
+ find_library(log-lib log)
+endif()
+
target_link_libraries(${TR_NAME}
PRIVATE
Threads::Threads
@@ -295,6 +299,7 @@ target_link_libraries(${TR_NAME}
$<$:crypt32>
$<$:shlwapi>
"$<$:-framework Foundation>"
+ "$<$:${log-lib}>"
PUBLIC
fmt::fmt-header-only
small::small
diff --git a/libtransmission/file-capacity.cc b/libtransmission/file-capacity.cc
index 326b318c5..2afdbfcf2 100644
--- a/libtransmission/file-capacity.cc
+++ b/libtransmission/file-capacity.cc
@@ -30,6 +30,9 @@
#else
#include /* quotactl() */
#endif
+#if !defined(btodb) && defined(QIF_DQBLKSIZE_BITS)
+#define btodb(num) ((num) >> QIF_DQBLKSIZE_BITS)
+#endif
#ifdef HAVE_GETMNTENT
#ifdef __sun
#include