build_fdroid.sh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  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. FLUTTER_BRIDGE_VERSION="$(yq -r \
  118. .env.FLUTTER_VERSION \
  119. .github/workflows/bridge.yml)"
  120. FLUTTER_RUST_BRIDGE_VERSION="$(yq -r \
  121. .env.FLUTTER_RUST_BRIDGE_VERSION \
  122. .github/workflows/bridge.yml)"
  123. NDK_VERSION="$(yq -r \
  124. .env.NDK_VERSION \
  125. .github/workflows/flutter-build.yml)"
  126. RUST_VERSION="$(yq -r \
  127. .env.RUST_VERSION \
  128. .github/workflows/flutter-build.yml)"
  129. VCPKG_COMMIT_ID="$(yq -r \
  130. .env.VCPKG_COMMIT_ID \
  131. .github/workflows/flutter-build.yml)"
  132. if [ -z "${CARGO_NDK_VERSION}" ] || [ -z "${FLUTTER_VERSION}" ] ||
  133. [ -z "${FLUTTER_BRIDGE_VERSION}" ] ||
  134. [ -z "${FLUTTER_RUST_BRIDGE_VERSION}" ] ||
  135. [ -z "${NDK_VERSION}" ] || [ -z "${RUST_VERSION}" ] ||
  136. [ -z "${VCPKG_COMMIT_ID}" ]; then
  137. echo "ERROR: Can not identify all required versions!" >&2
  138. exit 1
  139. fi
  140. # Map NDK version to revision
  141. NDK_VERSION="$(wget \
  142. -qO- \
  143. -H "Accept: application/vnd.github+json" \
  144. -H "X-GitHub-Api-Version: 2022-11-28" \
  145. 'https://api.github.com/repos/android/ndk/releases' |
  146. jq -r ".[] | select(.tag_name == \"${NDK_VERSION}\") | .body | match(\"ndkVersion \\\"(.*)\\\"\").captures[0].string")"
  147. if [ -z "${NDK_VERSION}" ]; then
  148. echo "ERROR: Can not map Android NDK codename to revision!" >&2
  149. exit 1
  150. fi
  151. export ANDROID_NDK_HOME="${ANDROID_SDK_ROOT}/ndk/${NDK_VERSION}"
  152. export ANDROID_NDK_ROOT="${ANDROID_SDK_ROOT}/ndk/${NDK_VERSION}"
  153. #
  154. # Install the components
  155. #
  156. set -e
  157. # Install Android NDK
  158. if [ ! -d "${ANDROID_NDK_ROOT}" ]; then
  159. sdkmanager --install "ndk;${NDK_VERSION}"
  160. fi
  161. # Install Rust
  162. if [ ! -f "${HOME}/rustup/rustup-init.sh" ]; then
  163. pushd "${HOME}"
  164. git clone --depth 1 https://github.com/rust-lang/rustup
  165. popd # ${HOME}
  166. fi
  167. pushd "${HOME}/rustup"
  168. bash rustup-init.sh -y \
  169. --target "${RUST_TARGET}" \
  170. --default-toolchain "${RUST_VERSION}"
  171. popd
  172. if ! command -v cargo 1>/dev/null 2>&1; then
  173. . "${HOME}/.cargo/env"
  174. fi
  175. # Install cargo-ndk
  176. cargo install \
  177. cargo-ndk \
  178. --version "${CARGO_NDK_VERSION}" \
  179. --locked
  180. # Install rust bridge generator
  181. cargo install cargo-expand
  182. cargo install flutter_rust_bridge_codegen \
  183. --version "${FLUTTER_RUST_BRIDGE_VERSION}" \
  184. --features "uuid" \
  185. --locked
  186. # Populate native vcpkg dependencies
  187. if [ ! -d "${VCPKG_ROOT}" ]; then
  188. pushd "${HOME}"
  189. git clone \
  190. https://github.com/Microsoft/vcpkg.git
  191. git clone \
  192. https://github.com/Microsoft/vcpkg-tool.git
  193. pushd vcpkg-tool
  194. mkdir build
  195. pushd build
  196. cmake \
  197. -DCMAKE_BUILD_TYPE=Release \
  198. -G 'Ninja' \
  199. -DVCPKG_DEVELOPMENT_WARNINGS=OFF \
  200. ..
  201. cmake --build .
  202. popd # build
  203. popd # vcpkg-tool
  204. pushd vcpkg
  205. git reset --hard "${VCPKG_COMMIT_ID}"
  206. cp -a ../vcpkg-tool/build/vcpkg vcpkg
  207. # disable telemetry
  208. touch "vcpkg.disable-metrics"
  209. popd # vcpkg
  210. popd # ${HOME}
  211. fi
  212. # Install depot-tools for x86
  213. if [ "${ANDROID_ABI}" = "x86" ]; then
  214. if [ ! -d "${HOME}/depot_tools" ]; then
  215. pushd "${HOME}"
  216. git clone \
  217. --depth 1 \
  218. https://chromium.googlesource.com/chromium/tools/depot_tools.git
  219. popd # ${HOME}
  220. fi
  221. fi
  222. # Patch the RustDesk sources
  223. git apply res/fdroid/patches/*.patch
  224. # If Flutter version used to generate bridge files differs from Flutter
  225. # version used to compile Rustdesk library, generate bridge using the
  226. # `FLUTTER_BRIDGE_VERSION` an restore the pubspec later
  227. if [ "${FLUTTER_VERSION}" != "${FLUTTER_BRIDGE_VERSION}" ]; then
  228. # Install Flutter bridge version
  229. prepare_flutter "${FLUTTER_BRIDGE_VERSION}" "${HOME}/flutter"
  230. # Save changes
  231. git add .
  232. # Edit pubspec to make flutter bridge version work
  233. sed \
  234. -i \
  235. -e 's/extended_text: 14.0.0/extended_text: 13.0.0/g' \
  236. flutter/pubspec.yaml
  237. # Download Flutter dependencies
  238. pushd flutter
  239. flutter clean
  240. flutter packages pub get
  241. popd # flutter
  242. # Generate FFI bindings
  243. flutter_rust_bridge_codegen \
  244. --rust-input ./src/flutter_ffi.rs \
  245. --dart-output ./flutter/lib/generated_bridge.dart
  246. # Add bridge files to save-list
  247. git add -f ./flutter/lib/generated_bridge.* ./src/bridge_generated.*
  248. # Restore everything
  249. git checkout '*'
  250. git clean -dffx
  251. git reset
  252. fi
  253. # Install Flutter version for RustDesk library build
  254. prepare_flutter "${FLUTTER_VERSION}" "${HOME}/flutter"
  255. # gms is not in thoes files now, but we still keep the following line for future reference(maybe).
  256. sed \
  257. -i \
  258. -e '/gms/d' \
  259. flutter/android/build.gradle \
  260. flutter/android/app/build.gradle
  261. # `firebase_analytics` is not in these files now, but we still keep the following lines.
  262. sed \
  263. -i \
  264. -e '/firebase_analytics/d' \
  265. flutter/pubspec.yaml
  266. sed \
  267. -i \
  268. -e '/ firebase/,/ version/d' \
  269. flutter/pubspec.lock
  270. sed \
  271. -i \
  272. -e '/firebase/Id' \
  273. flutter/lib/main.dart
  274. ;;
  275. build)
  276. # build: perform actual build of APK file
  277. set -e
  278. #
  279. # Extract required versions for NDK, Rust, Flutter from
  280. # '.github/workflows/flutter-build.yml'
  281. #
  282. # Flutter used to compile main Rustdesk library
  283. FLUTTER_VERSION="$(yq -r \
  284. .env.ANDROID_FLUTTER_VERSION \
  285. .github/workflows/flutter-build.yml)"
  286. if [ -z "${FLUTTER_VERSION}" ]; then
  287. FLUTTER_VERSION="$(yq -r \
  288. .env.FLUTTER_VERSION \
  289. .github/workflows/flutter-build.yml)"
  290. fi
  291. NDK_VERSION="$(yq -r \
  292. .env.NDK_VERSION \
  293. .github/workflows/flutter-build.yml)"
  294. # Map NDK version to revision
  295. NDK_VERSION="$(wget \
  296. -qO- \
  297. -H "Accept: application/vnd.github+json" \
  298. -H "X-GitHub-Api-Version: 2022-11-28" \
  299. 'https://api.github.com/repos/android/ndk/releases' |
  300. jq -r ".[] | select(.tag_name == \"${NDK_VERSION}\") | .body | match(\"ndkVersion \\\"(.*)\\\"\").captures[0].string")"
  301. if [ -z "${NDK_VERSION}" ]; then
  302. echo "ERROR: Can not map Android NDK codename to revision!" >&2
  303. exit 1
  304. fi
  305. export ANDROID_NDK_HOME="${ANDROID_SDK_ROOT}/ndk/${NDK_VERSION}"
  306. export ANDROID_NDK_ROOT="${ANDROID_SDK_ROOT}/ndk/${NDK_VERSION}"
  307. if ! command -v cargo 1>/dev/null 2>&1; then
  308. . "${HOME}/.cargo/env"
  309. fi
  310. # Download Flutter dependencies
  311. pushd flutter
  312. flutter clean
  313. flutter packages pub get
  314. popd # flutter
  315. # Build host android deps
  316. bash flutter/build_android_deps.sh "${ANDROID_ABI}"
  317. # Build rustdesk lib
  318. cargo ndk \
  319. --platform 21 \
  320. --target "${RUST_TARGET}" \
  321. --bindgen \
  322. build \
  323. --release \
  324. --features "${RUSTDESK_FEATURES}"
  325. mkdir -p "flutter/android/app/src/main/jniLibs/${ANDROID_ABI}"
  326. cp "target/${RUST_TARGET}/release/liblibrustdesk.so" \
  327. "flutter/android/app/src/main/jniLibs/${ANDROID_ABI}/librustdesk.so"
  328. cp "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/${NDK_TARGET}/libc++_shared.so" \
  329. "flutter/android/app/src/main/jniLibs/${ANDROID_ABI}/"
  330. "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip" \
  331. "flutter/android/app/src/main/jniLibs/${ANDROID_ABI}"/*
  332. # Build flutter-jit-release for x86
  333. if [ "${ANDROID_ABI}" = "x86" ]; then
  334. pushd flutter-sdk
  335. echo "## Sync flutter engine sources"
  336. echo "### We need fakeroot because chromium base image is unpacked with weird uid/gid ownership"
  337. sed -i "s/FLUTTER_VERSION_PLACEHOLDER/${FLUTTER_VERSION}/" .gclient
  338. export FAKEROOTDONTTRYCHOWN=1
  339. fakeroot gclient sync
  340. unset FAKEROOTDONTTRYCHOWN
  341. pushd src
  342. echo "## Patch away Google Play dependencies"
  343. rm \
  344. flutter/shell/platform/android/io/flutter/app/FlutterPlayStoreSplitApplication.java \
  345. flutter/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java flutter/shell/platform/android/io/flutter/embedding/android/FlutterPlayStoreSplitApplication.java
  346. sed \
  347. -i \
  348. -e '/PlayStore/d' \
  349. flutter/tools/android_lint/project.xml \
  350. flutter/shell/platform/android/BUILD.gn
  351. sed \
  352. -i \
  353. -e '/com.google.android.play/d' \
  354. flutter/tools/androidx/files.json
  355. echo "## Configure android engine build"
  356. flutter/tools/gn \
  357. --android --android-cpu x86 --runtime-mode=jit_release \
  358. --no-goma --no-enable-unittests
  359. echo "## Perform android engine build"
  360. ninja -C out/android_jit_release_x86
  361. echo "## Configure host engine build"
  362. flutter/tools/gn \
  363. --android-cpu x86 --runtime-mode=jit_release \
  364. --no-goma --no-enable-unittests
  365. echo "## Perform android engine build"
  366. ninja -C out/host_jit_release_x86
  367. echo "## Rename host engine"
  368. mv out/host_jit_release_x86 out/host_jit_release
  369. echo "## Mimic jit_release engine to debug to use with flutter build apk"
  370. pushd out/android_jit_release_x86
  371. sed \
  372. -e 's/jit_release/debug/' \
  373. flutter_embedding_jit_release.maven-metadata.xml \
  374. 1>flutter_embedding_debug.maven-metadata.xml
  375. sed \
  376. -e 's/jit_release/debug/' \
  377. flutter_embedding_jit_release.pom \
  378. 1>flutter_embedding_debug.pom
  379. sed \
  380. -e 's/jit_release/debug/' \
  381. x86_jit_release.maven-metadata.xml \
  382. 1>x86_debug.maven-metadata.xml
  383. sed \
  384. -e 's/jit_release/debug/' \
  385. x86_jit_release.pom \
  386. 1>x86_debug.pom
  387. cp -a \
  388. flutter_embedding_jit_release-sources.jar \
  389. flutter_embedding_debug-sources.jar
  390. cp -a \
  391. flutter_embedding_jit_release.jar \
  392. flutter_embedding_debug.jar
  393. cp -a \
  394. x86_jit_release.jar \
  395. x86_debug.jar
  396. popd # out/android_jit_release_x86
  397. popd # src
  398. popd # flutter-sdk
  399. echo "# Clean up intermediate engine files and show free space"
  400. rm -rf \
  401. flutter-sdk/src/out/android_jit_release_x86/obj \
  402. flutter-sdk/src/out/host_jit_release/obj
  403. mv flutter-sdk/src/out flutter-out
  404. rm -rf flutter-sdk
  405. mkdir -p flutter-sdk/src/
  406. mv flutter-out flutter-sdk/src/out
  407. fi
  408. # Build the apk
  409. pushd flutter
  410. if [ "${ANDROID_ABI}" = "x86" ]; then
  411. flutter build apk \
  412. --local-engine-src-path="$(readlink -mf "../flutter-sdk/src")" \
  413. --local-engine=android_jit_release_x86 \
  414. --debug \
  415. --build-number="${VERCODE}" \
  416. --build-name="${VERNAME}" \
  417. --target-platform "${FLUTTER_TARGET}"
  418. else
  419. flutter build apk \
  420. --release \
  421. --build-number="${VERCODE}" \
  422. --build-name="${VERNAME}" \
  423. --target-platform "${FLUTTER_TARGET}"
  424. fi
  425. popd # flutter
  426. rm -rf flutter-sdk
  427. # Special step for fdroiddata CI builds to remove .gitconfig
  428. rm -f /home/vagrant/.gitconfig
  429. ;;
  430. *)
  431. echo "ERROR: Unknown build step '${BUILDSTEP}'!" >&2
  432. exit 1
  433. ;;
  434. esac
  435. # Report success
  436. echo "All done!"