Check every JNI symbol, not just the first one
🚴 Build and Test BikeControl / Workspace tests (push) Successful in 16m55s
Build & Release / Run tests (push) Successful in 6m35s
🚴 Build and Test BikeControl / Android compile check (push) Successful in 3m41s
Build & Release / Build Linux (deb + AppImage) (push) Successful in 15m18s
Build & Release / Build Arch package (push) Successful in 29m19s
Build & Release / Build Android APK (push) Failing after 29s
Build & Release / Create release (push) Skipped
🚴 Build and Test BikeControl / Workspace tests (push) Successful in 16m55s
Build & Release / Run tests (push) Successful in 6m35s
🚴 Build and Test BikeControl / Android compile check (push) Successful in 3m41s
Build & Release / Build Linux (deb + AppImage) (push) Successful in 15m18s
Build & Release / Build Arch package (push) Successful in 29m19s
Build & Release / Build Android APK (push) Failing after 29s
Build & Release / Create release (push) Skipped
The android-check job failed on a tree that is perfectly correct: android.rs exports three `Java_..._MainActivity_*` symbols, the check compared all three against a single expected name and called it a mismatch. Two bugs, both from assuming one native: - SYM collected every export while EXPECTED was built from one method, so the comparison was three lines against one. - The Kotlin side matched `external fun name()` on empty parens, which quietly skipped nativeSetActivity and nativeBluetoothStateChanged — parameters do not appear in the symbol name, so stop at the paren. Now both sides are collected into sets and diffed, so a native declared in Kotlin with no Rust half fails as loudly as the reverse. Verified against the real files: passes as-is, and fails with a readable diff for a Kotlin-only native and for a renamed Rust export. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -138,7 +138,7 @@ jobs:
|
||||
|
||||
# Cheap invariants that a compiler cannot see. Both failures are silent:
|
||||
# the app builds, installs, launches, and then finds no trainer.
|
||||
- name: Check the Android source layout and the JNI symbol
|
||||
- name: Check the Android source layout and the JNI symbols
|
||||
run: |
|
||||
set -e
|
||||
# gen/ is generated and must stay untracked, or a `tauri android init`
|
||||
@@ -152,20 +152,35 @@ jobs:
|
||||
KT=src-tauri/android/src/main/java/paris/tourolle/bikecontrol/MainActivity.kt
|
||||
[ -f "$KT" ] || { echo "❌ $KT is missing"; exit 1; }
|
||||
|
||||
# The JNI symbol in android.rs is matched by the *runtime*, by name.
|
||||
# Rename the Kotlin package or the method and nothing fails to
|
||||
# compile — btleplug simply never gets initialised.
|
||||
SYM=$(sed -n 's/.*pub extern "system" fn \(Java_[A-Za-z0-9_]*\).*/\1/p' src-tauri/src/android.rs)
|
||||
# JNI symbols are matched by the *runtime*, by name. Rename the
|
||||
# Kotlin package, add a native without its Rust half, or drop a Rust
|
||||
# export, and nothing fails to compile — the method simply is not
|
||||
# there when Java calls it. So compare the two sets, both ways.
|
||||
#
|
||||
# Sets, not a single pair: there are three natives now, and matching
|
||||
# `external fun name()` on empty parens missed the two that take
|
||||
# arguments. Parameters do not appear in the symbol name, so stop at
|
||||
# the opening paren.
|
||||
TMP="${RUNNER_TEMP:-/tmp}"
|
||||
PKG=$(sed -n 's/^package \(.*\)$/\1/p' "$KT" | tr -d '\r')
|
||||
METHOD=$(sed -n 's/.*external fun \([A-Za-z0-9_]*\)().*/\1/p' "$KT")
|
||||
EXPECTED="Java_$(echo "$PKG" | tr '.' '_')_MainActivity_$METHOD"
|
||||
if [ "$SYM" != "$EXPECTED" ]; then
|
||||
echo "❌ JNI symbol mismatch:"
|
||||
echo " android.rs exports: $SYM"
|
||||
echo " MainActivity needs: $EXPECTED"
|
||||
PREFIX="Java_$(echo "$PKG" | tr '.' '_')_MainActivity_"
|
||||
|
||||
sed -n 's/.*pub extern "system" fn \(Java_[A-Za-z0-9_]*\).*/\1/p' \
|
||||
src-tauri/src/android.rs | sort -u > "$TMP/jni-rust"
|
||||
sed -n "s/.*external fun \([A-Za-z0-9_]*\)(.*/$PREFIX\1/p" \
|
||||
"$KT" | sort -u > "$TMP/jni-kotlin"
|
||||
|
||||
[ -s "$TMP/jni-rust" ] || { echo "❌ No JNI exports found in android.rs"; exit 1; }
|
||||
|
||||
if ! diff -u "$TMP/jni-kotlin" "$TMP/jni-rust" > "$TMP/jni-diff"; then
|
||||
echo "❌ JNI symbols differ between MainActivity.kt and android.rs:"
|
||||
echo " - declared in MainActivity.kt, not exported by android.rs"
|
||||
echo " + exported by android.rs, not declared in MainActivity.kt"
|
||||
tail -n +4 "$TMP/jni-diff"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ JNI symbol $SYM matches $PKG.MainActivity.$METHOD"
|
||||
echo "✅ $(wc -l < "$TMP/jni-rust") JNI symbols match $PKG.MainActivity:"
|
||||
sed 's/^/ /' "$TMP/jni-rust"
|
||||
|
||||
- name: Cargo check (aarch64-linux-android)
|
||||
run: |
|
||||
|
||||
Reference in New Issue
Block a user