build_fdroid.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. #!/bin/bash
  2. set -x
  3. #
  4. # Script to build F-Droid release of RustDesk
  5. #
  6. # Copyright (C) 2024, The RustDesk Authors
  7. # 2024, Vasyl Gello <vasek.gello@gmail.com>
  8. #
  9. # The script is invoked by F-Droid builder system ste-by-step.
  10. #
  11. # It accepts the following arguments:
  12. #
  13. # - versionName from https://github.com/rustdesk/rustdesk/releases/download/fdroid-version/rustdesk-version.txt
  14. # - versionCode from https://github.com/rustdesk/rustdesk/releases/download/fdroid-version/rustdesk-version.txt
  15. # - Android architecture to build APK for: armeabi-v7a arm64-v8av x86 x86_64
  16. # - The build step to execute:
  17. #
  18. # + sudo-deps: as root, install needed Debian packages into builder VM
  19. # + prebuild: patch sources and do other stuff before the build
  20. # + build: perform actual build of APK file
  21. #
  22. # Parse command-line arguments
  23. VERNAME="${1}"
  24. VERCODE="${2}"
  25. ANDROID_ABI="${3}"
  26. BUILDSTEP="${4}"
  27. if [ -z "${VERNAME}" ] || [ -z "${VERCODE}" ] || [ -z "${ANDROID_ABI}" ] ||
  28. [ -z "${BUILDSTEP}" ]; then
  29. echo "ERROR: Command-line arguments are all required to be non-empty!" >&2
  30. exit 1
  31. fi
  32. # Set various architecture-specific identifiers
  33. case "${ANDROID_ABI}" in
  34. arm64-v8a)
  35. FLUTTER_TARGET=android-arm64
  36. NDK_TARGET=aarch64-linux-android
  37. RUST_TARGET=aarch64-linux-android
  38. RUSTDESK_FEATURES='flutter,hwcodec'
  39. ;;
  40. armeabi-v7a)
  41. FLUTTER_TARGET=android-arm
  42. NDK_TARGET=arm-linux-androideabi
  43. RUST_TARGET=armv7-linux-androideabi
  44. RUSTDESK_FEATURES='flutter,hwcodec'
  45. ;;
  46. x86_64)
  47. FLUTTER_TARGET=android-x64
  48. NDK_TARGET=x86_64-linux-android
  49. RUST_TARGET=x86_64-linux-android
  50. RUSTDESK_FEATURES='flutter'
  51. ;;
  52. x86)
  53. FLUTTER_TARGET=android-x86
  54. NDK_TARGET=i686-linux-android
  55. RUST_TARGET=i686-linux-android
  56. RUSTDESK_FEATURES='flutter'
  57. ;;
  58. *)
  59. echo "ERROR: Unknown Android ABI '${ANDROID_ABI}'!" >&2
  60. exit 1
  61. ;;
  62. esac
  63. # Check ANDROID_SDK_ROOT and sdkmanager present on PATH
  64. if [ ! -d "${ANDROID_SDK_ROOT}" ] || ! command -v sdkmanager 1>/dev/null; then
  65. echo "ERROR: Can not find Android SDK!" >&2
  66. exit 1
  67. fi
  68. # Export necessary variables
  69. export PATH="${PATH}:${HOME}/flutter/bin:${HOME}/depot_tools"
  70. export VCPKG_ROOT="${HOME}/vcpkg"
  71. # Now act depending on build step
  72. # NOTE: F-Droid maintainers require explicit declaration of dependencies
  73. # as root via `Builds.sudo` F-Droid metadata directive:
  74. # https://gitlab.com/fdroid/fdroiddata/-/merge_requests/15343#note_1988918695
  75. case "${BUILDSTEP}" in
  76. prebuild)
  77. # prebuild: patch sources and do other stuff before the build
  78. #
  79. # Extract required versions for NDK, Rust, Flutter from
  80. # '.github/workflows/flutter-build.yml'
  81. #
  82. CARGO_NDK_VERSION="$(yq -r \
  83. .env.CARGO_NDK_VERSION \
  84. .github/workflows/flutter-build.yml)"
  85. FLUTTER_VERSION="$(yq -r \
  86. .env.ANDROID_FLUTTER_VERSION \
  87. .github/workflows/flutter-build.yml)"
  88. if [ -z "${FLUTTER_VERSION}" ]; then
  89. FLUTTER_VERSION="$(yq -r \
  90. .env.FLUTTER_VERSION \
  91. .github/workflows/flutter-build.yml)"
  92. fi
  93. FLUTTER_RUST_BRIDGE_VERSION="$(yq -r \
  94. .env.FLUTTER_RUST_BRIDGE_VERSION \
  95. .github/workflows/flutter-build.yml)"
  96. NDK_VERSION="$(yq -r \
  97. .env.NDK_VERSION \
  98. .github/workflows/flutter-build.yml)"
  99. RUST_VERSION="$(yq -r \
  100. .env.RUST_VERSION \
  101. .github/workflows/flutter-build.yml)"
  102. VCPKG_COMMIT_ID="$(yq -r \
  103. .env.VCPKG_COMMIT_ID \
  104. .github/workflows/flutter-build.yml)"
  105. if [ -z "${CARGO_NDK_VERSION}" ] || [ -z "${FLUTTER_VERSION}" ] ||
  106. [ -z "${FLUTTER_RUST_BRIDGE_VERSION}" ] ||
  107. [ -z "${NDK_VERSION}" ] || [ -z "${RUST_VERSION}" ] ||
  108. [ -z "${VCPKG_COMMIT_ID}" ]; then
  109. echo "ERROR: Can not identify all required versions!" >&2
  110. exit 1
  111. fi
  112. # Map NDK version to revision
  113. NDK_VERSION="$(wget \
  114. -qO- \
  115. -H "Accept: application/vnd.github+json" \
  116. -H "X-GitHub-Api-Version: 2022-11-28" \
  117. 'https://api.github.com/repos/android/ndk/releases' |
  118. jq -r ".[] | select(.tag_name == \"${NDK_VERSION}\") | .body | match(\"ndkVersion \\\"(.*)\\\"\").captures[0].string")"
  119. if [ -z "${NDK_VERSION}" ]; then
  120. echo "ERROR: Can not map Android NDK codename to revision!" >&2
  121. exit 1
  122. fi
  123. export ANDROID_NDK_HOME="${ANDROID_SDK_ROOT}/ndk/${NDK_VERSION}"
  124. export ANDROID_NDK_ROOT="${ANDROID_SDK_ROOT}/ndk/${NDK_VERSION}"
  125. #
  126. # Install the components
  127. #
  128. set -e
  129. # Install Android NDK
  130. if [ ! -d "${ANDROID_NDK_ROOT}" ]; then
  131. sdkmanager --install "ndk;${NDK_VERSION}"
  132. fi
  133. # Install Flutter
  134. if [ ! -f "${HOME}/flutter/bin/flutter" ]; then
  135. pushd "${HOME}"
  136. git clone https://github.com/flutter/flutter
  137. pushd flutter
  138. git reset --hard "${FLUTTER_VERSION}"
  139. flutter config --no-analytics
  140. popd # flutter
  141. popd # ${HOME}
  142. fi
  143. # Install Rust
  144. if [ ! -f "${HOME}/rustup/rustup-init.sh" ]; then
  145. pushd "${HOME}"
  146. git clone --depth 1 https://github.com/rust-lang/rustup
  147. popd # ${HOME}
  148. fi
  149. pushd "${HOME}/rustup"
  150. bash rustup-init.sh -y \
  151. --target "${RUST_TARGET}" \
  152. --default-toolchain "${RUST_VERSION}"
  153. popd
  154. if ! command -v cargo 1>/dev/null 2>&1; then
  155. . "${HOME}/.cargo/env"
  156. fi
  157. # Install cargo-ndk
  158. cargo install \
  159. cargo-ndk \
  160. --version "${CARGO_NDK_VERSION}"
  161. # Install rust bridge generator
  162. cargo install cargo-expand
  163. cargo install flutter_rust_bridge_codegen \
  164. --version "${FLUTTER_RUST_BRIDGE_VERSION}" \
  165. --features "uuid"
  166. # Populate native vcpkg dependencies
  167. if [ ! -d "${VCPKG_ROOT}" ]; then
  168. pushd "${HOME}"
  169. git clone \
  170. https://github.com/Microsoft/vcpkg.git
  171. git clone \
  172. https://github.com/Microsoft/vcpkg-tool.git
  173. pushd vcpkg-tool
  174. mkdir build
  175. pushd build
  176. cmake \
  177. -DCMAKE_BUILD_TYPE=Release \
  178. -G 'Ninja' \
  179. -DVCPKG_DEVELOPMENT_WARNINGS=OFF \
  180. ..
  181. cmake --build .
  182. popd # build
  183. popd # vcpkg-tool
  184. pushd vcpkg
  185. git reset --hard "${VCPKG_COMMIT_ID}"
  186. cp -a ../vcpkg-tool/build/vcpkg vcpkg
  187. # disable telemetry
  188. touch "vcpkg.disable-metrics"
  189. popd # vcpkg
  190. popd # ${HOME}
  191. fi
  192. # Install depot-tools for x86
  193. if [ "${ANDROID_ABI}" = "x86" ]; then
  194. if [ ! -d "${HOME}/depot_tools" ]; then
  195. pushd "${HOME}"
  196. git clone \
  197. --depth 1 \
  198. https://chromium.googlesource.com/chromium/tools/depot_tools.git
  199. popd # ${HOME}
  200. fi
  201. fi
  202. # Patch the RustDesk sources
  203. git apply res/fdroid/patches/*.patch
  204. sed \
  205. -i \
  206. -e '/gms/d' \
  207. flutter/android/build.gradle \
  208. flutter/android/app/build.gradle
  209. sed \
  210. -i \
  211. -e '/firebase_analytics/d' \
  212. flutter/pubspec.yaml
  213. sed \
  214. -i \
  215. -e '/ firebase/,/ version/d' \
  216. flutter/pubspec.lock
  217. sed \
  218. -i \
  219. -e '/firebase/Id' \
  220. flutter/lib/main.dart
  221. if [ "${FLUTTER_VERSION}" = "3.13.9" ]; then
  222. # Fix for android 3.13.9
  223. # https://github.com/rustdesk/rustdesk/blob/285e974d1a52c891d5fcc28e963d724e085558bc/.github/workflows/flutter-build.yml#L862
  224. sed \
  225. -i \
  226. -e 's/extended_text: .*/extended_text: 11.1.0/' \
  227. -e 's/uni_links_desktop/#uni_links_desktop/g' \
  228. flutter/pubspec.yaml
  229. set --
  230. while read -r _1; do
  231. set -- "$@" "${_1}"
  232. done 0<<.a
  233. $(find flutter/lib/ -type f -name "*dart*")
  234. .a
  235. sed \
  236. -i \
  237. -e 's/textScaler: TextScaler.linear(\(.*\)),/textScaleFactor: \1,/g' \
  238. "$@"
  239. set --
  240. fi
  241. sed -i "s/FLUTTER_VERSION_PLACEHOLDER/${FLUTTER_VERSION}/" flutter-sdk/.gclient
  242. ;;
  243. build)
  244. # build: perform actual build of APK file
  245. set -e
  246. #
  247. # Extract required versions for NDK, Rust, Flutter from
  248. # '.github/workflows/flutter-build.yml'
  249. #
  250. FLUTTER_VERSION="$(yq -r \
  251. .env.ANDROID_FLUTTER_VERSION \
  252. .github/workflows/flutter-build.yml)"
  253. if [ -z "${FLUTTER_VERSION}" ]; then
  254. FLUTTER_VERSION="$(yq -r \
  255. .env.FLUTTER_VERSION \
  256. .github/workflows/flutter-build.yml)"
  257. fi
  258. NDK_VERSION="$(yq -r \
  259. .env.NDK_VERSION \
  260. .github/workflows/flutter-build.yml)"
  261. # Map NDK version to revision
  262. NDK_VERSION="$(wget \
  263. -qO- \
  264. -H "Accept: application/vnd.github+json" \
  265. -H "X-GitHub-Api-Version: 2022-11-28" \
  266. 'https://api.github.com/repos/android/ndk/releases' |
  267. jq -r ".[] | select(.tag_name == \"${NDK_VERSION}\") | .body | match(\"ndkVersion \\\"(.*)\\\"\").captures[0].string")"
  268. if [ -z "${NDK_VERSION}" ]; then
  269. echo "ERROR: Can not map Android NDK codename to revision!" >&2
  270. exit 1
  271. fi
  272. export ANDROID_NDK_HOME="${ANDROID_SDK_ROOT}/ndk/${NDK_VERSION}"
  273. export ANDROID_NDK_ROOT="${ANDROID_SDK_ROOT}/ndk/${NDK_VERSION}"
  274. if ! command -v cargo 1>/dev/null 2>&1; then
  275. . "${HOME}/.cargo/env"
  276. fi
  277. # Download Flutter dependencies
  278. pushd flutter
  279. flutter packages pub get
  280. popd # flutter
  281. # Generate FFI bindings
  282. flutter_rust_bridge_codegen \
  283. --rust-input ./src/flutter_ffi.rs \
  284. --dart-output ./flutter/lib/generated_bridge.dart
  285. # Build host android deps
  286. bash flutter/build_android_deps.sh "${ANDROID_ABI}"
  287. # Build rustdesk lib
  288. cargo ndk \
  289. --platform 21 \
  290. --target "${RUST_TARGET}" \
  291. --bindgen \
  292. build \
  293. --release \
  294. --features "${RUSTDESK_FEATURES}"
  295. mkdir -p "flutter/android/app/src/main/jniLibs/${ANDROID_ABI}"
  296. cp "target/${RUST_TARGET}/release/liblibrustdesk.so" \
  297. "flutter/android/app/src/main/jniLibs/${ANDROID_ABI}/librustdesk.so"
  298. cp "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/${NDK_TARGET}/libc++_shared.so" \
  299. "flutter/android/app/src/main/jniLibs/${ANDROID_ABI}/"
  300. "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip" \
  301. "flutter/android/app/src/main/jniLibs/${ANDROID_ABI}"/*
  302. # Build flutter-jit-release for x86
  303. if [ "${ANDROID_ABI}" = "x86" ]; then
  304. pushd flutter-sdk
  305. echo "## Sync flutter engine sources"
  306. echo "### We need fakeroot because chromium base image is unpacked with weird uid/gid ownership"
  307. sed -i "s/FLUTTER_VERSION_PLACEHOLDER/${FLUTTER_VERSION}/" .gclient
  308. export FAKEROOTDONTTRYCHOWN=1
  309. fakeroot gclient sync
  310. unset FAKEROOTDONTTRYCHOWN
  311. pushd src
  312. echo "## Patch away Google Play dependencies"
  313. rm \
  314. flutter/shell/platform/android/io/flutter/app/FlutterPlayStoreSplitApplication.java \
  315. flutter/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java flutter/shell/platform/android/io/flutter/embedding/android/FlutterPlayStoreSplitApplication.java
  316. sed \
  317. -i \
  318. -e '/PlayStore/d' \
  319. flutter/tools/android_lint/project.xml \
  320. flutter/shell/platform/android/BUILD.gn
  321. sed \
  322. -i \
  323. -e '/com.google.android.play/d' \
  324. flutter/tools/androidx/files.json
  325. echo "## Configure android engine build"
  326. flutter/tools/gn \
  327. --android --android-cpu x86 --runtime-mode=jit_release \
  328. --no-goma --no-enable-unittests
  329. echo "## Perform android engine build"
  330. ninja -C out/android_jit_release_x86
  331. echo "## Configure host engine build"
  332. flutter/tools/gn \
  333. --android-cpu x86 --runtime-mode=jit_release \
  334. --no-goma --no-enable-unittests
  335. echo "## Perform android engine build"
  336. ninja -C out/host_jit_release_x86
  337. echo "## Rename host engine"
  338. mv out/host_jit_release_x86 out/host_jit_release
  339. echo "## Mimic jit_release engine to debug to use with flutter build apk"
  340. pushd out/android_jit_release_x86
  341. sed \
  342. -e 's/jit_release/debug/' \
  343. flutter_embedding_jit_release.maven-metadata.xml \
  344. 1>flutter_embedding_debug.maven-metadata.xml
  345. sed \
  346. -e 's/jit_release/debug/' \
  347. flutter_embedding_jit_release.pom \
  348. 1>flutter_embedding_debug.pom
  349. sed \
  350. -e 's/jit_release/debug/' \
  351. x86_jit_release.maven-metadata.xml \
  352. 1>x86_debug.maven-metadata.xml
  353. sed \
  354. -e 's/jit_release/debug/' \
  355. x86_jit_release.pom \
  356. 1>x86_debug.pom
  357. cp -a \
  358. flutter_embedding_jit_release-sources.jar \
  359. flutter_embedding_debug-sources.jar
  360. cp -a \
  361. flutter_embedding_jit_release.jar \
  362. flutter_embedding_debug.jar
  363. cp -a \
  364. x86_jit_release.jar \
  365. x86_debug.jar
  366. popd # out/android_jit_release_x86
  367. popd # src
  368. popd # flutter-sdk
  369. echo "# Clean up intermediate engine files and show free space"
  370. rm -rf \
  371. flutter-sdk/src/out/android_jit_release_x86/obj \
  372. flutter-sdk/src/out/host_jit_release/obj
  373. mv flutter-sdk/src/out flutter-out
  374. rm -rf flutter-sdk
  375. mkdir -p flutter-sdk/src/
  376. mv flutter-out flutter-sdk/src/out
  377. fi
  378. # Build the apk
  379. pushd flutter
  380. if [ "${ANDROID_ABI}" = "x86" ]; then
  381. flutter build apk \
  382. --local-engine-src-path="$(readlink -mf "../flutter-sdk/src")" \
  383. --local-engine=android_jit_release_x86 \
  384. --debug \
  385. --build-number="${VERCODE}" \
  386. --build-name="${VERNAME}" \
  387. --target-platform "${FLUTTER_TARGET}"
  388. else
  389. flutter build apk \
  390. --release \
  391. --build-number="${VERCODE}" \
  392. --build-name="${VERNAME}" \
  393. --target-platform "${FLUTTER_TARGET}"
  394. fi
  395. popd # flutter
  396. rm -rf flutter-sdk
  397. # Special step for fdroiddata CI builds to remove .gitconfig
  398. rm -f /home/vagrant/.gitconfig
  399. ;;
  400. *)
  401. echo "ERROR: Unknown build step '${BUILDSTEP}'!" >&2
  402. exit 1
  403. ;;
  404. esac
  405. # Report success
  406. echo "All done!"