Skip to content

Conversation

@haslinghuis
Copy link
Member

@haslinghuis haslinghuis commented Oct 29, 2025

Using

cd src-tauri
rm Cargo.lock && cargo check
cargo update -p tauri-plugin-serialplugin --precise 2.16.0
cargo tree | grep serialplugin

Summary by CodeRabbit

  • New Features

    • Android USB-serial support with a new Android entrypoint, public USB permission API, improved device discovery, and richer diagnostics.
  • Chores

    • CI Java updated to 21.
    • Simplified Android dev workflow and added local Android build, manifest/Gradle/device-filter patching, and ADB-over-WiFi helper scripts.
  • Permissions

    • Mobile platforms added (android, iOS) and fine-grained serial permissions declared.
  • Removed

    • Legacy Android development guide removed.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 29, 2025

Walkthrough

Switches to the unified tauri-plugin-serialplugin (v2.16.0), removes the custom Android serial module, adds Android MainActivity and idempotent scripts to patch Gradle/Manifest/device-filter, extends JS with an Android USB permission API and enhanced logging, updates capabilities and package scripts, and updates CI to Java 21 plus a manifest patch step.

Changes

Cohort / File(s) Summary
CI & Workflow
\ .github/workflows/ci.yml
Switch CI Java setup 17 → 21; run scripts/tauri-patch-android.sh before Android build.
Tauri Core / Cargo
\src-tauri/Cargo.toml, \src-tauri/src/main.rs, \src-tauri/src/lib.rs
Replace per-target serial deps with unified tauri-plugin-serialplugin = "2.16.0"; remove tauri_plugin_shell; always init tauri_plugin_serialplugin (remove platform branching).
Removed Android module
\src-tauri/src/serial_android.rs
Delete custom Android serial implementation and its Tauri commands/types.
Android Native / Manifest patching
\scripts/MainActivity.kt, \scripts/tauri-patch-android.sh, \scripts/patch-*.sh, \scripts/create-device-filter.sh
Add MainActivity to handle USB attach/permission; add idempotent scripts to inject USB permissions, intent-filter, device_filter.xml, add usb-serial dependency, and ensure Gradle repositories.
Frontend — Serial & Port handling
\src/js/protocols/TauriSerial.js, \src/js/port_handler.js
Add public requestUsbPermission(path) to TauriSerial; improve Android port parsing, debug logging, permission/error diagnostics; add tauriserial flow in port_handler.js.
Capabilities
\src-tauri/capabilities/default.json
Add android and iOS to platforms; expand serialplugin permission into granular serialplugin:allow-* entries.
Android Build & ADB helpers
\scripts/build-android-local.sh, \scripts/setup-adb-wifi.sh
Add local Android build helper (validate/dev/release, patching, signing, install) and ADB WiFi/TCP helper for pairing/connection.
Package scripts
\package.json
Remove many multi-variant emulator/ADB scripts; simplify tauri:dev:android to tauri android dev.
Docs
\scripts/README.md, \ ANDROID.md (removed)
Add scripts README documenting Android USB support; remove the old Android development guide (ANDROID.md).

Sequence Diagram(s)

sequenceDiagram
    participant App as Web App
    participant Handler as PortHandler
    participant Serial as TauriSerial (JS)
    participant Plugin as tauri-plugin-serialplugin
    participant Android as Android USB System
    participant MainActivity as MainActivity

    App->>Handler: requestDevicePermission(tauriserial)
    Handler->>Serial: requestUsbPermission(path)
    Serial->>Plugin: open_port (attempt)
    Plugin->>Android: request USB permission (system dialog)
    Android->>MainActivity: broadcast USB attach / permission result
    Note right of MainActivity `#DDEEFF`: MainActivity handles PendingIntent\nand forwards results
    Android-->>MainActivity: permission granted / denied
    alt Permission Granted
        Plugin-->>Serial: open success
        Serial-->>Handler: true (select port)
    else Permission Denied
        Plugin-->>Serial: error (permission denied)
        Serial-->>Handler: false (emit denial)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas:
    • scripts/MainActivity.kt — Android lifecycle, PendingIntent flags, BroadcastReceiver correctness.
    • scripts/tauri-patch-android.sh and scripts/patch-*.sh — idempotence, XML/Gradle edits, target paths.
    • src/js/protocols/TauriSerial.js and src/js/port_handler.js — permission API semantics, error mapping, Android response parsing.
    • Verify the removed src-tauri/src/serial_android.rs behaviors (timeouts, per-port state, read/write semantics) are adequately covered by the plugin and native changes.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete and does not follow the provided template, missing context about changes, objectives, and references to fixed issues. Provide a comprehensive description following the template: explain the purpose (Android USB support), summarize key changes, reference related issues with 'Fixes #', and remove the template placeholder text.
Title check ❓ Inconclusive The title 'Patch manifest' is vague and does not clearly convey the main changes in this comprehensive pull request. Use a more descriptive title that reflects the primary objective, such as 'Add Android USB serial support via tauri-plugin-serialplugin' or 'Enable Android USB host mode for serial communication'.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 376ebad and 745a9c1.

📒 Files selected for processing (1)
  • ANDROID.md (0 hunks)
💤 Files with no reviewable changes (1)
  • ANDROID.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Tauri Linux preview (deb/appimage)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
scripts/patch-android-manifest.sh (2)

38-82: Device filter creation is solid, but consider future maintainability.

The device_filter.xml generation is well-structured and covers major Betaflight-compatible devices. The heredoc approach is clean and readable.

Consider documenting (in ANDROID_USB.md) how users can add additional USB devices if needed, since the device list is currently hardcoded in the script.


29-37: Sed approach works for current Tauri-generated manifests but could be more robust.

The concern about multiple activities does not apply here: Tauri-generated Android manifests contain a single MainActivity with the launcher intent-filter. The sed regex 0,/<\/activity>/s correctly targets this only activity.

However, the sed approach remains fragile for XML manipulation. Using xmlstarlet instead would be more robust, preserve XML formatting, and scale better if the manifest structure ever changes. Consider this as an optional refactoring to improve maintainability and portability.

ANDROID_USB.md (1)

56-77: Expand troubleshooting and backup restoration guidance.

The documentation is comprehensive, but could be enhanced:

  1. Backup restoration: Line 62 mentions a backup is created, but doesn't explain where it's stored ($MANIFEST_PATH.bak) or how users can restore it if needed.
  2. Error recovery: The troubleshooting section could mention what to do if the patch script fails or produces an invalid manifest (hint: restore from the backup).

Consider adding a brief "Restoring from Backup" section that explains the .bak file location and how to recover if something goes wrong.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f9879f4 and fc31a5e.

📒 Files selected for processing (2)
  • ANDROID_USB.md (1 hunks)
  • scripts/patch-android-manifest.sh (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)
🔇 Additional comments (2)
scripts/patch-android-manifest.sh (1)

1-20: LGTM!

Proper validation, helpful error messages, and backup creation. The manifest path and error handling are appropriate for the Tauri Android structure.

ANDROID_USB.md (1)

1-20: LGTM!

Clear problem statement with good explanation of the Android rebuild issue and the patch-based solution. The required permissions list is accurate and helps readers understand what the script adds.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
scripts/patch-android-manifest.sh (1)

22-38: ** sed portability issues already flagged in past review.**

The sed portability concerns for lines 22-29 and similar issues for lines 31-38 (USB intent filter insertion) have been covered in the past review comment. Both sed operations suffer from the same macOS incompatibility and lack of XML validation.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae221c4 and b6b31db.

📒 Files selected for processing (5)
  • .github/workflows/ci.yml (2 hunks)
  • scripts/patch-android-manifest.sh (1 hunks)
  • src-tauri/Cargo.toml (1 hunks)
  • src-tauri/src/main.rs (1 hunks)
  • src-tauri/src/serial_android.rs (0 hunks)
💤 Files with no reviewable changes (1)
  • src-tauri/src/serial_android.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Android preview (APK)
  • GitHub Check: Tauri Linux preview (deb/appimage)
🔇 Additional comments (5)
src-tauri/Cargo.toml (1)

23-24: LGTM: Unified serial plugin simplifies cross-platform support.

The replacement of platform-specific serial dependencies with a single tauri-plugin-serialplugin dependency streamlines the build configuration and aligns with the simplified plugin initialization in main.rs.

.github/workflows/ci.yml (2)

129-133: LGTM: Java 21 upgrade appropriate for modern Android development.


154-156: LGTM: Manifest patching integrated into build workflow.

The patch step is correctly positioned after Android project initialization and before the build.

src-tauri/src/main.rs (1)

7-9: LGTM: Platform-agnostic plugin initialization.

The removal of conditional compilation directives and platform-specific branching simplifies the codebase and aligns with the unified tauri-plugin-serialplugin dependency.

scripts/patch-android-manifest.sh (1)

43-77: Document the source and compatibility of hardcoded USB device IDs.

The device filter includes numerous vendor-id/product-id pairs without documenting their sources or verification status. For maintainability and security, please verify and document:

  1. The source of each vendor/product ID pair (manufacturer specs, community testing, etc.)
  2. Which Betaflight firmware versions or hardware these correspond to
  3. Whether all listed devices have been tested with this implementation

Consider adding inline comments for each device group with references to official documentation or issue numbers where these IDs were verified.

Comment on lines 84 to 100
if [ -f "$APP_BUILD_GRADLE" ]; then
echo "Adding USB serial library dependency..."
if ! grep -q "usb-serial-for-android" "$APP_BUILD_GRADLE"; then
cat >> "$APP_BUILD_GRADLE" << 'EOF'
dependencies {
// USB Serial library for Android
implementation("com.github.mik3y:usb-serial-for-android:3.8.0")
}
EOF
echo "✓ USB serial library dependency added!"
else
echo "USB serial library dependency already present"
fi
else
echo "Warning: $APP_BUILD_GRADLE not found, skipping dependency addition"
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Risk of duplicate dependencies blocks in build.gradle.kts.

The script appends a dependencies block if "usb-serial-for-android" is not found (line 86), but doesn't check whether a dependencies block already exists in the file. Gradle build files typically have an existing dependencies block, so this logic will likely append a second block, potentially causing build errors or unexpected behavior.

Modify the script to insert the dependency within an existing dependencies block, or fail with a clear error message if the structure is unexpected:

 if [ -f "$APP_BUILD_GRADLE" ]; then
     echo "Adding USB serial library dependency..."
     if ! grep -q "usb-serial-for-android" "$APP_BUILD_GRADLE"; then
-        cat >> "$APP_BUILD_GRADLE" << 'EOF'
-
-dependencies {
-    // USB Serial library for Android
-    implementation("com.github.mik3y:usb-serial-for-android:3.8.0")
-}
-EOF
+        if grep -q "^dependencies {" "$APP_BUILD_GRADLE"; then
+            # Insert within existing dependencies block
+            sed -i '/^dependencies {/a \    // USB Serial library for Android\n    implementation("com.github.mik3y:usb-serial-for-android:3.8.0")' "$APP_BUILD_GRADLE"
+        else
+            echo "Error: No dependencies block found in $APP_BUILD_GRADLE"
+            exit 1
+        fi
         echo "✓ USB serial library dependency added!"

Note: This suggestion also inherits the sed portability issues flagged elsewhere in this review.

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
scripts/patch-android-manifest.sh (2)

35-37: Complex multi-line sed substitution is fragile and non-portable.

Line 35 uses a non-standard sed pattern (0,/<\/activity>/s|...|) with extensive embedded newlines that will fail or corrupt output on macOS and other systems with BSD sed.

The same platform-detection or xmlstarlet fallback from the previous comment applies here. A portable alternative using xmlstarlet:

-    sed -i '0,/<\/activity>/s|</activity>|\n            <!-- Intent filter for USB device attach -->\n            <intent-filter>\n                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />\n            </intent-filter>\n\n            <!-- USB device filter metadata -->\n            <meta-data\n                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"\n                android:resource="@xml/device_filter" />\n        </activity>|' "$MANIFEST_PATH"
+    xmlstarlet ed -L \
+      -s '//activity' -t elem -n 'intent-filter' \
+        -s '//activity/intent-filter' -t elem -n 'action' \
+          -a android:name -v 'android.hardware.usb.action.USB_DEVICE_ATTACHED' \
+      -s '//activity' -t elem -n 'meta-data' \
+        -a android:name -v 'android.hardware.usb.action.USB_DEVICE_ATTACHED' \
+        -a android:resource -v '@xml/device_filter' \
+      "$MANIFEST_PATH"

26-28: Fix sed portability for macOS—BSD sed incompatible with current multi-line insertion syntax.

The script uses GNU-specific sed syntax at lines 27, 36, and 91 that fails on macOS (BSD sed):

  • Line 27: Escaped newlines (\n) in i\ command are treated as literal characters by BSD sed, corrupting the XML
  • Line 36: The 0 address (first occurrence) is GNU-only; BSD sed doesn't support it
  • Line 91: Escaped newlines in a\ command have the same BSD incompatibility

Since Tauri's Android tooling supports cross-platform development including macOS, this script must work on both GNU and BSD sed variants.

Implement platform detection and use portable syntax:

+# Detect OS and set sed options
+if [[ "$OSTYPE" == "darwin"* ]]; then
+    # BSD sed requires empty string after -i
+    sed_i=(-i '')
+else
+    sed_i=(-i)
+fi
+
 # Check if USB permissions already added
 if grep -q "android.permission.USB_PERMISSION" "$MANIFEST_PATH"; then
     echo "USB permissions already present in manifest"
 else
     # Add USB permissions before </manifest>
-    sed -i '/<\/manifest>/i \    <!-- USB permissions for serial communication -->\n    <uses-permission android:name="android.permission.USB_PERMISSION" />\n    <uses-feature android:name="android.hardware.usb.host" android:required="false" />' "$MANIFEST_PATH"
+    sed "${sed_i[@]}" '/<\/manifest>/i\
+    <!-- USB permissions for serial communication -->\
+    <uses-permission android:name="android.permission.USB_PERMISSION" />\
+    <uses-feature android:name="android.hardware.usb.host" android:required="false" />' "$MANIFEST_PATH"
     echo "Added USB permissions to manifest"
 fi

Apply the same pattern (actual line continuations instead of \n escapes, and platform-aware sed invocation) to lines 36 and 91.

🧹 Nitpick comments (1)
scripts/patch-android-manifest.sh (1)

20-38: Consider adding XML validation after manifest modifications.

The script creates a backup (good), but does not validate that the modified manifest is still valid XML. If a sed command partially fails or corrupts the file, the error will go undetected until the build step.

Add a post-modification validation step:

# After all manifest modifications:
if command -v xmllint &> /dev/null; then
    if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
        echo "Error: Modified manifest is invalid XML. Restoring from backup."
        cp "$MANIFEST_PATH.bak" "$MANIFEST_PATH"
        exit 1
    fi
fi

This provides early detection of corruption and a automatic recovery path.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6b31db and 74a3266.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml (2 hunks)
  • scripts/patch-android-manifest.sh (1 hunks)
  • src-tauri/Cargo.toml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/ci.yml
  • src-tauri/Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Android preview (APK)
  • GitHub Check: Tauri Linux preview (deb/appimage)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/ci.yml (1)

157-171: Verified: Fix required to prevent duplicate allprojects blocks in generated build.gradle.kts.

The generated src-tauri/gen/android/build.gradle.kts will contain an allprojects block (matching the committed ./android/build.gradle structure). The current logic checks only for "jitpack.io" absence and blindly appends a new allprojects block, which creates duplicate or malformed Gradle configuration and breaks the build.

The fix must detect an existing allprojects block and insert the maven repository into it, rather than appending a new block:

-          if [ -f "$FILE" ]; then
-            echo "Ensuring JitPack repository in $FILE..."
-            if ! grep -q "jitpack.io" "$FILE"; then
-              echo "Adding JitPack repository..."
-              printf '\nallprojects {\n    repositories {\n        maven(url = "https://jitpack.io")\n    }\n}\n' >> "$FILE"
-            fi
+          if [ -f "$FILE" ]; then
+            echo "Ensuring JitPack repository in $FILE..."
+            if ! grep -q "jitpack.io" "$FILE"; then
+              if grep -q "^allprojects {" "$FILE"; then
+                echo "allprojects block exists; inserting JitPack into existing block..."
+                sed -i '/^allprojects {/a\    repositories {\n        maven(url = "https://jitpack.io")\n    }' "$FILE"
+              else
+                echo "Adding new allprojects block with JitPack..."
+                printf '\nallprojects {\n    repositories {\n        maven(url = "https://jitpack.io")\n    }\n}\n' >> "$FILE"
+              fi
+            fi

Note: The sed approach has portability concerns; consider awk for better cross-platform compatibility.

🧹 Nitpick comments (1)
scripts/patch-android-manifest.sh (1)

88-99: Excellent use of awk for portable dependency insertion.

The shift from sed to awk on lines 91–97 makes this logic portable to macOS and Linux. However, the regex ^dependencies { on line 88 assumes the dependencies block starts at the beginning of the line. In typical Kotlin build files, this block is not indented, so this should work; however, consider using grep -E "dependencies\s*\{" (without anchors) for robustness if the build file is reformatted.

This is a minor concern that can be addressed in a follow-up if needed.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74a3266 and c2163bd.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml (2 hunks)
  • scripts/patch-android-manifest.sh (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)

- Created test workflow to verify manifest patching is applied correctly
- Updated ANDROID_USB.md with current status and known issues
- Added ANDROID_USB_DEBUGGING.md with investigation steps and troubleshooting guide
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a801f59 and cadf39f.

📒 Files selected for processing (3)
  • .github/workflows/test-android-patch.yml (1 hunks)
  • ANDROID_USB.md (1 hunks)
  • ANDROID_USB_DEBUGGING.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
ANDROID_USB_DEBUGGING.md

[style] ~16-~16: ‘FIRST PRIORITY’ might be wordy. Consider a shorter alternative.
Context: ...Steps ### 1. Verify Manifest Patching (FIRST PRIORITY) Run the test workflow: ```bash # Push...

(EN_WORDINESS_PREMIUM_FIRST_PRIORITY)

🪛 markdownlint-cli2 (0.18.1)
ANDROID_USB.md

42-42: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)
🔇 Additional comments (5)
ANDROID_USB_DEBUGGING.md (1)

1-121: Comprehensive debugging guide looks good overall.

The document is well-structured and provides clear investigation steps, code examples, and troubleshooting guidance. A few minor refinements:

  1. Simplify emphasis on line 16 — "FIRST PRIORITY" is slightly wordy. Consider "PRIMARY STEP" or "STEP 1: Verify Manifest Patching" as a cleaner heading style.

  2. Documentation is well-aligned with the workflow — The instructions properly reference the test-android-patch.yml workflow and match the patch script's expected behavior described elsewhere in the PR.

ANDROID_USB.md (2)

34-67: Usage section is clear and well-structured.

The build workflow instructions are clear and progressively layered (initialize → patch → build). The automated workflow section (lines 56–67) nicely summarizes the steps for users who prefer a combined command.


69-89: Documentation aligns well with companion script and debugging guide.

The "What the Script Does" section accurately describes the expected behavior of scripts/patch-android-manifest.sh and clearly maps to the verification steps in ANDROID_USB_DEBUGGING.md. The troubleshooting section addresses sequencing pitfalls (patch after init, before build) that are common sources of user error.

.github/workflows/test-android-patch.yml (2)

1-103: Workflow structure is sound and verified.

The Tauri CLI supports the --ci flag for non-interactive Android initialization, confirming line 45 is correct.

The workflow follows good CI/CD practices:

  • Proper environment setup sequence (Java → Android SDK → Rust → targets)
  • Pre/post-patch verification with grep checks
  • Conditional JitPack repository addition (line 85) prevents duplicates
  • Artifact upload (7 days) enables inspection of generated files

75-92: I need to check the repository for any gradle template references or check what tauri versions might be using.

The review comment appears to be based on outdated Gradle patterns and may be incorrect.

Modern Android projects use dependencyResolutionManagement with repositories in settings.gradle.kts, not allprojects blocks in build.gradle.kts. Tauri-generated build.gradle.kts files include plugins {}, android {}, and configuration blocks following the modern Kotlin DSL pattern.

The workflow code appends a Groovy-style allprojects { repositories { ... } } block to a Kotlin DSL file. The Kotlin DSL uses build.gradle.kts syntax instead of the older Groovy build.gradle, so this pattern mixing may not work as intended. Additionally, repository configuration in modern Android projects should be in settings.gradle.kts via dependencyResolutionManagement, not in build.gradle.kts via allprojects.

The concern about duplicate allprojects blocks is likely unfounded because modern Tauri-generated projects do not use this deprecated pattern.

…ibility

The sed -i command was failing silently due to different behavior on macOS vs Linux.
Rewrote manifest patching to use awk which is more portable and reliable.

This should fix the issue where the USB intent filter wasn't being added,
causing the app to not prompt for USB permission when devices are attached.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
ANDROID_USB_DEBUGGING.md (3)

21-21: Simplify phrasing in section heading.

"FIRST PRIORITY" is slightly verbose; consider shortening to "HIGH PRIORITY" or "PRIORITY" for conciseness.


47-47: Add language identifier to fenced code block.

The code block at line 47 should specify bash for syntax highlighting and proper rendering.

-```
+```bash
 lsusb

96-96: Wrap bare URL in markdown link syntax.

Bare URLs should be wrapped in markdown link format for better documentation rendering.

-4. **Review plugin source code** at https://github.com/s00d/tauri-plugin-serialplugin/tree/main/android
+4. **Review plugin source code** at [tauri-plugin-serialplugin Android source](https://github.com/s00d/tauri-plugin-serialplugin/tree/main/android)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cadf39f and eb441f4.

📒 Files selected for processing (2)
  • ANDROID_USB_DEBUGGING.md (1 hunks)
  • scripts/patch-android-manifest.sh (1 hunks)
🧰 Additional context used
🪛 LanguageTool
ANDROID_USB_DEBUGGING.md

[style] ~21-~21: ‘FIRST PRIORITY’ might be wordy. Consider a shorter alternative.
Context: ...Steps ### 1. Verify Manifest Patching (FIRST PRIORITY) Run the test workflow: ```bash # Push...

(EN_WORDINESS_PREMIUM_FIRST_PRIORITY)

🪛 markdownlint-cli2 (0.18.1)
ANDROID_USB_DEBUGGING.md

47-47: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


96-96: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (3)
scripts/patch-android-manifest.sh (3)

27-61: ✅ Good use of awk for cross-platform portability.

The script correctly uses awk for XML insertions (lines 27–61) instead of the previous sed commands, ensuring the script works on both macOS and Linux. The found variable in the second awk block (line 46) properly limits the intent filter insertion to the first </activity> match.


66-101: Verify decimal VID/PID values match expected USB devices.

The device_filter.xml uses decimal format for IDs, which is correct per Android documentation, though IDs are often specified in hex format by manufacturers. The conversions appear reasonable (e.g., 1027 = 0x0403 for FTDI), but verify that the product IDs (e.g., 12886 for "STM32 in HID mode") match your target devices. Users may need to add their specific device VID/PID combinations if they're not in this list.


114-138: Good defensive Gradle dependency insertion logic.

The script correctly checks for both the existence of dependencies block and the library presence before inserting. The awk-based insertion (lines 114–120) is portable and the fallback to appending a new block (lines 124–130) handles edge cases gracefully.

Comment on lines +27 to +59
# Using awk for portability across macOS and Linux
awk '
/<\/manifest>/ {
print " <!-- USB permissions for serial communication -->"
print " <uses-permission android:name=\"android.permission.USB_PERMISSION\" />"
print " <uses-feature android:name=\"android.hardware.usb.host\" android:required=\"false\" />"
}
{ print }
' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
echo "Added USB permissions to manifest"
fi

# Check if USB intent filter already added
if grep -q "USB_DEVICE_ATTACHED" "$MANIFEST_PATH"; then
echo "USB intent filter already present in manifest"
else
# Add USB device intent filter and metadata before </activity>
# Using awk for portability across macOS and Linux
awk '
/<\/activity>/ && !found {
print " <!-- Intent filter for USB device attach -->"
print " <intent-filter>"
print " <action android:name=\"android.hardware.usb.action.USB_DEVICE_ATTACHED\" />"
print " </intent-filter>"
print ""
print " <!-- USB device filter metadata -->"
print " <meta-data"
print " android:name=\"android.hardware.usb.action.USB_DEVICE_ATTACHED\""
print " android:resource=\"@xml/device_filter\" />"
found=1
}
{ print }
' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add XML validation after manifest modifications.

The script modifies the manifest and creates device_filter.xml but never validates the resulting XML is well-formed. If modifications are incorrect or incomplete, the build will fail later during the Gradle phase. Consider adding a quick validation check after both awk operations:

# After the manifest modifications (around line 61)
if command -v xmllint &> /dev/null; then
    xmllint --noout "$MANIFEST_PATH" || { echo "❌ Manifest XML validation failed"; exit 1; }
else
    echo "⚠️  Warning: xmllint not found, skipping XML validation"
fi

This addresses a concern flagged in the previous review.

Do you want me to generate the complete updated script with XML validation integrated?

🤖 Prompt for AI Agents
In scripts/patch-android-manifest.sh around lines 27 to 59, the script updates
AndroidManifest.xml but does not validate the resulting XML; add an xmllint
validation step after each awk modification (i.e., immediately after the first
mv that writes MANIFEST_PATH and immediately after the second mv that writes
MANIFEST_PATH) so the script runs `xmllint --noout "$MANIFEST_PATH"` when
xmllint is available, exits with a non-zero status and a clear error message on
validation failure, and prints a warning and continues (or documents skipping)
if xmllint is not installed.

The tauri-plugin-serialplugin doesn't automatically request USB permissions
on Android. Created a custom MainActivity that:

- Registers broadcast receivers for USB attach/detach events
- Automatically requests permission when USB devices are detected
- Checks for already connected devices on app launch
- Handles permission dialog responses
- Includes extensive logging for debugging

The patch script now copies this MainActivity into the generated Android
project, replacing the default TauriActivity.

This should fix the issue where the app didn't prompt for USB permission
and couldn't detect any serial ports.
Added comprehensive testing guide including:
- How to monitor logcat for USB events
- Three test scenarios (pre-connected, hot plug, app selector)
- Common issues and fixes
- What to look for in logs (good vs bad signs)
The MainActivity.kt was missing the import for TauriActivity from app.tauri package,
causing Kotlin compilation errors. Added the required import statement.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
.github/workflows/test-android-patch.yml (2)

58-74: Assert the patch outcome, don’t just print

Currently this step only cats/greps loosely. Add explicit assertions for usb.host feature and the usb-serial dependency so the job fails if patching regresses.

Apply this diff to harden the checks:

       - name: Show files after patch
         run: |
           echo "=== AndroidManifest.xml AFTER patch ==="
           cat src-tauri/gen/android/app/src/main/AndroidManifest.xml
           echo ""
           echo "=== Checking for USB permissions ==="
-          grep -i "usb" src-tauri/gen/android/app/src/main/AndroidManifest.xml || echo "No USB permissions found!"
+          set -e
+          grep -qi 'android.hardware.usb.host' src-tauri/gen/android/app/src/main/AndroidManifest.xml || (echo "Missing usb.host feature!" && exit 1)
+          grep -qi 'intent-filter' src-tauri/gen/android/app/src/main/AndroidManifest.xml || (echo "Missing intent-filter!" && exit 1)
           echo ""
           echo "=== device_filter.xml ==="
           cat src-tauri/gen/android/app/src/main/res/xml/device_filter.xml || echo "device_filter.xml not found!"
           echo ""
           echo "=== MainActivity.kt ==="
           cat src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt || echo "MainActivity.kt not found!"
           echo ""
           echo "=== app/build.gradle.kts dependencies ==="
-          grep -A 10 "dependencies {" src-tauri/gen/android/app/build.gradle.kts || echo "No dependencies block found!"
+          grep -A 10 "dependencies {" src-tauri/gen/android/app/build.gradle.kts || (echo "No dependencies block found!" && exit 1)
+          grep -qi 'com.github.mik3y:usb-serial-for-android' src-tauri/gen/android/app/build.gradle.kts || (echo "usb-serial dependency missing!" && exit 1)

55-57: Make the patch step fail verbosely on any error

Enable xtrace and pipefail when running the patch script for easier debugging and to avoid silent failures.

-      - name: Patch Android manifest for USB support
-        run: bash scripts/patch-android-manifest.sh
+      - name: Patch Android manifest for USB support
+        run: bash -euxo pipefail scripts/patch-android-manifest.sh
scripts/MainActivity.kt (3)

16-18: Make constants static and explicit

Prefer companion object + const for TAG and action string. Minor perf/readability win.

-class MainActivity : TauriActivity() {
-    private val TAG = "BetaflightUSB"
-    private val ACTION_USB_PERMISSION = "com.betaflight.configurator.USB_PERMISSION"
+class MainActivity : TauriActivity() {
+    companion object {
+        private const val TAG = "BetaflightUSB"
+        private const val ACTION_USB_PERMISSION = "com.betaflight.configurator.USB_PERMISSION"
+    }

23-40: Drop unnecessary synchronized block in onReceive

onReceive runs on the main thread for this dynamic receiver; no shared mutable state here. The lock adds overhead without benefit.

-                ACTION_USB_PERMISSION -> {
-                    synchronized(this) {
-                        val device: UsbDevice? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-                            intent.getParcelableExtra(UsbManager.EXTRA_DEVICE, UsbDevice::class.java)
-                        } else {
-                            @Suppress("DEPRECATION")
-                            intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
-                        }
-                        
-                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
-                            device?.let {
-                                Log.d(TAG, "Permission granted for device ${it.deviceName}")
-                                // Device is ready to use
-                            }
-                        } else {
-                            Log.d(TAG, "Permission denied for device ${device?.deviceName}")
-                        }
-                    }
-                }
+                ACTION_USB_PERMISSION -> {
+                    val device: UsbDevice? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+                        intent.getParcelableExtra(UsbManager.EXTRA_DEVICE, UsbDevice::class.java)
+                    } else {
+                        @Suppress("DEPRECATION")
+                        intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
+                    }
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                        device?.let { Log.d(TAG, "Permission granted for device ${it.deviceName}") }
+                    } else {
+                        Log.d(TAG, "Permission denied for device ${device?.deviceName}")
+                    }
+                }

100-103: Guard receiver unregister to avoid IllegalArgumentException

Defensive guard prevents crashes if lifecycle changes later.

-        unregisterReceiver(usbReceiver)
+        try {
+            unregisterReceiver(usbReceiver)
+        } catch (e: IllegalArgumentException) {
+            Log.w(TAG, "usbReceiver already unregistered", e)
+        }
ANDROID_USB_DEBUGGING.md (2)

56-72: Use headings instead of bold for scenario titles

Satisfy MD036 and improve structure.

-**Test A: Device Already Connected**
+#### Test A: Device Already Connected
...
-**Test B: Hot Plug**
+#### Test B: Hot Plug
...
-**Test C: App Selector**
+#### Test C: App Selector

89-99: Add languages to fenced code blocks

Satisfy MD040 and improve readability.

-```
+```text
 Bus 001 Device 005: ID 0483:5740 STMicroelectronics Virtual COM Port
                       ^^^^ ^^^^
                       VID  PID

- +text
BetaflightUSB: Checking connected USB devices: 1 found
BetaflightUSB: Device: /dev/bus/usb/001/005, VID: 1155, PID: 22336
BetaflightUSB: Requesting USB permission for /dev/bus/usb/001/005
BetaflightUSB: Permission granted for device /dev/bus/usb/001/005


-```
+```text
BetaflightUSB: Checking connected USB devices: 0 found
# ^ Device not detected by Android at all

BetaflightUSB: Permission denied for device /dev/bus/usb/001/005
# ^ User denied permission or dialog didn't work

# No logs at all
# ^ MainActivity not installed or crashed

- +text
=== MainActivity.kt ===
package com.betaflight.configurator
...

Also applies to: 107-113, 115-125, 134-139

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb441f4 and 2eb9aaa.

📒 Files selected for processing (5)
  • .github/workflows/test-android-patch.yml (1 hunks)
  • ANDROID_USB.md (1 hunks)
  • ANDROID_USB_DEBUGGING.md (1 hunks)
  • scripts/MainActivity.kt (1 hunks)
  • scripts/patch-android-manifest.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • scripts/patch-android-manifest.sh
  • ANDROID_USB.md
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
ANDROID_USB_DEBUGGING.md

56-56: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


64-64: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


72-72: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


89-89: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


107-107: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


115-115: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


134-134: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Android preview (APK)
  • GitHub Check: Tauri Linux preview (deb/appimage)
🔇 Additional comments (1)
scripts/MainActivity.kt (1)

148-152: Correct PendingIntent flags for S+ USB permission flow

Use of FLAG_MUTABLE for S+ is correct because the system fills extras. No changes needed.

If you want to ensure no collisions across simultaneous requests, consider using a unique requestCode:

-            0,
+            device.deviceId,

Comment on lines 75 to 92
- name: Ensure JitPack repository
shell: bash
run: |
set -euo pipefail
FILE="src-tauri/gen/android/build.gradle.kts"
if [ -f "$FILE" ]; then
echo "=== ROOT BUILD.GRADLE.KTS BEFORE JITPACK ==="
cat "$FILE"
echo ""
echo "Ensuring JitPack repository in $FILE..."
if ! grep -q "jitpack.io" "$FILE"; then
echo "Adding JitPack repository..."
printf '\nallprojects {\n repositories {\n maven(url = "https://jitpack.io")\n }\n}\n' >> "$FILE"
fi
echo ""
echo "=== ROOT BUILD.GRADLE.KTS AFTER JITPACK ==="
cat "$FILE"
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix JitPack repository injection: target settings.gradle.kts and Kotlin DSL syntax

Appending an allprojects block to build.gradle.kts is discouraged in Gradle 8+ and often ignored when repositoriesMode FAIL_ON_PROJECT_REPOS is enabled. Also, maven(url = "...") is not idiomatic Kotlin DSL. Patch settings.gradle.kts under dependencyResolutionManagement instead.

Apply this diff to replace the step and use Kotlin DSL:

-      - name: Ensure JitPack repository
-        shell: bash
-        run: |
-          set -euo pipefail
-          FILE="src-tauri/gen/android/build.gradle.kts"
-          if [ -f "$FILE" ]; then
-            echo "=== ROOT BUILD.GRADLE.KTS BEFORE JITPACK ==="
-            cat "$FILE"
-            echo ""
-            echo "Ensuring JitPack repository in $FILE..."
-            if ! grep -q "jitpack.io" "$FILE"; then
-              echo "Adding JitPack repository..."
-              printf '\nallprojects {\n    repositories {\n        maven(url = "https://jitpack.io")\n    }\n}\n' >> "$FILE"
-            fi
-            echo ""
-            echo "=== ROOT BUILD.GRADLE.KTS AFTER JITPACK ==="
-            cat "$FILE"
-          fi
+      - name: Ensure JitPack repository (settings.gradle.kts)
+        shell: bash
+        run: |
+          set -euo pipefail
+          FILE="src-tauri/gen/android/settings.gradle.kts"
+          if [ -f "$FILE" ]; then
+            echo "=== settings.gradle.kts BEFORE JITPACK ==="
+            cat "$FILE"; echo ""
+            if grep -q 'dependencyResolutionManagement' "$FILE"; then
+              if ! grep -q 'https://jitpack.io' "$FILE"; then
+                echo "Adding JitPack to dependencyResolutionManagement.repositories..."
+                awk '
+                  /dependencyResolutionManagement/ {print; inBlock=1; next}
+                  inBlock && /repositories\s*\{/ && !added {print; print "        maven(\"https://jitpack.io\")"; added=1; next}
+                  {print}
+                ' "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
+              fi
+            else
+              printf '\ndependencyResolutionManagement {\n    repositories {\n        mavenCentral()\n        google()\n        maven("https://jitpack.io")\n    }\n}\n' >> "$FILE"
+            fi
+            echo "=== settings.gradle.kts AFTER JITPACK ==="
+            cat "$FILE"
+          fi

Run to confirm where repositories are sourced:


🏁 Script executed:

#!/bin/bash
rg -n "dependencyResolutionManagement|jitpack|repositoriesMode" -S src-tauri/gen/android 2>/dev/null || true

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if src-tauri/gen/android directory exists and list contents
if [ -d "src-tauri/gen/android" ]; then
  echo "=== src-tauri/gen/android exists ==="
  find "src-tauri/gen/android" -type f \( -name "*.gradle*" -o -name "*.kts" \) 2>/dev/null | head -20
else
  echo "src-tauri/gen/android does not exist"
fi

# Search for any gradle or kts files in src-tauri
echo ""
echo "=== Searching for gradle/kts files in src-tauri ==="
find src-tauri -type f \( -name "*.gradle.kts" -o -name "*.gradle" \) 2>/dev/null | head -20

# Check if settings.gradle.kts or build.gradle.kts exist elsewhere
echo ""
echo "=== Checking entire repo for build.gradle.kts or settings.gradle.kts ==="
find . -maxdepth 5 -type f \( -name "build.gradle.kts" -o -name "settings.gradle.kts" \) 2>/dev/null

Length of output: 163


🏁 Script executed:

#!/bin/bash
# View the entire test-android-patch.yml workflow to understand context
cat .github/workflows/test-android-patch.yml

Length of output: 3674


🌐 Web query:

Tauri android init gradle structure settings.gradle.kts

💡 Result:

Short answer — what tauri android init produces and what goes in settings.gradle.kts

  • The Android project is generated at src-tauri/gen/android as a Gradle multi-project (root + modules). settings.gradle.kts lives at that generated android root and declares the included modules and repository resolution rules. [1][2]

  • Typical responsibilities of settings.gradle.kts in a Tauri-generated project:

    • include the app module (usually ":app") and the Tauri Android library/project (names vary; older templates used :tauri-android / :tauri).
    • set dependencyResolutionManagement / repositoriesMode and repositories so subprojects don’t each declare their own repos.
    • (optionally) pluginManagement or version catalogs if the template uses them. [1][2]
  • Minimal example (Kotlin DSL) you can expect or copy into the generated android root:

    • include(":app")
    • include(":tauri-android") // or the module name your template created
    • dependencyResolutionManagement {
      repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
      repositories {
      google()
      mavenCentral()
      }
      }
      (Adapt module names to whatever src-tauri/gen/android contains.) [1][2]
  • Notes:

    • Tauri’s Android templates have been updated to recent Gradle / Android Gradle Plugin versions (Gradle 8.x / AGP 8.x in current templates), so you may need recent Android Studio / JDK versions. Check the Tauri CLI/release notes for the exact template versions you have. [3]

Sources

  • Gradle: Organizing multi-project builds / settings.gradle.kts (explains settings file role and dependencyResolutionManagement). [1]
  • Community Tauri Android setup guides showing the generated layout and where files live (src-tauri/gen/android, app/build.gradle.kts). [2]
  • Tauri CLI / template release notes mentioning Gradle/AGP updates. [3]

🌐 Web query:

Kotlin DSL maven repository syntax gradle

💡 Result:

Short examples for declaring Maven repositories in Gradle Kotlin DSL (build.gradle.kts or settings.gradle.kts):

  • common built-ins
    repositories {
    mavenCentral()
    mavenLocal()
    google()
    }
    [1]

  • custom Maven URL (build.gradle.kts)
    repositories {
    maven {
    url = uri("https://my.repo.example/maven")
    }
    }
    [1][2]

  • with name + credentials (username/password)
    repositories {
    maven {
    name = "MyRepo"
    url = uri("https://my.repo.example/maven")
    credentials(PasswordCredentials::class) {
    username = findProperty("repoUser") as String?
    password = findProperty("repoPassword") as String?
    }
    }
    }
    [2]

  • token/HTTP-header auth example (GitLab style)
    val gitLabToken: String by project
    repositories {
    maven {
    url = uri("https://gitlab.com/api/v4/projects/12345/packages/maven")
    name = "GitLab"
    credentials(org.gradle.plugin.auth.HttpHeaderCredentials::class) {
    name = "Private-Token"
    value = gitLabToken
    }
    authentication { create<org.gradle.plugin.auth.HttpHeaderAuthentication>("header") }
    }
    }
    [3]

  • centralizing in settings.gradle.kts (dependencyResolutionManagement)
    dependencyResolutionManagement {
    repositories {
    mavenCentral()
    maven { url = uri("https://my.repo.example/maven") }
    }
    }
    [1][3]

References:

  • Gradle — Declaring repositories (Kotlin DSL examples). [1]
  • MavenArtifactRepository / properties (credentials, url). [2]
  • Kotlin DSL examples including GitLab token / StackOverflow translation. [3]

Fix JitPack repository injection: target settings.gradle.kts with correct Kotlin DSL syntax

The original approach appends allprojects to build.gradle.kts using Groovy syntax, which is incompatible with Kotlin DSL (.kts) files and ignored in Gradle 8+ when repositoriesMode.FAIL_ON_PROJECT_REPOS is enabled. The correct target is settings.gradle.kts under dependencyResolutionManagement.

However, the proposed fix also contains incorrect Kotlin DSL syntax. In Kotlin DSL, the correct syntax is maven { url = uri("https://jitpack.io") }, not maven("url").

Replace the step with:

       - name: Ensure JitPack repository (settings.gradle.kts)
         shell: bash
         run: |
           set -euo pipefail
           FILE="src-tauri/gen/android/settings.gradle.kts"
           if [ -f "$FILE" ]; then
             echo "=== settings.gradle.kts BEFORE JITPACK ==="
             cat "$FILE"; echo ""
             if grep -q 'dependencyResolutionManagement' "$FILE"; then
               if ! grep -q 'https://jitpack.io' "$FILE"; then
                 echo "Adding JitPack to dependencyResolutionManagement.repositories..."
                 sed -i '/repositories\s*{/a\        maven { url = uri("https://jitpack.io") }' "$FILE"
               fi
             else
               printf '\ndependencyResolutionManagement {\n    repositories {\n        mavenCentral()\n        google()\n        maven { url = uri("https://jitpack.io") }\n    }\n}\n' >> "$FILE"
             fi
             echo "=== settings.gradle.kts AFTER JITPACK ==="
             cat "$FILE"
           fi
🤖 Prompt for AI Agents
.github/workflows/test-android-patch.yml around lines 75 to 92: the workflow
currently appends a Groovy-style allprojects block into
src-tauri/gen/android/build.gradle.kts which is incompatible with Kotlin DSL and
ignored under Gradle 8+ with repositoriesMode.FAIL_ON_PROJECT_REPOS; instead
modify the step to target settings.gradle.kts and inject a Kotlin DSL
dependencyResolutionManagement block (or merge into existing one) that adds the
JitPack repository using correct Kotlin DSL syntax: repositories { maven { url =
uri("https://jitpack.io") } }; ensure you check for an existing JitPack uri to
avoid duplication and preserve file integrity rather than appending Groovy code
to build.gradle.kts.

Comment on lines 35 to 36
adb install -r gen/android/app/build/outputs/apk/universal/release/app-universal-release-unsigned.apk
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Install the debug variant or use Gradle install task

Unsigned release APK won’t install. Recommend installing debug or using Gradle.

-adb install -r gen/android/app/build/outputs/apk/universal/release/app-universal-release-unsigned.apk
+./gradlew -p gen/android :app:installDebug
+# or:
+# adb install -r gen/android/app/build/outputs/apk/universal/debug/app-universal-debug.apk
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
adb install -r gen/android/app/build/outputs/apk/universal/release/app-universal-release-unsigned.apk
```
./gradlew -p gen/android :app:installDebug
# or:
# adb install -r gen/android/app/build/outputs/apk/universal/debug/app-universal-debug.apk
🤖 Prompt for AI Agents
In ANDROID_USB_DEBUGGING.md around lines 35-36, the example shows installing an
unsigned release APK which won’t install on devices; update the instructions to
either use the debug APK path (e.g.,
gen/android/app/build/outputs/apk/debug/app-debug.apk) or recommend running the
Gradle install task (./gradlew installDebug) — alternatively note that a release
APK must be properly signed before installation and show the signed APK path or
signing/signingConfig step.

Copy link
Member

@nerdCopter nerdCopter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • approving untested

… DSL

Changed from incorrectly appending Groovy-style allprojects block to
build.gradle.kts (which is ignored in Gradle 8+ with FAIL_ON_PROJECT_REPOS)
to properly injecting JitPack repository into settings.gradle.kts using
correct Kotlin DSL syntax: maven { url = uri("https://jitpack.io") }

This inserts the repository into the existing dependencyResolutionManagement
repositories block, which is the correct location for Gradle 8+.
The CI workflow step was running too early and the awk pattern wasn't
matching correctly. Moved the JitPack repository injection into the
patch-android-manifest.sh script so it runs at the right time and uses
the same proven awk approach as the other patches.

This ensures the JitPack repository is added to settings.gradle.kts
so that usb-serial-for-android:3.9.0 can be resolved.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
scripts/patch-android-manifest.sh (2)

117-149: Gradle dependency insertion handles both existing and missing dependencies blocks.

The script correctly checks for an existing dependencies block (line 122) and inserts the USB library into it using awk. If no block exists, it appends one. However, the grep pattern ^dependencies { assumes the block starts at the beginning of a line, which could fail if the build.gradle.kts uses indentation or different formatting.

Consider making the pattern more flexible to handle indented dependencies blocks:

-        if grep -q "^dependencies {" "$APP_BUILD_GRADLE"; then
+        if grep -q "^\s*dependencies\s*{" "$APP_BUILD_GRADLE"; then
             echo "Inserting into existing dependencies block..."
-            awk '/^dependencies \{/ {
+            awk '/^\s*dependencies\s*\{/ {
                 print
                 print "    // USB Serial library for Android"
                 print "    implementation(\"com.github.mik3y:usb-serial-for-android:3.9.0\")"

This addresses potential formatting variations in generated Gradle files.


23-62: Add XML validation after manifest modifications.

The script modifies the manifest via awk insertions (lines 27–36 and 46–60) but never validates the resulting XML is well-formed. If awk produces malformed XML due to an unexpected manifest structure, the error propagates silently until the Gradle build fails. This issue was flagged in previous reviews but remains unaddressed.

Add XML validation after both manifest modifications:

# After line 38 (USB permissions insertion):
if command -v xmllint &> /dev/null; then
    if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
        echo "❌ Manifest XML validation failed after USB permissions insertion"
        exit 1
    fi
fi

# After line 62 (intent filter insertion):
if command -v xmllint &> /dev/null; then
    if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
        echo "❌ Manifest XML validation failed after intent filter insertion"
        exit 1
    fi
fi

Or consolidate into a helper function and call it once after all modifications complete.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2eb9aaa and 2f2e9ab.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml (2 hunks)
  • scripts/patch-android-manifest.sh (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)
🔇 Additional comments (6)
scripts/patch-android-manifest.sh (4)

27-38: ✓ Awk-based USB permissions insertion is platform-portable.

The migration from sed to awk for USB permissions insertion addresses the macOS/BSD sed compatibility issues flagged in previous reviews. The conditional check (line 24) prevents duplicate insertions, and the awk pattern correctly targets the closing </manifest> tag.


40-62: ✓ Awk-based intent filter insertion with !found guard prevents duplicates.

The USB device intent-filter insertion correctly uses the !found flag to ensure the block is inserted only once, even if the script runs multiple times. The indentation and escaping are properly handled.


64-102: ✓ Device filter XML is well-formed and comprehensive.

The hardcoded USB device list covers common Betaflight-compatible microcontroller families (STM32, CP210x, GD32, AT32, APM32, Raspberry Pi Pico, etc.) and is properly formatted. The use of a heredoc with proper XML escaping is safe.


155-176: ✓ JitPack repository insertion is correctly guarded and portable.

The awk implementation for inserting the JitPack maven entry into the existing repositories block uses the !found flag to prevent duplicates and is portable across platforms.

.github/workflows/ci.yml (2)

129-133: ✓ Java version upgrade to 21 is straightforward.

The upgrade from Java 17 to 21 in the tauri-android-preview job is a simple version bump with no other changes. Ensure downstream code (Gradle, Tauri, etc.) is compatible with Java 21.


154-155: ✓ Patch step is correctly positioned in the workflow.

The new step "Patch Android manifest for USB support" runs at the right point: after "Initialize Tauri Android project" (which generates the required files) and before "Build Tauri Android APK". This ensures the manifest and Gradle configuration are patched before the build consumes them.

…ttings.gradle.kts

- Target the correct repositories (dependency resolution, not pluginManagement)
- Robust awk block tracking to avoid inserting in wrong block
- Append full dependencyResolutionManagement block if missing
- Log repository lines for verification
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
scripts/patch-android-manifest.sh (2)

155-200: Consider improving robustness of JitPack repository insertion.

The awk logic for inserting the JitPack repository (lines 162–176) relies on brace tracking and assumes a specific Gradle file structure (e.g., braces on the same line, repositories { on its own line). If the Gradle file format varies, the insertion could fail silently or insert in an incorrect location. The fallback logic helps (lines 179–190), but the primary insertion path is brittle.

Consider one of the following:

  1. Add a post-insertion validation step to confirm the repository was added correctly.
  2. Use a more lenient pattern match that tolerates formatting variations (e.g., repositories\s*\{).
  3. Document that settings.gradle.kts must follow a specific format for this insertion to work.

1-22: Add error handling and validation for awk operations.

The script uses set -e to exit on error, but doesn't validate that awk operations succeeded or produced valid output. If awk fails silently or produces a truncated file, the corruption won't be caught. After each awk operation, verify the output exists and is non-empty before moving it:

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
+   if [ ! -s "$MANIFEST_PATH" ]; then
+       echo "Error: Manifest modification resulted in empty file"
+       cp "$MANIFEST_PATH.bak" "$MANIFEST_PATH"
+       exit 1
+   fi

Apply this check after each awk-to-tmp-file-and-mv sequence (lines 36, 60, 131, 176).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f2e9ab and e9c511e.

📒 Files selected for processing (1)
  • scripts/patch-android-manifest.sh (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)

Comment on lines +27 to +62
# Add USB permissions before </manifest>
# Using awk for portability across macOS and Linux
awk '
/<\/manifest>/ {
print " <!-- USB permissions for serial communication -->"
print " <uses-permission android:name=\"android.permission.USB_PERMISSION\" />"
print " <uses-feature android:name=\"android.hardware.usb.host\" android:required=\"false\" />"
}
{ print }
' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
echo "Added USB permissions to manifest"
fi

# Check if USB intent filter already added
if grep -q "USB_DEVICE_ATTACHED" "$MANIFEST_PATH"; then
echo "USB intent filter already present in manifest"
else
# Add USB device intent filter and metadata before </activity>
# Using awk for portability across macOS and Linux
awk '
/<\/activity>/ && !found {
print " <!-- Intent filter for USB device attach -->"
print " <intent-filter>"
print " <action android:name=\"android.hardware.usb.action.USB_DEVICE_ATTACHED\" />"
print " </intent-filter>"
print ""
print " <!-- USB device filter metadata -->"
print " <meta-data"
print " android:name=\"android.hardware.usb.action.USB_DEVICE_ATTACHED\""
print " android:resource=\"@xml/device_filter\" />"
found=1
}
{ print }
' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
echo "Added USB intent filter to manifest"
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Add XML validation after manifest modifications.

Past reviews flagged the lack of XML validation after manifest changes. The script modifies the manifest with awk operations but never validates the resulting XML is well-formed. If any awk insertion is incorrect or incomplete, the XML could be corrupted, and this error would only surface later during the Gradle build phase.

Add validation after both awk modifications:

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB permissions to manifest"
+   
+   # Validate XML is well-formed
+   if command -v xmllint &> /dev/null; then
+       xmllint --noout "$MANIFEST_PATH" || { echo "❌ Manifest XML validation failed"; exit 1; }
+   fi
 fi

Apply the same validation after the intent-filter insertion (around line 62).


I'll verify the review comment by examining the actual file and validating the claims made.

I need to verify the claims made in the review comment by examining the actual file. Let me gather the necessary information.


🏁 Script executed:

#!/bin/bash
# Examine the patch-android-manifest.sh file to validate review comment claims

echo "=== File info ==="
wc -l scripts/patch-android-manifest.sh 2>/dev/null || echo "File not found"

echo -e "\n=== Lines 27-62 (USB permissions and intent filter sections) ==="
sed -n '27,62p' scripts/patch-android-manifest.sh

echo -e "\n=== Lines 155-200 (JitPack and line 197 grep command) ==="
sed -n '155,200p' scripts/patch-android-manifest.sh

echo -e "\n=== Search for xmllint or XML validation ==="
grep -n "xmllint\|xml.*valid" scripts/patch-android-manifest.sh || echo "No XML validation found"

echo -e "\n=== Check for sed usage (to verify sed portability issues claim) ==="
grep -n "sed" scripts/patch-android-manifest.sh || echo "No sed commands found"

Length of output: 4213


🏁 Script executed:

#!/bin/bash
# Examine the patch-android-manifest.sh file to validate review comment claims

echo "=== File existence and total lines ==="
if [ -f scripts/patch-android-manifest.sh ]; then
  wc -l scripts/patch-android-manifest.sh
else
  echo "File not found at scripts/patch-android-manifest.sh"
  find . -name "patch-android-manifest.sh" 2>/dev/null
fi

echo -e "\n=== Lines 27-62 (USB permissions and intent filter sections) ==="
sed -n '27,62p' scripts/patch-android-manifest.sh 2>/dev/null

echo -e "\n=== Lines 155-200 (JitPack section with line 197 grep) ==="
sed -n '155,200p' scripts/patch-android-manifest.sh 2>/dev/null

echo -e "\n=== Search for XML validation (xmllint, xml validation) ==="
grep -n "xmllint\|xml.*validat" scripts/patch-android-manifest.sh 2>/dev/null || echo "No xmllint validation found"

echo -e "\n=== Check for sed usage in entire file ==="
grep -n "^[^#]*sed" scripts/patch-android-manifest.sh 2>/dev/null || echo "No sed commands found"

echo -e "\n=== Complete file structure (first 30 lines) ==="
head -30 scripts/patch-android-manifest.sh 2>/dev/null

Length of output: 5384


I need to verify the exact line number of the grep error mentioned in the review.


🏁 Script executed:

#!/bin/bash
# Find exact line number of grep commands, especially the one with -n flag issue

echo "=== All grep commands in the file with line numbers ==="
grep -n "grep" scripts/patch-android-manifest.sh

echo -e "\n=== Line 191 specifically ==="
sed -n '191p' scripts/patch-android-manifest.sh

echo -e "\n=== Lines 189-195 (context around line 191) ==="
sed -n '189,195p' scripts/patch-android-manifest.sh

echo -e "\n=== Search for double -n flags in grep ==="
grep -n -- '-n.*-n' scripts/patch-android-manifest.sh || echo "No double -n found via direct search"

echo -e "\n=== Analyze the grep command syntax ==="
sed -n '191p' scripts/patch-android-manifest.sh | cat -A

Length of output: 1253


🏁 Script executed:

#!/bin/bash
# Find exact line number of grep commands and verify the syntax error

echo "=== All grep commands with line numbers ==="
grep -n "grep" scripts/patch-android-manifest.sh

echo -e "\n=== Lines 185-200 to see full grep context ==="
sed -n '185,200p' scripts/patch-android-manifest.sh

echo -e "\n=== Search for patterns with multiple flags ==="
grep -nE '\-n.*\-n|repositories' scripts/patch-android-manifest.sh | tail -5

Length of output: 1575


Add XML validation after manifest modifications and fix grep syntax error.

The script modifies the Android manifest with awk but never validates the XML remains well-formed. Corrupted XML will only surface during the Gradle build phase.

Additionally, line 197 has a grep syntax error: the -n flag appears twice, and the pipe characters in the pattern won't work as regex alternation without -E flag.

Line 38 area — Add XML validation after USB permissions insertion:

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB permissions to manifest"
+   if command -v xmllint &> /dev/null; then
+       xmllint --noout "$MANIFEST_PATH" || { echo "❌ Manifest XML validation failed"; exit 1; }
+   fi
 fi

Line 62 area — Add XML validation after intent-filter insertion:

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB intent filter to manifest"
+   if command -v xmllint &> /dev/null; then
+       xmllint --noout "$MANIFEST_PATH" || { echo "❌ Manifest XML validation failed"; exit 1; }
+   fi
 fi

Line 197 — Fix grep command (remove duplicate -n, add -E for extended regex):

-   grep -n "dependencyResolutionManagement\|repositories \{|jitpack.io" -n "$SETTINGS_GRADLE" || true
+   grep -nE "dependencyResolutionManagement|repositories \{|jitpack.io" "$SETTINGS_GRADLE" || true

- Switch dependency back to 3.8.0 (known available on JitPack)
- Inject JitPack into both dependencyResolutionManagement and pluginManagement
- Add log preview of repositories blocks to verify in CI
Use `grep -En` with extended regex alternation for clearer CI logging:
`dependencyResolutionManagement|pluginManagement|repositories { |jitpack.io`.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src-tauri/capabilities/default.json (1)

4-4: Update description to reflect serialplugin permissions.

The description states "Default capability for all windows, allows core and shell open permissions" but the capability now also includes 9 serialplugin permissions. Update the description to accurately reflect the current scope:

-  "description": "Default capability for all windows, allows core and shell open permissions.",
+  "description": "Default capability for all windows, allows core, shell, and serial plugin permissions.",
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b46d4b2 and 7e03458.

📒 Files selected for processing (2)
  • package.json (0 hunks)
  • src-tauri/capabilities/default.json (1 hunks)
💤 Files with no reviewable changes (1)
  • package.json
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: haslinghuis
PR: betaflight/betaflight-configurator#0
File: :0-0
Timestamp: 2025-05-14T21:51:09.253Z
Learning: On Android Chrome browsers, Web Bluetooth API is supported for BLE devices and Web USB API is supported, but Web Serial API is not supported (except limited Bluetooth serial support added in 2025). The Betaflight Configurator should detect and use available APIs on Android rather than requiring all three.
Learnt from: haslinghuis
PR: betaflight/betaflight-configurator#0
File: :0-0
Timestamp: 2025-05-14T21:39:16.388Z
Learning: On Android Chrome browsers, Web Bluetooth API is supported from version 133+ (requires Android 6.0+) and Web USB API is supported from version 136+, but Web Serial API is not supported. The Betaflight Configurator should detect and use available APIs on Android rather than requiring all three.
📚 Learning: 2025-10-25T21:16:32.474Z
Learnt from: haslinghuis
PR: betaflight/betaflight-configurator#4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.

Applied to files:

  • src-tauri/capabilities/default.json
📚 Learning: 2025-06-19T22:13:09.136Z
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4521
File: src/js/protocols/WebSerial.js:148-151
Timestamp: 2025-06-19T22:13:09.136Z
Learning: In WebSerial.js, there's a timing issue where the cached `this.ports` array doesn't immediately reflect newly permitted devices after `requestPermissionDevice()` completes. The `getDevices()` method needs to refresh the device list from the browser API to return accurate data immediately following a permission request and user acceptance.

Applied to files:

  • src-tauri/capabilities/default.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Android preview (APK)
  • GitHub Check: Tauri Linux preview (deb/appimage)
🔇 Additional comments (2)
src-tauri/capabilities/default.json (2)

5-5: Verify iOS platform inclusion for serial plugin support.

The platforms list now includes both "android" and "iOS". However, iOS may not support the Tauri serial plugin in the same way as Android, Linux, or Windows. Verify that:

  • The serialplugin is available and functional on iOS
  • iOS serial capabilities are intended for this application
  • This won't cause runtime errors on iOS devices

If iOS doesn't support these serial permissions, consider removing it from the platforms list or creating a separate capability for iOS.


10-18: Verify serialplugin permission set is complete for Android USB support.

The explicit granular serialplugin permissions replace the previous "serialplugin:default" entry, which correctly addresses the earlier redundancy issue. However, verify that this set of 9 permissions is sufficient for the Android USB serial use case:

  • Are all required operations (open, read, write, close, etc.) covered?
  • Are any additional permissions needed for USB-specific operations?
  • Does the serialplugin v2.16.0 support all listed permissions?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
scripts/tauri-patch-android.sh (3)

9-10: Remove unused variables or add documentation explaining their purpose.

APP_BUILD_GRADLE and MAINACTIVITY_PATH are defined but never used in the script. Remove them or add a comment explaining intended future use and why they're currently unused. Lines 107–109 already document why custom MainActivity is skipped; consider adding similar rationale for APP_BUILD_GRADLE.


27-38: Add XML validation after manifest modifications.

The script modifies AndroidManifest.xml but never validates it remains well-formed. If the awk insertion is incorrect or incomplete, the XML could be corrupted, surfacing only during the Gradle build phase.

Add validation after the manifest write (line 36):

     ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
     echo "Added USB permissions to manifest"
+    
+    if command -v xmllint &> /dev/null; then
+        xmllint --noout "$MANIFEST_PATH" || { echo "❌ Manifest XML validation failed"; exit 1; }
+    fi
 fi

Apply the same validation after the intent-filter insertion (line 60).


64-102: Add validation for created device_filter.xml.

The device_filter.xml is generated via heredoc but never validated. Add a post-write validation check to catch any file creation or XML well-formedness issues before the build consumes it.

Add validation after the heredoc (after line 102):

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     ...
 </resources>
 EOF
+
+# Validate device filter XML is well-formed
+if command -v xmllint &> /dev/null; then
+    if ! xmllint --noout "$DEVICE_FILTER_PATH" 2>/dev/null; then
+        echo "❌ Device filter XML validation failed"
+        exit 1
+    fi
+fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e03458 and 7040058.

📒 Files selected for processing (2)
  • scripts/build-android-local.sh (1 hunks)
  • scripts/tauri-patch-android.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/build-android-local.sh
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 0
File: :0-0
Timestamp: 2025-05-14T21:51:09.253Z
Learning: On Android Chrome browsers, Web Bluetooth API is supported for BLE devices and Web USB API is supported, but Web Serial API is not supported (except limited Bluetooth serial support added in 2025). The Betaflight Configurator should detect and use available APIs on Android rather than requiring all three.
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 0
File: :0-0
Timestamp: 2025-05-14T21:39:16.388Z
Learning: On Android Chrome browsers, Web Bluetooth API is supported from version 133+ (requires Android 6.0+) and Web USB API is supported from version 136+, but Web Serial API is not supported. The Betaflight Configurator should detect and use available APIs on Android rather than requiring all three.
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4576
File: src/js/port_usage.js:17-23
Timestamp: 2025-08-22T16:43:20.901Z
Learning: In betaflight-configurator, the serial facade architecture requires accessing metrics like bitrate, bytesReceived, and bytesSent from serial._protocol rather than the top-level serial object. This change maintains compatibility with existing port utilization calculations that have been stable for over 11 years.
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
🪛 Shellcheck (0.11.0)
scripts/tauri-patch-android.sh

[warning] 9-9: APP_BUILD_GRADLE appears unused. Verify use (or export if used externally).

(SC2034)


[warning] 10-10: MAINACTIVITY_PATH appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
scripts/tauri-patch-android.sh (5)

115-136: Add validation and idempotency logic for settings.gradle.kts.

The script creates settings.gradle.kts only if missing, but provides no validation of the Gradle syntax and no logic to patch an existing file if it lacks required repositories. If the file already exists with incomplete repository configuration, the build will fail later.

 SETTINGS_GRADLE="src-tauri/gen/android/settings.gradle.kts"
 if [ ! -f "$SETTINGS_GRADLE" ]; then
     echo "settings.gradle.kts not found, creating and injecting required repository blocks..."
     cat > "$SETTINGS_GRADLE" << 'EOF'
 dependencyResolutionManagement {
     repositories {
         google()
         mavenCentral()
         maven { url = uri("https://jitpack.io") }
     }
 }

 pluginManagement {
     repositories {
         gradlePluginPortal()
         google()
         mavenCentral()
         maven { url = uri("https://jitpack.io") }
     }
 }
 EOF
+    echo "✓ settings.gradle.kts created"
+else
+    # Idempotently check existing file has required repositories
+    if ! grep -q "jitpack.io" "$SETTINGS_GRADLE"; then
+        echo "⚠️  Warning: settings.gradle.kts exists but may lack JitPack repository"
+        echo "    Please ensure it includes: maven { url = uri(\"https://jitpack.io\") }"
+    fi
 fi

7-10: Remove unused variable declarations.

Lines 9-10 define APP_BUILD_GRADLE and MAINACTIVITY_PATH but neither is used in the script. Line 109 explicitly skips MainActivity implementation. Remove these unused declarations to reduce clutter and avoid confusion during future maintenance.

 MANIFEST_PATH="src-tauri/gen/android/app/src/main/AndroidManifest.xml"
 DEVICE_FILTER_PATH="src-tauri/gen/android/app/src/main/res/xml/device_filter.xml"
-APP_BUILD_GRADLE="src-tauri/gen/android/app/build.gradle.kts"
-MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"

27-38: Add XML validation after USB permissions insertion.

The manifest is modified via awk but never validated to confirm it remains well-formed. If the awk insertion fails silently or produces malformed XML, the error will only surface during the Gradle build phase, making debugging difficult.

     ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
     echo "Added USB permissions to manifest"
+    
+    # Validate manifest XML is well-formed
+    if command -v xmllint &> /dev/null; then
+        if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+            echo "❌ Manifest XML validation failed after USB permissions insertion"
+            mv "$MANIFEST_PATH.bak" "$MANIFEST_PATH"
+            exit 1
+        fi
+    else
+        echo "⚠️  Warning: xmllint not found, skipping XML validation"
+    fi
 fi

64-102: Add validation for generated device_filter.xml.

While the device_filter.xml is generated fresh (not modified in-place), it should still be validated to catch any issues in the heredoc structure before the build consumes it.

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <!-- USB device filters for Betaflight-compatible devices -->
     
     <!-- FT232R USB UART -->
     <usb-device vendor-id="1027" product-id="24577" />
     
     <!-- STM32 devices -->
     <usb-device vendor-id="1155" product-id="12886" />  <!-- STM32 in HID mode -->
     <usb-device vendor-id="1155" product-id="14158" />  <!-- STLink Virtual COM Port (NUCLEO boards) -->
     <usb-device vendor-id="1155" product-id="22336" />  <!-- STM Electronics Virtual COM Port -->
     <usb-device vendor-id="1155" product-id="57105" />  <!-- STM Device in DFU Mode -->
     
     <!-- CP210x devices -->
     <usb-device vendor-id="4292" product-id="60000" />
     <usb-device vendor-id="4292" product-id="60001" />
     <usb-device vendor-id="4292" product-id="60002" />
     
     <!-- GD32 devices -->
     <usb-device vendor-id="10473" product-id="394" />   <!-- GD32 VCP -->
     <usb-device vendor-id="10473" product-id="393" />   <!-- GD32 DFU Bootloader -->
     
     <!-- AT32 devices -->
     <usb-device vendor-id="11836" product-id="22336" /> <!-- AT32 VCP -->
     <usb-device vendor-id="11836" product-id="57105" /> <!-- AT32F435 DFU Bootloader -->
     
     <!-- APM32 devices -->
     <usb-device vendor-id="12619" product-id="22336" /> <!-- APM32 VCP -->
     <usb-device vendor-id="12619" product-id="262" />   <!-- APM32 DFU Bootloader -->
     
     <!-- Raspberry Pi Pico devices -->
     <usb-device vendor-id="11914" product-id="9" />     <!-- Raspberry Pi Pico VCP -->
     <usb-device vendor-id="11914" product-id="15" />    <!-- Raspberry Pi Pico in Bootloader mode -->
 </resources>
 EOF
+
+# Validate device filter XML is well-formed
+if command -v xmllint &> /dev/null; then
+    if ! xmllint --noout "$DEVICE_FILTER_PATH" 2>/dev/null; then
+        echo "❌ Device filter XML validation failed"
+        exit 1
+    fi
+fi

44-62: Add XML validation after intent filter insertion.

Similar to the USB permissions section, the intent filter modification via awk requires validation to catch any corruption before the build proceeds.

     ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
     echo "Added USB intent filter to manifest"
+    
+    # Validate manifest XML is well-formed
+    if command -v xmllint &> /dev/null; then
+        if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+            echo "❌ Manifest XML validation failed after intent filter insertion"
+            mv "$MANIFEST_PATH.bak" "$MANIFEST_PATH"
+            exit 1
+        fi
+    else
+        echo "⚠️  Warning: xmllint not found, skipping XML validation"
+    fi
 fi
🧹 Nitpick comments (1)
scripts/tauri-patch-android.sh (1)

20-21: Backup provides recovery point but consider safety of restore.

The backup at line 21 is good practice, but there's no logic to restore it on error. Consider adding a trap to restore the backup if the script exits with an error code.

 set -e
 
 MANIFEST_PATH="src-tauri/gen/android/app/src/main/AndroidManifest.xml"
 DEVICE_FILTER_PATH="src-tauri/gen/android/app/src/main/res/xml/device_filter.xml"
 
 if [ ! -f "$MANIFEST_PATH" ]; then
     echo "Error: Android manifest not found at $MANIFEST_PATH"
     echo "Please run 'cargo tauri android init' first"
     exit 1
 fi
 
 echo "Patching Android manifest for USB serial support..."
 
 # Backup original manifest
 cp "$MANIFEST_PATH" "$MANIFEST_PATH.bak"
+
+# Trap to restore backup on error
+trap 'if [ $? -ne 0 ] && [ -f "$MANIFEST_PATH.bak" ]; then echo "Restoring backup..."; mv "$MANIFEST_PATH.bak" "$MANIFEST_PATH"; fi' EXIT
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7040058 and b7f391a.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml (2 hunks)
  • scripts/build-android-local.sh (1 hunks)
  • scripts/tauri-patch-android.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 0
File: :0-0
Timestamp: 2025-05-14T21:51:09.253Z
Learning: On Android Chrome browsers, Web Bluetooth API is supported for BLE devices and Web USB API is supported, but Web Serial API is not supported (except limited Bluetooth serial support added in 2025). The Betaflight Configurator should detect and use available APIs on Android rather than requiring all three.
🪛 Shellcheck (0.11.0)
scripts/tauri-patch-android.sh

[warning] 9-9: APP_BUILD_GRADLE appears unused. Verify use (or export if used externally).

(SC2034)


[warning] 10-10: MAINACTIVITY_PATH appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)
🔇 Additional comments (8)
.github/workflows/ci.yml (2)

129-133: Java version upgrade to 21 is appropriate.

The update from Java 17 to 21 aligns with recent JDK LTS releases and supports the latest Android build toolchain requirements.


154-155: Patch script integration is well-positioned in the build flow.

The bash scripts/tauri-patch-android.sh step runs after yarn tauri android init --ci and before the APK build, ensuring the manifest is correctly prepared for USB support. The timing is correct for the build workflow.

scripts/build-android-local.sh (6)

47-69: Robust Tauri CLI fallback chain with clear error messaging.

The run_tauri() helper properly cascades through multiple entry points (cargo, npx, yarn) and uses portable printf for multi-line error output. This approach maximizes compatibility across different development environments.


71-77: Ensure node modules check is appropriate for web asset builds.

The ensure_node_modules() function checks for both the directory and the vite executable. This is good for guaranteeing the build environment is ready, though it will silently retry if the first yarn install fails (line 75). This is acceptable for a local build script.


106-141: Device selection logic handles single and multiple devices appropriately.

The code gracefully handles three scenarios: no devices (clear error), single device (auto-select), multiple devices (interactive menu). The use of select is idiomatic bash for this UX pattern.


186-212: Keystore handling balances convenience with security.

The script defaults to the Android debug keystore (auto-generating if missing), and allows custom keystores with full parameter validation. The error message on line 209 clearly states all required parameters when using a custom keystore. This is a good balance for local development.


214-227: Robust APK signer discovery logic.

The code first checks PATH for apksigner, then falls back to ANDROID_HOME/build-tools, with proper error handling if neither is available. This covers the most common setup scenarios.


153-166: Dev build mode appropriately rebuilds web assets when missing.

The check for dist/ directory ensures web assets are available as a fallback, improving developer experience for incremental builds. The select_android_device is called at the right point (after assets are ready, before the build).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
scripts/build-android-local.sh (2)

177-181: Consider more specific APK pattern matching.

The find command with head -1 may select an unexpected APK if multiple unsigned APKs exist in the output directory. While this scenario is unlikely in a clean build, consider using a more specific pattern (e.g., matching the app name or build variant).

Example improvement:

-UNSIGNED_APK=$(find "$GEN_ANDROID_DIR/app/build/outputs/apk" -type f -name "*-unsigned.apk" | head -1 || true)
+UNSIGNED_APK=$(find "$GEN_ANDROID_DIR/app/build/outputs/apk/universal/release" -type f -name "*-universal-release-unsigned.apk" | head -1 || true)

241-242: Installation failure may be silently ignored.

The || true on line 242 prevents the script from failing if adb install encounters an error, which could mask legitimate installation problems (e.g., incompatible architecture, insufficient permissions, or conflicting signatures).

Consider either:

  • Removing || true to fail on installation errors, or
  • Capturing and logging the exit code to inform the user

Example with explicit error handling:

-adb install -r "$SIGNED_APK" || true
+if ! adb install -r "$SIGNED_APK"; then
+  echo "⚠ Warning: APK installation failed, but APK was signed successfully at: $SIGNED_APK" >&2
+  exit 1
+fi

Or if you want to allow failures but inform the user:

-adb install -r "$SIGNED_APK" || true
+if ! adb install -r "$SIGNED_APK"; then
+  echo "⚠ Warning: APK installation failed. You can manually install: $SIGNED_APK" >&2
+fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7f391a and 0a0bf83.

⛔ Files ignored due to path filters (1)
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • package.json (1 hunks)
  • scripts/build-android-local.sh (1 hunks)
  • scripts/tauri-wifi.sh (1 hunks)
  • src-tauri/Cargo.toml (1 hunks)
  • src-tauri/capabilities/default.json (1 hunks)
  • src-tauri/src/lib.rs (1 hunks)
  • src-tauri/src/main.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src-tauri/src/lib.rs
  • package.json
  • src-tauri/Cargo.toml
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
📚 Learning: 2025-10-25T21:16:32.474Z
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.

Applied to files:

  • src-tauri/capabilities/default.json
📚 Learning: 2025-06-19T22:13:09.136Z
Learnt from: blckmn
Repo: betaflight/betaflight-configurator PR: 4521
File: src/js/protocols/WebSerial.js:148-151
Timestamp: 2025-06-19T22:13:09.136Z
Learning: In WebSerial.js, there's a timing issue where the cached `this.ports` array doesn't immediately reflect newly permitted devices after `requestPermissionDevice()` completes. The `getDevices()` method needs to refresh the device list from the browser API to return accurate data immediately following a permission request and user acceptance.

Applied to files:

  • src-tauri/capabilities/default.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)
🔇 Additional comments (8)
scripts/tauri-wifi.sh (3)

1-10: LGTM!

The setup and helper function are well-structured. set -e provides strict error handling, and get_real_device() correctly filters out emulators and offline devices.


39-46: LGTM!

The error handling is clear, and the user guidance is helpful and actionable.


48-51: Verify that cargo tauri android dev --device parameter exists and is correctly formatted.

The script passes --device "$WIFI_DEVICE" to cargo tauri android dev, but it's unclear whether this parameter is supported by the Tauri CLI or if the correct syntax is being used. If the parameter doesn't exist or is incorrectly formatted, the command will fail and confuse the user.

Please verify the correct syntax for device selection in cargo tauri android dev by checking the Tauri documentation or running cargo tauri android dev --help to confirm that --device is a valid parameter and accepts device IDs/serials.

src-tauri/src/main.rs (1)

7-8: LGTM! Clean plugin initialization simplification.

The consolidation to a single tauri_plugin_serialplugin::init() call removes platform-specific branching and aligns with the broader PR objective of unified serial plugin handling across all platforms.

scripts/build-android-local.sh (2)

47-69: Good multi-toolchain fallback strategy.

The run_tauri() helper appropriately tries multiple CLI options (cargo-tauri, npx, yarn) with proper error messaging. The use of printf for newline rendering correctly addresses the previous review comment.


106-141: Robust device selection with good UX.

The select_android_device() function handles single/multiple device scenarios well and provides clear guidance when no devices are found.

src-tauri/capabilities/default.json (2)

9-21: Granular permissions correctly replace the default capability.

The explicit serialplugin permissions properly address the previous review feedback about redundancy. This approach grants fine-grained control over serial operations, which is appropriate for Android USB support.

Note: These permissions grant comprehensive serial access (read, write, port management, baud rate control). Ensure this aligns with your security model.


2-5: Schema naming is externally generated; verify if this reflects intentional unified-schema design or requires platform-specific schema updates.

The platforms array intentionally includes android and iOS (confirmed by git history adding Android USB serial support), yet the schema reference is desktop-schema.json. The schema file is generated by Tauri's build system and not present in source.

This mismatch could indicate: (1) a unified schema intentionally supporting all platforms despite the name, or (2) the schema naming hasn't been updated to reflect expanded mobile support. Since the schema generation is handled by the external Tauri framework, confirm whether this naming is expected behavior or if a schema version/configuration update is needed to align with the current platform support.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
scripts/tauri-patch-android.sh (3)

9-10: Remove unused variable declarations or document their purpose.

APP_BUILD_GRADLE (line 9) and MAINACTIVITY_PATH (line 10) are declared but never referenced. Either remove them or add a comment explaining future intent.

-APP_BUILD_GRADLE="src-tauri/gen/android/app/build.gradle.kts"
-MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"

If these are intentionally reserved for future use, add a comment above them:

+# Future customizations (currently unused)
+# APP_BUILD_GRADLE="src-tauri/gen/android/app/build.gradle.kts"
+# MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"

36-36: Add XML validation after manifest modifications.

The script modifies the Android manifest via awk but never validates that the resulting XML is well-formed. If an insertion fails or produces malformed XML, the error only surfaces during the Gradle build phase. Add validation immediately after both awk operations:

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB permissions to manifest"
+   if command -v xmllint &> /dev/null; then
+       if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+           echo "❌ Manifest XML validation failed after USB permissions injection"
+           exit 1
+       fi
+   fi
 fi

Apply the same validation after line 60 (following the intent filter insertion):

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB intent filter to manifest"
+   if command -v xmllint &> /dev/null; then
+       if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+           echo "❌ Manifest XML validation failed after intent filter injection"
+           exit 1
+       fi
+   fi
 fi

Also applies to: 60-60


67-102: Add validation for device_filter.xml after creation.

The device_filter.xml is generated fresh but never validated. If the here-doc is malformed or truncated, the XML corruption will only be caught at build time. Add a validation step after the file is written:

 EOF
+
+# Validate device filter XML is well-formed
+if command -v xmllint &> /dev/null; then
+    if ! xmllint --noout "$DEVICE_FILTER_PATH" 2>/dev/null; then
+        echo "❌ Device filter XML validation failed"
+        rm -f "$DEVICE_FILTER_PATH"
+        exit 1
+    fi
+fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62f9c41 and 05bc006.

📒 Files selected for processing (1)
  • scripts/tauri-patch-android.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
🪛 Shellcheck (0.11.0)
scripts/tauri-patch-android.sh

[warning] 9-9: APP_BUILD_GRADLE appears unused. Verify use (or export if used externally).

(SC2034)


[warning] 10-10: MAINACTIVITY_PATH appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Android preview (APK)
  • GitHub Check: Tauri Linux preview (deb/appimage)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
scripts/tauri-patch-android.sh (3)

10-10: Remove or document the unused MAINACTIVITY_PATH variable.

Line 10 defines MAINACTIVITY_PATH but it's never used. Lines 107–109 explicitly skip custom MainActivity implementation. Either remove this variable or add an inline comment explaining its intended future use and why it's currently unused.

Apply this diff to document the intent:

-MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"
+# MAINACTIVITY_PATH intentionally unused—custom MainActivity not needed for USB serial permissions.
+# (See lines 107–109.) Kept as reference for potential future enhancements.

Alternatively, remove the variable entirely and the referencing comment.


29-62: Add XML validation after manifest modifications.

The script modifies AndroidManifest.xml with awk but never validates the resulting XML is well-formed. If the awk transformation produces malformed XML, the error will only surface later during the Gradle build phase, making debugging harder.

Add validation after both awk modifications:

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB permissions to manifest"
+   if command -v xmllint &> /dev/null; then
+       if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+           echo "❌ Manifest XML validation failed after USB permissions insertion"
+           mv "$MANIFEST_PATH.bak" "$MANIFEST_PATH"
+           exit 1
+       fi
+   fi
 fi

Apply the same validation after line 60 (intent-filter insertion):

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB intent filter to manifest"
+   if command -v xmllint &> /dev/null; then
+       if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+           echo "❌ Manifest XML validation failed after intent-filter insertion"
+           mv "$MANIFEST_PATH.bak" "$MANIFEST_PATH"
+           exit 1
+       fi
+   fi
 fi

This approach restores the backup if validation fails, ensuring the script fails fast rather than producing a broken build.


67-102: Add optional validation for device_filter.xml creation.

The device_filter.xml is created fresh via a here-doc, which is reliable. However, adding a quick XML validation check would catch any issues early:

 cat > "$DEVICE_FILTER_PATH" << 'EOF'
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <!-- ... USB device filters ... -->
 </resources>
 EOF
+
+if command -v xmllint &> /dev/null; then
+    if ! xmllint --noout "$DEVICE_FILTER_PATH" 2>/dev/null; then
+        echo "❌ Device filter XML validation failed"
+        exit 1
+    fi
+fi

This ensures the file is well-formed before the build attempts to consume it.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05bc006 and 5ec9332.

📒 Files selected for processing (1)
  • scripts/tauri-patch-android.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
🪛 Shellcheck (0.11.0)
scripts/tauri-patch-android.sh

[warning] 10-10: MAINACTIVITY_PATH appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
scripts/tauri-patch-android.sh (3)

189-210: Fix sed portability for pluginManagement patching—fails on macOS.

The sed commands on lines 191–208 use GNU sed syntax that fails on macOS (BSD sed). Same issue as lines 157–171.

Apply the same portable awk-based solution here, or simplify by validating that the file-creation path is sufficient.


157-171: Fix sed portability for dependencyResolutionManagement patching—fails on macOS.

The sed commands on lines 158–170 use GNU sed syntax (/a\ with backslash continuations) that fails on macOS (BSD sed). While the file-creation path (lines 119–138) is correct, the patching logic will silently fail or corrupt settings.gradle.kts for macOS developers using scripts/build-android-local.sh.

Replace with a portable awk-based approach:

         # Check and add missing repositories in dependencyResolutionManagement
-        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "google()"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        google()
-}' "$SETTINGS_GRADLE"
-        fi
-        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "mavenCentral()"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        mavenCentral()
-}' "$SETTINGS_GRADLE"
-        fi
-        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "jitpack.io"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        maven { url = uri("https://jitpack.io") }
-}' "$SETTINGS_GRADLE"
-        fi
+        # Regenerate the entire file with correct repositories instead of patching
+        # This ensures portability and correctness across macOS and Linux
+        awk '
+            /dependencyResolutionManagement/ { found_drm=1 }
+            /pluginManagement/ && found_drm && !done_repos {
+                # Insert missing repositories before pluginManagement
+                print "dependencyResolutionManagement {"
+                print "    repositories {"
+                print "        google()"
+                print "        mavenCentral()"
+                print "        maven { url = uri(\"https://jitpack.io\") }"
+                print "    }"
+                print "}"
+                print ""
+                done_repos=1
+            }
+            { print }
+        ' "$SETTINGS_GRADLE" > "$SETTINGS_GRADLE.tmp" && mv "$SETTINGS_GRADLE.tmp" "$SETTINGS_GRADLE"

Alternatively, validate that the generated file in lines 119–138 is always correct and skip the entire patching section (lines 156–172) with a warning if the file already exists.


221-225: Fix sed portability for dependency injection—fails on macOS.

The sed command on lines 223–225 uses GNU sed syntax (/a\ continuation) that fails on macOS (BSD sed). Use the portable awk approach or simple text insertion:

-        if grep -q "^dependencies {" "$APP_BUILD_GRADLE"; then
-            # Insert after the opening dependencies { line
-            sed -i '/^dependencies {/a\
-    implementation("com.github.mik3y:usb-serial-for-android:3.8.0")
-' "$APP_BUILD_GRADLE"
+        if grep -q "^dependencies {" "$APP_BUILD_GRADLE"; then
+            # Insert after the opening dependencies { line using portable awk
+            awk '
+                /^dependencies \{/ && !added {
+                    print $0
+                    print "    implementation(\"com.github.mik3y:usb-serial-for-android:3.8.0\")"
+                    added=1
+                    next
+                }
+                { print }
+            ' "$APP_BUILD_GRADLE" > "$APP_BUILD_GRADLE.tmp" && mv "$APP_BUILD_GRADLE.tmp" "$APP_BUILD_GRADLE"
🧹 Nitpick comments (4)
scripts/tauri-patch-android.sh (4)

10-10: Remove or document unused variable MAINACTIVITY_PATH.

This variable is defined but never referenced. Either remove it or add a comment explaining its intended purpose (as noted in lines 107–109 where custom MainActivity is skipped).

-MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"
+# MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"
+# Custom MainActivity implementation skipped; USB permissions handled by serial plugin (see line 108)

29-36: Good—portable awk-based manifest patching with idempotency.

The awk-based approach is cross-platform compatible and correctly handles atomic file replacement. However, consider adding XML validation after modification to catch corruption early.

Add XML validation after line 37:

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB permissions to manifest"
+   if command -v xmllint &> /dev/null; then
+       if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+           echo "❌ Manifest XML validation failed after patching"
+           exit 1
+       fi
+   fi
 fi

46-60: Good—portable awk-based intent filter insertion.

The awk implementation is cross-platform compatible with proper idempotency. Add XML validation here too (after line 61) to ensure manifest integrity.

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB intent filter to manifest"
+   if command -v xmllint &> /dev/null; then
+       if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+           echo "❌ Manifest XML validation failed after intent filter insertion"
+           exit 1
+       fi
+   fi
 fi

67-102: Add validation for device_filter.xml.

The here-document is well-formed, but add a post-write XML validation check to catch any file system issues or truncation.

     <usb-device vendor-id="11914" product-id="15" />    <!-- Raspberry Pi Pico in Bootloader mode -->
 </resources>
 EOF
+
+# Validate device_filter.xml is well-formed
+if command -v xmllint &> /dev/null; then
+    if ! xmllint --noout "$DEVICE_FILTER_PATH" 2>/dev/null; then
+        echo "❌ Device filter XML validation failed"
+        exit 1
+    fi
+fi
 
 echo "✓ Android manifest patched successfully!"
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ec9332 and 5f31190.

⛔ Files ignored due to path filters (1)
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • scripts/tauri-patch-android.sh (1 hunks)
🧰 Additional context used
🪛 Shellcheck (0.11.0)
scripts/tauri-patch-android.sh

[warning] 10-10: MAINACTIVITY_PATH appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
scripts/tauri-patch-android.sh (2)

217-225: Fix sed portability for app/build.gradle.kts dependency injection—will fail on macOS.

Lines 223–225 use the same GNU sed syntax that fails on macOS. Replace with awk for portability:

 if grep -q "^dependencies {" "$APP_BUILD_GRADLE"; then
     # Insert after the opening dependencies { line
-    sed -i '/^dependencies {/a\
-    implementation("com.github.mik3y:usb-serial-for-android:3.9.0")
-' "$APP_BUILD_GRADLE"
+    # Use awk for cross-platform compatibility
+    awk '
+        /^dependencies \{/ && !added {
+            print $0
+            print "    implementation(\"com.github.mik3y:usb-serial-for-android:3.9.0\")"
+            added=1
+            next
+        }
+        { print }
+    ' "$APP_BUILD_GRADLE" > "$APP_BUILD_GRADLE.tmp" && mv "$APP_BUILD_GRADLE.tmp" "$APP_BUILD_GRADLE"
 else

157-172: Fix sed portability for settings.gradle.kts—will fail on macOS.

Lines 158–172 use GNU sed syntax (sed -i with backslash-escaped newlines) that fails on macOS (which uses BSD sed). These commands will silently fail or corrupt the Gradle file for macOS developers using scripts/build-android-local.sh.

Replace the complex sed logic with the same awk-based approach used for manifest modifications (lines 29–36, 46–60), or use sed with a backup suffix that works across platforms:

-        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "google()"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        google()
-}' "$SETTINGS_GRADLE"
+        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "google()"; then
+            # Use awk for cross-platform compatibility (macOS + Linux)
+            awk '
+                /dependencyResolutionManagement/ { in_drm=1 }
+                in_drm && /repositories \{/ { print; print "        google()"; next }
+                { print }
+            ' "$SETTINGS_GRADLE" > "$SETTINGS_GRADLE.tmp" && mv "$SETTINGS_GRADLE.tmp" "$SETTINGS_GRADLE"
         fi

Apply the same fix to lines 162–165, 167–170 (remaining repositories in dependencyResolutionManagement), and repeat for pluginManagement block (lines 190–209).

🧹 Nitpick comments (1)
scripts/tauri-patch-android.sh (1)

10-10: Remove or document the unused MAINACTIVITY_PATH variable.

This variable is defined but never used in the script. While lines 107–109 explain why custom MainActivity implementation is skipped, the variable declaration itself adds unnecessary clutter.

Either remove line 10 entirely or replace it with a clarifying comment.

-MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"
+# Custom MainActivity not needed; USB permissions handled by the serial plugin and manifest intent filters
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f31190 and a93186b.

📒 Files selected for processing (1)
  • scripts/tauri-patch-android.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
🪛 Shellcheck (0.11.0)
scripts/tauri-patch-android.sh

[warning] 10-10: MAINACTIVITY_PATH appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)
🔇 Additional comments (2)
scripts/tauri-patch-android.sh (2)

27-38: Add XML validation after manifest modifications.

The manifest is modified via awk but never validated for well-formedness. If the awk insertion produces invalid XML, the error surfaces only during the Gradle build phase. Add validation immediately after line 36 to fail fast.

     ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
     echo "Added USB permissions to manifest"
+    
+    # Validate manifest XML is well-formed
+    if command -v xmllint &> /dev/null; then
+        if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+            echo "❌ Manifest XML validation failed after USB permissions insertion"
+            exit 1
+        fi
+    fi
 fi

Apply the same validation pattern after the intent-filter insertion at line 62.


64-102: Add XML validation for created device_filter.xml.

The device_filter.xml is written fresh from a heredoc and never validated. While lower risk than manifest modification, validation should be added to catch any templating errors.

 cat > "$DEVICE_FILTER_PATH" << 'EOF'
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     ...usb-device entries...
 </resources>
 EOF
+
+# Validate device filter XML is well-formed
+if command -v xmllint &> /dev/null; then
+    if ! xmllint --noout "$DEVICE_FILTER_PATH" 2>/dev/null; then
+        echo "❌ Device filter XML validation failed"
+        exit 1
+    fi
+fi

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
scripts/tauri-patch-android.sh (2)

223-225: Fix sed portability for app/build.gradle.kts dependency—fails on macOS.

Lines 223–225 use GNU sed syntax that fails on macOS (BSD sed). Replace with the awk-based approach for consistency:

-            sed -i '/^dependencies {/a\
-    implementation("com.github.mik3y:usb-serial-for-android:3.8.1")
-' "$APP_BUILD_GRADLE"
+            # Use awk for cross-platform compatibility
+            awk '
+                /^dependencies \{/ && !added {
+                    print $0
+                    print "    implementation(\"com.github.mik3y:usb-serial-for-android:3.8.1\")"
+                    added = 1
+                    next
+                }
+                { print }
+            ' "$APP_BUILD_GRADLE" > "$APP_BUILD_GRADLE.tmp" && mv "$APP_BUILD_GRADLE.tmp" "$APP_BUILD_GRADLE"

This ensures the dependency is added correctly on both macOS and Linux.


158-171: Fix sed portability for dependencyResolutionManagement repositories—fails on macOS.

The sed commands on lines 158–171 use GNU sed syntax (sed -i with /a\ multi-line insertions) that fails silently on macOS (BSD sed). The repositories won't be added, leaving the Gradle configuration incomplete.

Since the awk-based approach on lines 29–36 works across platforms, apply the same pattern here. Replace the sed blocks with a portable solution:

-        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "google()"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        google()
-}' "$SETTINGS_GRADLE"
-        fi
-        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "mavenCentral()"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        mavenCentral()
-}' "$SETTINGS_GRADLE"
-        fi
-        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "jitpack.io"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        maven { url = uri("https://jitpack.io") }
-}' "$SETTINGS_GRADLE"
-        fi
+        # Use awk for cross-platform compatibility (macOS + Linux)
+        if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "google()"; then
+            awk '
+                /dependencyResolutionManagement \{/,/^\}/ {
+                    if (/repositories \{/ && !added_google) {
+                        print $0
+                        print "        google()"
+                        added_google = 1
+                        next
+                    }
+                }
+                { print }
+            ' "$SETTINGS_GRADLE" > "$SETTINGS_GRADLE.tmp" && mv "$SETTINGS_GRADLE.tmp" "$SETTINGS_GRADLE"
+        fi
+        # Apply similar awk patterns for mavenCentral() and jitpack.io...

This ensures repositories are added correctly on both macOS and Linux.

🧹 Nitpick comments (3)
scripts/tauri-patch-android.sh (3)

10-10: Remove or document unused variable MAINACTIVITY_PATH.

This variable is defined but never used. The comment at lines 107–109 explains custom MainActivity is skipped, so either remove this line or add an inline comment referencing the skip logic for future readers.

-MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"
+# MAINACTIVITY_PATH unused: custom MainActivity is not needed for USB serial permissions (see lines 107–109)

36-36: Add XML validation after manifest modifications.

The manifest is modified via awk insertions, but never validated to ensure well-formedness. If the awk operations produce invalid XML, the build fails later during Gradle compilation with a confusing error message.

Add validation after each manifest modification:

    ' "$MANIFEST_PATH" > "$MANIFEST_PATH.tmp" && mv "$MANIFEST_PATH.tmp" "$MANIFEST_PATH"
    echo "Added USB permissions to manifest"
+   if command -v xmllint &> /dev/null; then
+       if ! xmllint --noout "$MANIFEST_PATH" 2>/dev/null; then
+           echo "❌ Manifest XML validation failed after USB permissions insertion"
+           mv "$MANIFEST_PATH.bak" "$MANIFEST_PATH"
+           exit 1
+       fi
+   fi
 fi

Apply the same validation block after line 60 (intent filter insertion).

Also applies to: 60-60


102-102: Validate device_filter.xml after creation.

The device_filter.xml is written but never validated. If the XML is malformed, the Gradle build fails with an unclear error.

Add validation immediately after the here-doc closes (after line 102):

 EOF
+
+if command -v xmllint &> /dev/null; then
+    if ! xmllint --noout "$DEVICE_FILTER_PATH" 2>/dev/null; then
+        echo "❌ Device filter XML validation failed"
+        exit 1
+    fi
+fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a93186b and 8e779cd.

📒 Files selected for processing (1)
  • scripts/tauri-patch-android.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
🪛 Shellcheck (0.11.0)
scripts/tauri-patch-android.sh

[warning] 10-10: MAINACTIVITY_PATH appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Android preview (APK)
  • GitHub Check: Tauri Linux preview (deb/appimage)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
scripts/tauri-patch-android.sh (2)

158-170: Replace sed with awk for cross-platform portability (dependencyResolutionManagement repositories).

Lines 158–170 use GNU sed syntax (/a\ with line continuation) that fails on macOS/BSD sed. The script already uses the correct awk-based approach for pluginManagement repositories (lines 191–244)—apply the same pattern here for consistency and macOS compatibility.

         # Check and add missing repositories in dependencyResolutionManagement
         if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "google()"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        google()
-}' "$SETTINGS_GRADLE"
+            # Using awk for portability across macOS and Linux
+            awk '
+                /dependencyResolutionManagement \{/,/\}/ {
+                    if ($0 ~ /repositories \{/ && !found) {
+                        print $0
+                        print "        google()"
+                        found=1
+                        next
+                    }
+                }
+                { print }
+            ' "$SETTINGS_GRADLE" > "$SETTINGS_GRADLE.tmp" && mv "$SETTINGS_GRADLE.tmp" "$SETTINGS_GRADLE"
         fi
         if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "mavenCentral()"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        mavenCentral()
-}' "$SETTINGS_GRADLE"
+            # Using awk for portability across macOS and Linux
+            awk '
+                /dependencyResolutionManagement \{/,/\}/ {
+                    if ($0 ~ /repositories \{/ && !found) {
+                        print $0
+                        print "        mavenCentral()"
+                        found=1
+                        next
+                    }
+                }
+                { print }
+            ' "$SETTINGS_GRADLE" > "$SETTINGS_GRADLE.tmp" && mv "$SETTINGS_GRADLE.tmp" "$SETTINGS_GRADLE"
         fi
         if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "jitpack.io"; then
-            sed -i '/dependencyResolutionManagement {/,/}/ { /repositories {/a\
-        maven { url = uri("https://jitpack.io") }
-}' "$SETTINGS_GRADLE"
+            # Using awk for portability across macOS and Linux
+            awk '
+                /dependencyResolutionManagement \{/,/\}/ {
+                    if ($0 ~ /repositories \{/ && !found) {
+                        print $0
+                        print "        maven { url = uri(\"https://jitpack.io\") }"
+                        found=1
+                        next
+                    }
+                }
+                { print }
+            ' "$SETTINGS_GRADLE" > "$SETTINGS_GRADLE.tmp" && mv "$SETTINGS_GRADLE.tmp" "$SETTINGS_GRADLE"
         fi

259-261: Replace sed with awk for cross-platform portability (app/build.gradle.kts dependency injection).

Line 259–261 uses GNU sed syntax that fails on macOS/BSD sed. Replace with awk for portability, matching the pattern already used elsewhere in this script.

         if grep -q "^dependencies {" "$APP_BUILD_GRADLE"; then
             # Insert after the opening dependencies { line
-            sed -i '/^dependencies {/a\
-    implementation("com.github.mik3y:usb-serial-for-android:3.8.1")
-' "$APP_BUILD_GRADLE"
+            # Using awk for portability across macOS and Linux
+            awk '
+                /^dependencies \{/ && !found {
+                    print $0
+                    print "    implementation(\"com.github.mik3y:usb-serial-for-android:3.8.1\")"
+                    found=1
+                    next
+                }
+                { print }
+            ' "$APP_BUILD_GRADLE" > "$APP_BUILD_GRADLE.tmp" && mv "$APP_BUILD_GRADLE.tmp" "$APP_BUILD_GRADLE"
         else
🧹 Nitpick comments (2)
scripts/tauri-patch-android.sh (2)

10-10: Remove or document unused variable MAINACTIVITY_PATH.

This variable is defined but never used; lines 107–109 explicitly skip custom MainActivity implementation. Either remove the unused variable or add a comment explaining why it's defined and not used, referencing the skip logic for future maintainers.

-MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"

Alternatively, add a comment if future custom MainActivity support is planned:

-MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"
+# MAINACTIVITY_PATH="src-tauri/gen/android/app/src/main/java/com/betaflight/configurator/MainActivity.kt"
+# Currently unused; custom MainActivity not needed since USB permissions are handled by the serial plugin.
+# Defined for future reference if custom activity implementation becomes necessary.

67-102: Add XML validation for device_filter.xml after creation.

The device_filter.xml is generated fresh but never validated. While the static XML is unlikely to be malformed, adding a quick validation step follows defensive practices and catches issues before the build consumes the file.

 cat > "$DEVICE_FILTER_PATH" << 'EOF'
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <!-- USB device filters for Betaflight-compatible devices -->
     ...
 </resources>
 EOF
+
+# Validate device filter XML is well-formed
+if command -v xmllint &> /dev/null; then
+    if ! xmllint --noout "$DEVICE_FILTER_PATH" 2>/dev/null; then
+        echo "❌ Device filter XML validation failed"
+        exit 1
+    fi
+fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e779cd and 72173cf.

📒 Files selected for processing (1)
  • scripts/tauri-patch-android.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
🪛 Shellcheck (0.11.0)
scripts/tauri-patch-android.sh

[warning] 10-10: MAINACTIVITY_PATH appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
scripts/create-device-filter.sh (1)

12-47: Clean and straightforward script; consider optional XML validation.

The device filter generation is well-organized with clear comments for each device category. The XML structure looks correct.

For robustness (optional), you could add a post-generation XML validation step:

# After the cat > command closes (after line 47)
if command -v xmllint &> /dev/null; then
    xmllint --noout "$DEVICE_FILTER_PATH" || { echo "❌ Device filter XML validation failed"; exit 1; }
else
    echo "⚠️  Tip: Install xmllint for XML validation"
fi
scripts/patch-android-manifest.sh (1)

20-35: Solid portability fix using awk for manifest permissions.

Good use of awk to insert USB permissions in a portable way across macOS and Linux. The backup creation (line 18) and duplicate-prevention checks (lines 21, 38) are appropriate.

For enhanced robustness (optional), you could add XML validation after each modification:

# After line 34 (after USB permissions insertion)
if command -v xmllint &> /dev/null; then
    xmllint --noout "$MANIFEST_PATH" || { echo "❌ Manifest validation failed"; exit 1; }
fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72173cf and 4dfd15e.

📒 Files selected for processing (6)
  • scripts/README.md (1 hunks)
  • scripts/create-device-filter.sh (1 hunks)
  • scripts/patch-android-manifest.sh (1 hunks)
  • scripts/patch-app-gradle.sh (1 hunks)
  • scripts/patch-gradle-settings.sh (1 hunks)
  • scripts/tauri-patch-android.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)
🔇 Additional comments (1)
scripts/tauri-patch-android.sh (1)

1-39: Clean orchestration script; depends on fixing sed issues in called scripts.

The main script is well-structured and calls the patching scripts in logical order. The manifest existence check (line 12) and the explicit skip of custom MainActivity (lines 33–35) are appropriate.

However, this script will fail on macOS if the called scripts (patch-gradle-settings.sh and patch-app-gradle.sh) still contain sed portability issues. Once those scripts are fixed, this orchestration will work correctly.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
scripts/patch-gradle-settings.sh (1)

47-49: Remove stray statements causing syntax error.

Lines 47–49 contain floating Kotlin statements (google(), mavenCentral(), etc.) with no context inside the bash script. These are not part of any bash construct and cause the script to fail parsing. Remove them entirely.

     else
-        google()
-        mavenCentral()
-        maven { url = uri("https://jitpack.io") }
         # Portable awk-based insertion for missing repositories in dependencyResolutionManagement
         if ! grep -A 10 "dependencyResolutionManagement" "$SETTINGS_GRADLE" | grep -q "google()"; then
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4dfd15e and 376ebad.

📒 Files selected for processing (2)
  • scripts/patch-app-gradle.sh (1 hunks)
  • scripts/patch-gradle-settings.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4379
File: src/js/protocols/TauriSerial.js:203-259
Timestamp: 2025-10-25T21:16:32.474Z
Learning: In TauriSerial (src/js/protocols/TauriSerial.js), the requestPermissionDevice() method is not needed and not invoked. Tauri automatically discovers serial devices through the constructor's loadDevices() and startDeviceMonitoring() calls, bypassing the browser permission model that WebSerial requires. Devices are auto-detected via a 1-second polling interval without user permission prompts.
🪛 Shellcheck (0.11.0)
scripts/patch-app-gradle.sh

[error] 54-54: Couldn't parse this function. Fix to allow more checks.

(SC1073)


[error] 54-54: Trying to declare parameters? Don't. Use () and refer to params as $1, $2..

(SC1065)


[error] 55-55: Expected a { to open the function definition.

(SC1064)


[error] 55-55: Fix any mentioned problems and try again.

(SC1072)

scripts/patch-gradle-settings.sh

[error] 47-47: Couldn't parse this function. Fix to allow more checks.

(SC1073)


[error] 48-48: Expected a { to open the function definition.

(SC1064)


[error] 48-48: Fix any mentioned problems and try again.

(SC1072)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Linux preview (deb/appimage)
  • GitHub Check: Tauri Android preview (APK)

@haslinghuis
Copy link
Member Author

Rate limit exceeded

@haslinghuis has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 49 seconds before requesting another review.

@coderabbitai wake up after build completes :)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Tip

For best results, initiate chat on the files or code changes.

@haslinghuis, I appreciate the heads up! 😊

Unfortunately, I can't automatically monitor build statuses or wake myself up when builds complete. I only respond when you explicitly mention me or when new commits are pushed to the PR.

Here are your options:

  1. Ping me after the build completes - Just mention me again once your CI build finishes, and I'll review the changes
  2. Review now - If you'd like me to review the current state of the PR right now, just let me know

The rate limit window should have passed by now, so I'm ready to review whenever you'd like! Just give me the word. 👍

@haslinghuis
Copy link
Member Author

Backtracking on AI suggestions

@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 4, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants