build_fdroid.sh 14 KB

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