Add example of building TDLib for Android.

This commit is contained in:
levlam 2022-08-11 18:18:48 +03:00
parent e7fa6741aa
commit 5479c640fe
7 changed files with 308 additions and 0 deletions

View File

@ -0,0 +1,44 @@
<?php
if ($argc !== 2) {
exit();
}
$file = file_get_contents($argv[1]);
if (strpos($file, 'androidx.annotation.IntDef') !== false) {
exit();
}
$file = str_replace('import androidx.annotation.Nullable;', 'import androidx.annotation.IntDef;'.PHP_EOL.
'import androidx.annotation.Nullable;'.PHP_EOL.
PHP_EOL.
'import java.lang.annotation.Retention;'.PHP_EOL.
'import java.lang.annotation.RetentionPolicy;', $file);
preg_match_all('/public static class ([A-Za-z0-9]+) extends ([A-Za-z0-9]+)/', $file, $matches, PREG_SET_ORDER);
$children = [];
foreach ($matches as $val) {
if ($val[2] === 'Object') {
continue;
}
$children[$val[2]][] = PHP_EOL.' '.$val[1].'.CONSTRUCTOR';
}
$file = preg_replace_callback('/public abstract static class ([A-Za-z0-9]+)(<R extends Object>)? extends Object [{]/',
function ($val) use ($children) {
return $val[0].PHP_EOL.' @Retention(RetentionPolicy.SOURCE)'.PHP_EOL.' @IntDef({'.implode(',', $children[$val[1]]).<<<'EOL'
})
public @interface Constructors {}
/**
* @return identifier uniquely determining type of the object.
*/
@Constructors
@Override
public abstract int getConstructor();
EOL;
},
$file);
file_put_contents($argv[1], $file);

View File

@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 3.4.1 FATAL_ERROR)
project(TdAndroid VERSION 1.0 LANGUAGES CXX)
option(TD_ENABLE_JNI "Enable JNI-compatible TDLib API" ON)
set(TD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
if (CMAKE_CROSSCOMPILING)
set(CMAKE_MODULE_PATH "${TD_DIR}/CMake")
include(TdSetUpCompiler)
td_set_up_compiler()
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -flto=thin -Oz")
list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third-party/openssl/${ANDROID_ARCH_NAME}")
add_subdirectory(${TD_DIR} td)
add_library(tdjni SHARED "${TD_DIR}/example/java/td_jni.cpp")
target_link_libraries(tdjni PRIVATE Td::TdStatic)
target_compile_definitions(tdjni PRIVATE PACKAGE_NAME="org/drinkless/tdlib")
add_custom_command(TARGET tdjni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rename $<TARGET_FILE:tdjni> $<TARGET_FILE:tdjni>.debug
COMMAND ${CMAKE_STRIP} --strip-debug --strip-unneeded $<TARGET_FILE:tdjni>.debug -o $<TARGET_FILE:tdjni>)
else()
add_subdirectory(${TD_DIR} td)
set(TD_API_JAVA_PACKAGE "org/drinkless/tdlib")
set(TD_API_JAVA_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${TD_API_JAVA_PACKAGE}/TdApi.java")
set(TD_API_TLO_PATH "${TD_DIR}/td/generate/auto/tlo/td_api.tlo")
set(TD_API_TL_PATH "${TD_DIR}/td/generate/scheme/td_api.tl")
set(JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH "${TD_DIR}/td/generate/JavadocTlDocumentationGenerator.php")
set(GENERATE_JAVA_CMD td_generate_java_api TdApi ${TD_API_TLO_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${TD_API_JAVA_PACKAGE})
if (PHP_EXECUTABLE)
set(GENERATE_JAVA_CMD ${GENERATE_JAVA_CMD} &&
${PHP_EXECUTABLE} ${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH} ${TD_API_TL_PATH} ${TD_API_JAVA_PATH} androidx.annotation.Nullable @Nullable &&
${PHP_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/AddIntDef.php ${TD_API_JAVA_PATH})
endif()
file(MAKE_DIRECTORY ${TD_API_JAVA_PACKAGE})
add_custom_target(tl_generate_java
COMMAND ${GENERATE_JAVA_CMD}
COMMENT "Generate Java TL source files"
DEPENDS td_generate_java_api tl_generate_tlo ${TD_API_TLO_PATH} ${TD_API_TL_PATH}
)
endif()

18
example/android/README.md Normal file
View File

@ -0,0 +1,18 @@
# TDLib Android example
This is an example of building `TDLib` for Android.
You need a Bash shell on Linux, macOS, or Windows with some common tools, cmake, JDK, PHP, and gperf pre-installed.
## Building TDLib for Android
* Run the script `./check-environment.sh` to check that you have all required Unix tools and Java utilities. If the script exits with an error message, install the missing tool.
* Run the script `./fetch-sdk.sh` to download Android SDK to a local directory.
* Run the script `./build-openssl.sh` to download and build OpenSSL for Android.
* Run the script `./build-tdlib.sh` to build TDLib for Android.
* The built libraries are now located in the `tdlib/libs` directory, corresponding Java code is located in the `tdlib/java` directory, and standalone Java documentation can be found in the `tdlib/javadoc` directory. You can also use archives `tdlib/tdlib.zip` and `tdlib/tdlib-debug.zip`, which contain all aforementioned data.
If you already have installed Android SDK and NDK, you can skip the second step and specify existing Android SDK root path and Android NDK version as parameters to the subsequent scripts. Make sure that the SDK includes android-33 platform.
If you want to update TDLib to a newer version, you need to run only the script `./build-tdlib.sh`.
You can specify different OpenSSL version as a third parameter to the script `./build-openssl.sh`. By default OpenSSL 1.1.1 is used because of much smaller binary footprint then newer OpenSSL versions.

View File

@ -0,0 +1,68 @@
#!/usr/bin/env bash
cd $(dirname $0)
ANDROID_SDK_ROOT=${1:-SDK}
ANDROID_NDK_VERSION=${2:-23.2.8568313}
OPENSSL=${3:-OpenSSL_1_1_1q} # openssl-3.0.5
OPENSSL_INSTALL_DIR="third-party/openssl"
if [ -d "$OPENSSL_INSTALL_DIR" ] ; then
echo "Error: directory $OPENSSL_INSTALL_DIR already exists. Delete it manually to proceed."
exit 1
fi
source ./check-environment.sh
ANDROID_SDK_ROOT="$(cd "$(dirname -- "$ANDROID_SDK_ROOT")" >/dev/null; pwd -P)/$(basename -- "$ANDROID_SDK_ROOT")"
if [[ "$OS_NAME" == "linux" ]] ; then
HOST_ARCH="linux-x86_64"
elif [[ "$OS_NAME" == "mac" ]] ; then
HOST_ARCH="darwin-x86_64"
elif [[ "$OS_NAME" == "win" ]] ; then
HOST_ARCH="windows-x86_64"
else
echo "Error: unsupported OS_NAME."
exit 1
fi
if [ ! -f $OPENSSL.tar.gz ] ; then
echo "Downloading OpenSSL sources..."
$WGET https://github.com/openssl/openssl/archive/refs/tags/$OPENSSL.tar.gz || exit 1
fi
rm -rf ./openssl-$OPENSSL || exit 1
tar xzf $OPENSSL.tar.gz || exit 1
rm $OPENSSL.tar.gz || exit 1
cd openssl-$OPENSSL
export ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION # for OpenSSL 3.0
export ANDROID_NDK_HOME=$ANDROID_NDK_ROOT # for OpenSSL 1.1.1
PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/bin:$PATH
for ARCH in arm64 arm x86_64 x86 ; do
if [[ $ARCH == "x86" ]]; then
./Configure android-x86 no-shared -U__ANDROID_API__ -D__ANDROID_API__=16 || exit 1
elif [[ $ARCH == "x86_64" ]]; then
./Configure android-x86_64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=21 || exit 1
elif [[ $ARCH == "arm" ]]; then
./Configure android-arm no-shared -U__ANDROID_API__ -D__ANDROID_API__=16 -D__ARM_MAX_ARCH__=8 || exit 1
elif [[ $ARCH == "arm64" ]]; then
./Configure android-arm64 no-shared -U__ANDROID_API__ -D__ANDROID_API__=21 || exit 1
fi
sed -i.bak 's/-O3/-O3 -ffunction-sections -fdata-sections/g' Makefile || exit 1
make depend -s || exit 1
make -j4 -s || exit 1
rm -rf ../$OPENSSL_INSTALL_DIR/$ARCH/* || exit 1
mkdir -p ../$OPENSSL_INSTALL_DIR/$ARCH/lib/ || exit 1
cp libcrypto.a libssl.a ../$OPENSSL_INSTALL_DIR/$ARCH/lib/ || exit 1
cp -r include ../$OPENSSL_INSTALL_DIR/$ARCH/ || exit 1
make distclean || exit 1
done
cd ..
rm -rf ./openssl-$OPENSSL || exit 1

57
example/android/build-tdlib.sh Executable file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env bash
cd $(dirname $0)
ANDROID_SDK_ROOT=${1:-SDK}
ANDROID_NDK_VERSION=${2:-23.2.8568313}
source ./check-environment.sh
echo "Downloading annotation Java package..."
rm -rf annotation || exit 1
mkdir -p annotation || exit 1
cd annotation
$WGET https://maven.google.com/androidx/annotation/annotation/1.4.0/annotation-1.4.0.pom || exit 1
$WGET https://maven.google.com/androidx/annotation/annotation/1.4.0/annotation-1.4.0.jar || exit 1
cd ..
echo "Generating TDLib source files..."
mkdir -p build-native || exit 1
cd build-native
cmake .. || exit 1
cmake --build . --target prepare_cross_compiling || exit 1
cmake --build . --target tl_generate_java || exit 1
cd ..
php AddIntDef.php org/drinkless/tdlib/TdApi.java || exit 1
echo "Copying Java source files..."
rm -rf tdlib || exit 1
mkdir -p tdlib/java/org/drinkless/tdlib || exit 1
cp -p {../../example,tdlib}/java/org/drinkless/tdlib/Client.java || exit 1
mv {,tdlib/java/}org/drinkless/tdlib/TdApi.java || exit 1
rm -rf org || exit 1
echo "Generating Javadoc documentation..."
javadoc -d tdlib/javadoc -encoding UTF-8 -charset UTF-8 -bootclasspath $ANDROID_SDK_ROOT/platforms/android-33/android.jar -extdirs annotation -classpath tdlib/java org.drinkless.tdlib || exit 1
rm -rf annotation || exit 1
ANDROID_SDK_ROOT="$(cd "$(dirname -- "$ANDROID_SDK_ROOT")" >/dev/null; pwd -P)/$(basename -- "$ANDROID_SDK_ROOT")"
echo "Building TDLib..."
for ABI in arm64-v8a armeabi-v7a x86_64 x86 ; do
mkdir -p build-$ABI || exit 1
cd build-$ABI
cmake -DCMAKE_TOOLCHAIN_FILE=${ANDROID_SDK_ROOT}/ndk/${ANDROID_NDK_VERSION}/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -GNinja -DANDROID_ABI=${ABI} -DANDROID_PLATFORM=android-16 .. || exit 1
cmake --build . || exit 1
cd ..
mkdir -p tdlib/libs/$ABI/ || exit 1
cp -p build-$ABI/libtd*.so* tdlib/libs/$ABI/ || exit 1
done
echo "Compressing..."
jar -cMf tdlib-debug.zip tdlib || exit 1
rm tdlib/libs/*/*.debug || exit 1
jar -cMf tdlib.zip tdlib || exit 1
mv tdlib.zip tdlib-debug.zip tdlib
echo "Done."

View File

@ -0,0 +1,42 @@
#!/usr/bin/env bash
# The script checks that all needed tools are installed and sets OS_NAME and WGET variables
if [[ "$OSTYPE" == "linux"* ]] ; then
OS_NAME="linux"
elif [[ "$OSTYPE" == "darwin"* ]] ; then
OS_NAME="mac"
elif [[ "$OSTYPE" == "msys" ]] ; then
OS_NAME="win"
else
echo "Error: this script supports only Bash shell on Linux, macOS, or Windows."
exit 1
fi
if which wget >/dev/null 2>&1 ; then
WGET="wget -q"
elif which curl >/dev/null 2>&1 ; then
WGET="curl -sfLO"
else
echo "Error: this script requires either curl or wget tool installed."
exit 1
fi
for TOOL_NAME in cmake gperf jar javadoc make perl php sed tar yes unzip ; do
if ! which "$TOOL_NAME" >/dev/null 2>&1 ; then
echo "Error: this script requires $TOOL_NAME tool installed."
exit 1
fi
done
if [[ $(which make) = *" "* ]] ; then
echo "Error: OpenSSL expects that full path to make tool doesn't contain spaces. Move it to some other place."
fi
if ! perl -MExtUtils::MakeMaker -MLocale::Maketext::Simple -MPod::Usage -e '' >/dev/null 2>&1 ; then
echo "Error: Perl installation is broken."
if [[ "$OSTYPE" == "msys" ]] ; then
echo "For Git Bash you need to manually copy ExtUtils, Locale and Pod modules to /usr/share/perl5/core_perl from any compatible Perl installation."
fi
exit 1
fi

31
example/android/fetch-sdk.sh Executable file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env bash
cd $(dirname $0)
ANDROID_SDK_ROOT=${1:-SDK}
ANDROID_NDK_VERSION=${2:-23.2.8568313}
if [ -d "$ANDROID_SDK_ROOT" ] ; then
echo "Error: directory $ANDROID_SDK_ROOT already exists. Delete it manually to proceed."
exit 1
fi
source ./check-environment.sh
SDKMANAGER="./sdkmanager"
if [[ "$OS_NAME" == "win" ]] ; then
SDKMANAGER="./sdkmanager.bat"
fi
echo "Downloading SDK Manager..."
mkdir -p "$ANDROID_SDK_ROOT" || exit 1
cd "$ANDROID_SDK_ROOT" || exit 1
$WGET "https://dl.google.com/android/repository/commandlinetools-$OS_NAME-8512546_latest.zip" || exit 1
mkdir -p cmdline-tools || exit 1
unzip -qq "commandlinetools-$OS_NAME-8512546_latest.zip" -d cmdline-tools || exit 1
rm "commandlinetools-$OS_NAME-8512546_latest.zip" || exit 1
mv cmdline-tools/* cmdline-tools/latest/ || exit 1
echo "Installing required SDK tools..."
cd cmdline-tools/latest/bin/ || exit 1
yes | $SDKMANAGER --licenses >/dev/null || exit 1
$SDKMANAGER --install "platform-tools" "ndk;$ANDROID_NDK_VERSION" "cmake;3.22.1" "build-tools;33.0.0" "platforms;android-33" > /dev/null || exit 1