@@ -673,6 +673,11 @@ jobs:
673673 echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
674674 echo "#define LICENSE" >> secret.h
675675
676+ - name : Prepare Android signing key
677+ run : |
678+ printf '%s' "${{ secrets.SIGNING_KEY }}" | base64 --decode > ${{ github.workspace }}/src/android/ci-signing-key.jks
679+ echo "CI_ANDROID_SIGNING_KEYSTORE=${{ github.workspace }}/src/android/ci-signing-key.jks" >> $GITHUB_ENV
680+
676681 - name : Build qthttpserver for Android
677682 run : |
678683 cd src/qthttpserver
@@ -699,6 +704,24 @@ jobs:
699704 - name : Build APK (not usable for production due to unpatched QT library)
700705 run : cd src; androiddeployqt --input android-qdomyos-zwift-deployment-settings.json --output ${{ github.workspace }}/output/android/ --android-platform android-31 --gradle --aab
701706
707+ - name : Re-sign APK for stable App Links fingerprint
708+ run : |
709+ APK_PATH="${{ github.workspace }}/output/android/build/outputs/apk/debug/android-debug.apk"
710+ SIGNED_APK_PATH="${{ github.workspace }}/output/android/build/outputs/apk/debug/android-debug-signed.apk"
711+ APKSIGNER=$(find /usr/local/lib/android/sdk/build-tools -name apksigner | sort | tail -n 1)
712+ if [ -z "$APKSIGNER" ]; then
713+ echo "apksigner not found"
714+ exit 1
715+ fi
716+ "$APKSIGNER" sign \
717+ --ks "$CI_ANDROID_SIGNING_KEYSTORE" \
718+ --ks-key-alias "${{ secrets.ALIAS }}" \
719+ --ks-pass "pass:${{ secrets.KEY_STORE_PASSWORD }}" \
720+ --key-pass "pass:${{ secrets.KEY_PASSWORD }}" \
721+ --out "$SIGNED_APK_PATH" \
722+ "$APK_PATH"
723+ mv "$SIGNED_APK_PATH" "$APK_PATH"
724+
702725 - name : Show ccache stats
703726 if : always()
704727 run : ccache --show-stats
@@ -1375,9 +1398,6 @@ jobs:
13751398 - name : Set up QEMU
13761399 uses : docker/setup-qemu-action@v3
13771400
1378- - name : Set up Docker Buildx
1379- uses : docker/setup-buildx-action@v3
1380-
13811401 - name : Secrets
13821402 run : |
13831403 cd src
@@ -1393,32 +1413,41 @@ jobs:
13931413 cd ..
13941414
13951415 - name : Build for Raspberry Pi
1396- uses : docker://arm32v7/debian:bullseye-20241016
1397- with :
1398- args : >
1416+ run : |
1417+ docker run --rm --platform linux/arm/v6 \
1418+ -v ${{ github.workspace }}:/workspace -w /workspace \
1419+ balenalib/raspberry-pi-debian:bullseye-build \
13991420 bash -c "
1400- set -ex &&
1401- for i in 1 2 3; do apt-get update && break || sleep 5; done &&
1402- for i in 1 2 3; do apt-get install -y --fix-missing build-essential git cmake qtbase5-dev qtbase5-private-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools libqt5svg5-dev qtmultimedia5-dev libqt5charts5-dev qtpositioning5-dev qtconnectivity5-dev libqt5websockets5-dev libqt5texttospeech5-dev libqt5bluetooth5 libqt5networkauth5-dev qml-module-qtlocation qml-module-qtpositioning qtlocation5-dev libqt5quickcontrols2-5 qtquickcontrols2-5-dev qml-module-qtquick-controls2 qtbase5-dev libqt5sql5-sqlite libqt5sql5 libqt5sql5-mysql libqt5sql5-psql && break || sleep 5; done &&
1403- export QT_SELECT=qt5 &&
1404- export PATH=/usr/lib/qt5/bin:$PATH &&
1405- cd /github/workspace &&
1406- sed -i '/QtHttpServer/d' qdomyos-zwift.pro &&
1407- find src -type f \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/#include <QtHttpServer/\/\/#include <QtHttpServer/' {} + &&
1408- find src -type f \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/QHttpServer/\/\/QHttpServer/' {} + &&
1409- cat qdomyos-zwift.pro &&
1410- qmake &&
1411- make -j$(nproc)
1421+ set -ex &&
1422+ for i in 1 2 3; do apt-get update && break || sleep 5; done &&
1423+ for i in 1 2 3; do apt-get install -y --fix-missing build-essential git cmake qtbase5-dev qtbase5-private-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools libqt5svg5-dev qtmultimedia5-dev libqt5charts5-dev qtpositioning5-dev qtconnectivity5-dev libqt5websockets5-dev libqt5texttospeech5-dev libqt5bluetooth5 libqt5networkauth5-dev qml-module-qtlocation qml-module-qtpositioning qtlocation5-dev libqt5quickcontrols2-5 qtquickcontrols2-5-dev qml-module-qtquick-controls2 qtbase5-dev libqt5sql5-sqlite libqt5sql5 libqt5sql5-mysql libqt5sql5-psql && break || sleep 5; done &&
1424+ export QT_SELECT=qt5 &&
1425+ export PATH=/usr/lib/qt5/bin:\$PATH &&
1426+ sed -i '/QtHttpServer/d' qdomyos-zwift.pro &&
1427+ find src -type f \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/#include <QtHttpServer/\/\/#include <QtHttpServer/' {} + &&
1428+ find src -type f \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/QHttpServer/\/\/QHttpServer/' {} + &&
1429+ cat qdomyos-zwift.pro &&
1430+ qmake &&
1431+ make -j\$(nproc)
14121432 "
14131433
14141434 - name : Rename binary
1415- run : mv src/qdomyos-zwift src/qdomyos-zwift-32bit
1416-
1435+ run : mv src/qdomyos-zwift src/qdomyos-zwift-armv6hf
1436+
1437+ - name : Verify 32-bit binary targets ARMv6
1438+ run : |
1439+ ARCH=$(readelf -A src/qdomyos-zwift-armv6hf | grep 'Tag_CPU_arch:' | awk '{print $2}')
1440+ echo "Binary CPU architecture: $ARCH"
1441+ if [ "$ARCH" != "v6" ]; then
1442+ echo "::error::Binary targets $ARCH but must target v6 for Pi Zero W compatibility"
1443+ exit 1
1444+ fi
1445+
14171446 - name : Archive Raspberry Pi binary
14181447 uses : actions/upload-artifact@v4
14191448 with :
1420- name : raspberry-pi-binary
1421- path : src/qdomyos-zwift-32bit
1449+ name : raspberry-pi-binary-armv6hf
1450+ path : src/qdomyos-zwift-armv6hf
14221451
14231452 raspberry-pi-build-and-image-64bit :
14241453 runs-on : ubuntu-22.04-arm
@@ -1443,30 +1472,141 @@ jobs:
14431472 echo "#define LICENSE" >> secret.h
14441473 cd ..
14451474
1446- - name : Install Qt5 build dependencies
1447- run : |
1448- sudo apt-get update
1449- sudo apt-get install -y build-essential git cmake qtbase5-dev qtbase5-private-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools libqt5svg5-dev qtmultimedia5-dev libqt5charts5-dev qtpositioning5-dev qtconnectivity5-dev libqt5websockets5-dev libqt5texttospeech5-dev libqt5bluetooth5 libqt5networkauth5-dev qml-module-qtlocation qml-module-qtpositioning qtlocation5-dev libqt5quickcontrols2-5 qtquickcontrols2-5-dev qml-module-qtquick-controls2 qtbase5-dev libqt5sql5-sqlite libqt5sql5 libqt5sql5-mysql libqt5sql5-psql
1450-
14511475 - name : Build for Raspberry Pi 64-bit
1452- run : |
1453- export QT_SELECT=qt5
1454- export PATH=/usr/lib/qt5/bin:$PATH
1455- sed -i '/QtHttpServer/d' qdomyos-zwift.pro
1456- find src -type f \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/#include <QtHttpServer/\/\/#include <QtHttpServer/' {} +
1457- find src -type f \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/QHttpServer/\/\/QHttpServer/' {} +
1458- cat qdomyos-zwift.pro
1459- qmake
1460- make -j$(nproc)
1476+ uses : docker://arm64v8/debian:bullseye-20241016
1477+ with :
1478+ args : >
1479+ bash -c "
1480+ set -ex &&
1481+ for i in 1 2 3; do apt-get update && break || sleep 5; done &&
1482+ for i in 1 2 3; do apt-get install -y --fix-missing build-essential git cmake qtbase5-dev qtbase5-private-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools libqt5svg5-dev qtmultimedia5-dev libqt5charts5-dev qtpositioning5-dev qtconnectivity5-dev libqt5websockets5-dev libqt5texttospeech5-dev libqt5bluetooth5 libqt5networkauth5-dev qml-module-qtlocation qml-module-qtpositioning qtlocation5-dev libqt5quickcontrols2-5 qtquickcontrols2-5-dev qml-module-qtquick-controls2 qtbase5-dev libqt5sql5-sqlite libqt5sql5 libqt5sql5-mysql libqt5sql5-psql && break || sleep 5; done &&
1483+ export QT_SELECT=qt5 &&
1484+ export PATH=/usr/lib/qt5/bin:$PATH &&
1485+ cd /github/workspace &&
1486+ sed -i '/QtHttpServer/d' qdomyos-zwift.pro &&
1487+ find src -type f \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/#include <QtHttpServer/\/\/#include <QtHttpServer/' {} + &&
1488+ find src -type f \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/QHttpServer/\/\/QHttpServer/' {} + &&
1489+ cat qdomyos-zwift.pro &&
1490+ qmake &&
1491+ make -j$(nproc)
1492+ "
14611493
14621494 - name : Rename binary
1463- run : mv src/qdomyos-zwift src/qdomyos-zwift-64bit
1495+ run : mv src/qdomyos-zwift src/qdomyos-zwift-aarch64
1496+
1497+ - name : Verify 64-bit binary glibc compatibility
1498+ run : |
1499+ MAX_GLIBC=$(readelf -V src/qdomyos-zwift-aarch64 | grep -oP 'GLIBC_\K[0-9.]+' | sort -V | tail -1)
1500+ echo "Max required GLIBC version: $MAX_GLIBC"
1501+ if dpkg --compare-versions "$MAX_GLIBC" gt "2.31"; then
1502+ echo "::error::Binary requires GLIBC $MAX_GLIBC but Raspberry Pi OS Bullseye only has 2.31"
1503+ exit 1
1504+ fi
14641505
14651506 - name : Archive Raspberry Pi 64bit binary
14661507 uses : actions/upload-artifact@v4
14671508 with :
1468- name : raspberry-pi-binary-64bit
1469- path : src/qdomyos-zwift-64bit
1509+ name : raspberry-pi-binary-aarch64
1510+ path : src/qdomyos-zwift-aarch64
1511+
1512+ raspberry-pi-smoke-test :
1513+ runs-on : ubuntu-22.04-arm
1514+ needs : [raspberry-pi-build, raspberry-pi-build-and-image-64bit]
1515+
1516+ steps :
1517+ - name : Download armv6hf binary
1518+ uses : actions/download-artifact@v4
1519+ with :
1520+ name : raspberry-pi-binary-armv6hf
1521+ path : bin32
1522+
1523+ - name : Download aarch64 binary
1524+ uses : actions/download-artifact@v4
1525+ with :
1526+ name : raspberry-pi-binary-aarch64
1527+ path : bin64
1528+
1529+ - name : Set up QEMU
1530+ uses : docker/setup-qemu-action@v3
1531+
1532+ - name : ELF metadata checks for armv6hf binary (Pi Zero W)
1533+ timeout-minutes : 5
1534+ run : |
1535+ chmod +x bin32/qdomyos-zwift-armv6hf
1536+ file bin32/qdomyos-zwift-armv6hf
1537+ readelf -A bin32/qdomyos-zwift-armv6hf | grep -E 'Tag_CPU|Tag_FP|Tag_ABI'
1538+
1539+ # Check CPU architecture is ARMv6
1540+ ARCH=$(readelf -A bin32/qdomyos-zwift-armv6hf | grep 'Tag_CPU_arch:' | awk '{print $2}')
1541+ if [ "$ARCH" != "v6" ]; then
1542+ echo "::error::Binary targets $ARCH, expected v6"
1543+ exit 1
1544+ fi
1545+ echo "PASS: CPU architecture is ARMv6"
1546+
1547+ # Check hard-float ABI
1548+ VFP=$(readelf -A bin32/qdomyos-zwift-armv6hf | grep 'Tag_ABI_VFP_args:' | awk '{print $2}')
1549+ if [ "$VFP" != "VFP" ]; then
1550+ echo "::error::Binary does not use hard-float ABI (Tag_ABI_VFP_args: $VFP)"
1551+ exit 1
1552+ fi
1553+ echo "PASS: Hard-float ABI (VFP registers)"
1554+
1555+ # Check dynamic linker / interpreter path
1556+ INTERP=$(readelf -l bin32/qdomyos-zwift-armv6hf | grep 'interpreter:' | grep -oP '/[^\]]+')
1557+ if [ "$INTERP" != "/lib/ld-linux-armhf.so.3" ]; then
1558+ echo "::error::Wrong interpreter: $INTERP, expected /lib/ld-linux-armhf.so.3"
1559+ exit 1
1560+ fi
1561+ echo "PASS: Interpreter is /lib/ld-linux-armhf.so.3"
1562+
1563+ echo "SUCCESS: All armv6hf ELF metadata checks passed"
1564+
1565+ - name : Runtime smoke test armv6hf binary
1566+ timeout-minutes : 10
1567+ continue-on-error : true
1568+ run : |
1569+ docker run --rm --platform linux/arm/v6 \
1570+ -v ${{ github.workspace }}/bin32:/app \
1571+ balenalib/raspberry-pi-debian:bullseye-run \
1572+ bash -c "
1573+ for i in 1 2 3; do apt-get update && break || sleep 5; done
1574+ for i in 1 2 3; do apt-get install -y --no-install-recommends \
1575+ libqt5core5a libqt5bluetooth5 libqt5charts5 libqt5widgets5 \
1576+ libqt5network5 libqt5websockets5 libqt5xml5 libqt5sql5 \
1577+ libqt5multimedia5 libqt5positioning5 libqt5qml5 libqt5quick5 \
1578+ libqt5texttospeech5 libqt5networkauth5 libqt5gui5 || true && break || sleep 5; done
1579+ OUTPUT=\$(/app/qdomyos-zwift-armv6hf -no-gui -smoke-test 2>&1) || true
1580+ echo \"\$OUTPUT\"
1581+ if echo \"\$OUTPUT\" | grep -q 'SMOKE_OK'; then
1582+ echo 'SUCCESS: armv6hf binary runs and Qt runtime loads'
1583+ else
1584+ echo '::error::armv6hf runtime smoke test failed - SMOKE_OK not found'
1585+ exit 1
1586+ fi
1587+ "
1588+
1589+ - name : Runtime smoke test aarch64 binary (ARM64 Bullseye - Pi 3/4/5)
1590+ timeout-minutes : 10
1591+ run : |
1592+ chmod +x bin64/qdomyos-zwift-aarch64
1593+ docker run --rm -v ${{ github.workspace }}/bin64:/app \
1594+ arm64v8/debian:bullseye-20241016 \
1595+ bash -c "
1596+ apt-get update && apt-get install -y --no-install-recommends \
1597+ libqt5core5a libqt5bluetooth5 libqt5charts5 libqt5widgets5 \
1598+ libqt5network5 libqt5websockets5 libqt5xml5 libqt5sql5 \
1599+ libqt5multimedia5 libqt5positioning5 libqt5qml5 libqt5quick5 \
1600+ libqt5texttospeech5 libqt5networkauth5 libqt5gui5 || true
1601+ OUTPUT=\$(/app/qdomyos-zwift-aarch64 -no-gui -smoke-test 2>&1) || true
1602+ echo \"\$OUTPUT\"
1603+ if echo \"\$OUTPUT\" | grep -q 'SMOKE_OK'; then
1604+ echo 'SUCCESS: aarch64 binary runs on ARM64 Bullseye'
1605+ else
1606+ echo '::error::aarch64 runtime smoke test failed - SMOKE_OK not found'
1607+ exit 1
1608+ fi
1609+ "
14701610
14711611 window-msvc2022-build :
14721612 runs-on : windows-latest
@@ -1985,7 +2125,7 @@ jobs:
19852125 permissions : write-all
19862126 runs-on : ubuntu-22.04
19872127 if : github.event_name == 'schedule'
1988- needs : [window-msvc2019-build, window-msvc2022-build, window-build, android-build, raspberry-pi-build, nordictrack-build, peloton-bike-plus-build, peloton-bike-build, raspberry-pi-build-and-image-64bit]
2128+ needs : [window-msvc2019-build, window-msvc2022-build, window-build, android-build, raspberry-pi-build, nordictrack-build, peloton-bike-plus-build, peloton-bike-build, raspberry-pi-build-and-image-64bit, raspberry-pi-smoke-test ]
19892129 steps :
19902130 - name : Checkout code
19912131 uses : actions/checkout@v2
@@ -2026,7 +2166,8 @@ jobs:
20262166 - **nordictrack-rower-android-trial**: Nordictrack Rower build for iFIT2 Tablets
20272167 - **peloton-bike-plus-android-trial**: Peloton Bike Plus build with Grupetto backend
20282168 - **peloton-bike-android-trial**: Peloton Bike build with Grupetto backend
2029- - **raspberry-pi-binary**: Raspberry Pi build
2169+ - **raspberry-pi-binary-armv6hf**: Raspberry Pi 32-bit (ARMv6 hard-float, Pi Zero W compatible)
2170+ - **raspberry-pi-binary-aarch64**: Raspberry Pi 64-bit (AArch64, Pi 3/4/5)
20302171
20312172 __Please help us improve QZ by reporting any issues you encounter!__ :wink:
20322173 files : |
@@ -2043,5 +2184,5 @@ jobs:
20432184 nordictrack-rower-android-trial/android-debug-nordictrack-rower.apk
20442185 peloton-bike-plus-android-trial/android-debug-peloton-bike-plus.apk
20452186 peloton-bike-android-trial/android-debug-peloton-bike.apk
2046- raspberry-pi-binary/qdomyos-zwift-32bit
2047- raspberry-pi-binary/qdomyos-zwift-64bit
2187+ raspberry-pi-binary-armv6hf /qdomyos-zwift-armv6hf
2188+ raspberry-pi-binary-aarch64 /qdomyos-zwift-aarch64
0 commit comments