fix(mobile): target minSdk for the native lib, move memory-card thumbhash to the core, add native CI

This commit is contained in:
Santo Shakil 2026-07-20 20:11:39 +06:00
parent ce718e6c10
commit 2786cc16a1
57 changed files with 760 additions and 702 deletions

View file

@ -65,6 +65,7 @@ jobs:
filters: |
mobile:
- 'mobile/**'
- 'native/**'
force-filters: |
- '.github/workflows/build-mobile.yml'
force-events: 'workflow_call,workflow_dispatch'
@ -154,6 +155,59 @@ jobs:
flutter build apk --release
fi
- name: Verify native Android compatibility
run: |
apk=mobile/build/app/outputs/flutter-apk/app-release.apk
sdk=${ANDROID_SDK_ROOT:-${ANDROID_HOME:?Android SDK path is not set}}
min_sdk=$(sed -nE 's/^[[:space:]]*minSdk[[:space:]]*=[[:space:]]*([0-9]+)[[:space:]]*$/\1/p' mobile/android/app/build.gradle)
[[ $min_sdk =~ ^[0-9]+$ ]] || { printf 'Could not parse minSdk from mobile/android/app/build.gradle\n' >&2; exit 1; }
readelf=$(find "$sdk/ndk" -path '*/toolchains/llvm/prebuilt/*/bin/llvm-readelf' -print | sort -V | tail -n 1)
[[ -n $readelf ]] || { printf 'No llvm-readelf found under %s\n' "$sdk/ndk" >&2; exit 1; }
dir=$(mktemp -d)
trap 'rm -rf "$dir"' EXIT
test -f "$apk"
[[ -x $readelf ]] || { printf 'llvm-readelf is not executable: %s\n' "$readelf" >&2; exit 1; }
for abi in armeabi-v7a arm64-v8a x86_64; do
so="$dir/$abi.so"
unzip -p "$apk" "lib/$abi/libimmich_core_ffi.so" > "$so"
test -s "$so"
notes=$("$readelf" -n "$so")
headers=$("$readelf" -lW "$so")
printf '%s notes:\n%s\n' "$abi" "$notes"
printf '%s LOAD headers:\n%s\n' "$abi" "$(printf '%s\n' "$headers" | awk '/^[[:space:]]*LOAD[[:space:]]/')"
bytes=$(printf '%s\n' "$notes" | awk '
/^[[:space:]]*Android[[:space:]]/ { android = 1; next }
android && /description data:/ {
sub(/^.*description data:[[:space:]]*/, "")
print $1, $2, $3, $4
exit
}
')
read -r b0 b1 b2 b3 <<< "$bytes"
for byte in "$b0" "$b1" "$b2" "$b3"; do
[[ $byte =~ ^[0-9a-fA-F]{2}$ ]]
done
api=$((16#$b0 + (16#$b1 << 8) + (16#$b2 << 16) + (16#$b3 << 24)))
printf '%s Android API: %d\n' "$abi" "$api"
if ((api > min_sdk)); then
printf '%s Android API %d exceeds minSdk %d\n' "$abi" "$api" "$min_sdk" >&2
exit 1
fi
alignments=$(printf '%s\n' "$headers" | awk '/^[[:space:]]*LOAD[[:space:]]/ { print $NF }')
test -n "$alignments"
while read -r alignment; do
if [[ $alignment != 0x4000 ]]; then
printf '%s LOAD alignment %s is not 0x4000\n' "$abi" "$alignment" >&2
exit 1
fi
done <<< "$alignments"
done
- name: Publish Android Artifact
id: upload-apk
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1

View file

@ -35,6 +35,7 @@ jobs:
mobile:
- 'mobile/**'
- 'i18n/en.json'
- 'native/**'
force-filters: |
- '.github/workflows/static_analysis.yml'
force-events: 'workflow_dispatch,release'

View file

@ -59,6 +59,10 @@ jobs:
- 'mise.toml'
mobile:
- 'mobile/**'
- 'native/**'
- 'mise.toml'
native:
- 'native/**'
- 'mise.toml'
machine-learning:
- 'machine-learning/**'
@ -69,6 +73,73 @@ jobs:
- '.github/workflows/test.yml'
force-events: 'workflow_dispatch'
native-tests:
name: Test & Lint Native Core
needs: pre-job
if: ${{ fromJSON(needs.pre-job.outputs.should_run).native == true }}
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: ./native
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@1af396ae134e4bc3b63d947e672bc68bf4ff9dc5 # create-workflow-token-action-v3.0.0
with:
client-id: ${{ secrets.PUSH_O_MATIC_APP_CLIENT_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
permission-contents: read
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup Mise
uses: immich-app/devtools/actions/use-mise@3bca63ca3c15020293b36b51737a3ee2c773340b # use-mise-action-v3.1.0
with:
github_token: ${{ steps.token.outputs.token }}
working_directory: ./native
- name: Install Flutter dependencies
working-directory: ./native/immich_native_core
run: flutter pub get
- name: Run Dart analyze
working-directory: ./native/immich_native_core
run: dart analyze
- name: Check formatting
run: cargo fmt --all --check
- name: Run Clippy
run: cargo clippy --workspace --all-targets --locked -- -D warnings
- name: Run tests
run: cargo test --workspace --locked
- name: Generate native bindings
run: mise //native:codegen
- name: Find generated file changes
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20.0.4
id: verify-native-generated-files
with:
files: |
native/crates/immich_core_ffi/include/immich_core.h
native/immich_native_core/lib/src/ffi/bindings.g.dart
- name: Verify generated files have not changed
if: steps.verify-native-generated-files.outputs.files_changed == 'true'
env:
CHANGED_FILES: ${{ steps.verify-native-generated-files.outputs.changed_files }}
run: |
echo "ERROR: Native generated files not up to date! Run 'mise //native:codegen'"
echo "Changed files: ${CHANGED_FILES}"
exit 1
script-unit-tests:
name: Scripts unit tests
needs: pre-job