build_fdroid.sh 14 KB

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