Skip to content

Commit cadf39f

Browse files
committed
Add Android USB debugging tools and updated documentation
- 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
1 parent a801f59 commit cadf39f

File tree

3 files changed

+249
-11
lines changed

3 files changed

+249
-11
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: Test Android Manifest Patch
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
test-patch:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout
11+
uses: actions/checkout@v5
12+
13+
- name: Setup Node
14+
uses: actions/setup-node@v5
15+
with:
16+
node-version-file: '.nvmrc'
17+
cache: 'yarn'
18+
19+
- name: Install dependencies
20+
run: yarn install --frozen-lockfile
21+
22+
- name: Setup Java 21
23+
uses: actions/setup-java@v4
24+
with:
25+
distribution: 'temurin'
26+
java-version: '21'
27+
28+
- name: Setup Android SDK
29+
uses: android-actions/setup-android@v3
30+
31+
- name: Install Rust
32+
uses: dtolnay/rust-toolchain@stable
33+
34+
- name: Install Rust Android targets
35+
run: |
36+
rustup target add aarch64-linux-android
37+
rustup target add armv7-linux-androideabi
38+
rustup target add i686-linux-android
39+
rustup target add x86_64-linux-android
40+
41+
- name: Build web assets (Vite)
42+
run: yarn build
43+
44+
- name: Initialize Tauri Android project
45+
run: yarn tauri android init --ci
46+
47+
- name: Show generated manifest BEFORE patch
48+
run: |
49+
echo "=== MANIFEST BEFORE PATCH ==="
50+
cat src-tauri/gen/android/app/src/main/AndroidManifest.xml || echo "Manifest not found"
51+
echo ""
52+
echo "=== APP BUILD.GRADLE.KTS BEFORE PATCH ==="
53+
cat src-tauri/gen/android/app/build.gradle.kts || echo "build.gradle.kts not found"
54+
55+
- name: Patch Android manifest for USB support
56+
run: bash scripts/patch-android-manifest.sh
57+
58+
- name: Show generated files AFTER patch
59+
run: |
60+
echo "=== MANIFEST AFTER PATCH ==="
61+
cat src-tauri/gen/android/app/src/main/AndroidManifest.xml
62+
echo ""
63+
echo "=== DEVICE FILTER ==="
64+
cat src-tauri/gen/android/app/src/main/res/xml/device_filter.xml || echo "device_filter.xml not found"
65+
echo ""
66+
echo "=== APP BUILD.GRADLE.KTS AFTER PATCH ==="
67+
cat src-tauri/gen/android/app/build.gradle.kts
68+
echo ""
69+
echo "=== Checking for USB permissions ==="
70+
grep -i "usb" src-tauri/gen/android/app/src/main/AndroidManifest.xml || echo "No USB found in manifest"
71+
echo ""
72+
echo "=== Checking for usb-serial dependency ==="
73+
grep -i "usb-serial" src-tauri/gen/android/app/build.gradle.kts || echo "No usb-serial dependency found"
74+
75+
- name: Ensure JitPack repository
76+
shell: bash
77+
run: |
78+
set -euo pipefail
79+
FILE="src-tauri/gen/android/build.gradle.kts"
80+
if [ -f "$FILE" ]; then
81+
echo "=== ROOT BUILD.GRADLE.KTS BEFORE JITPACK ==="
82+
cat "$FILE"
83+
echo ""
84+
echo "Ensuring JitPack repository in $FILE..."
85+
if ! grep -q "jitpack.io" "$FILE"; then
86+
echo "Adding JitPack repository..."
87+
printf '\nallprojects {\n repositories {\n maven(url = "https://jitpack.io")\n }\n}\n' >> "$FILE"
88+
fi
89+
echo ""
90+
echo "=== ROOT BUILD.GRADLE.KTS AFTER JITPACK ==="
91+
cat "$FILE"
92+
fi
93+
94+
- name: Upload generated Android files
95+
uses: actions/upload-artifact@v4
96+
with:
97+
name: android-generated-files
98+
path: |
99+
src-tauri/gen/android/app/src/main/AndroidManifest.xml
100+
src-tauri/gen/android/app/src/main/res/xml/device_filter.xml
101+
src-tauri/gen/android/app/build.gradle.kts
102+
src-tauri/gen/android/build.gradle.kts
103+
retention-days: 7

ANDROID_USB.md

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
# Android USB Serial Support
22

3-
## Problem
3+
# Android USB Serial Support
4+
5+
## Current Status (v2.16.0)
6+
7+
The `tauri-plugin-serialplugin` version 2.16.0 includes Android support with Kotlin implementation for USB serial communication. However, USB devices may not be detected due to runtime permission handling.
8+
9+
## What's Working
410

5-
The Betaflight Configurator uses `tauri-plugin-serialplugin` to access serial ports. On Linux, this works without special configuration, but **Android requires explicit USB permissions** that must be declared in the `AndroidManifest.xml`.
11+
**Build**: APK compiles successfully
12+
**Manifest Permissions**: USB permissions are patched into AndroidManifest.xml
13+
**Plugin**: Version 2.16.0 has Android Kotlin code
14+
**Dependencies**: `usb-serial-for-android` library is added via Gradle
15+
**Device Filter**: USB device VID/PID filter is created
616

7-
Since the Android project in `src-tauri/gen/android/` is **regenerated at build time**, manual changes to the manifest are lost.
17+
## What May Not Be Working
818

9-
## Solution
19+
**Runtime Permission Request**: Android requires explicit permission request when USB device is attached
20+
**Port Detection**: USB ports may not appear without proper UsbManager usage
1021

11-
We've created a patch script that automatically adds the required USB permissions and device filters to the generated Android manifest.
22+
## The Problem
1223

13-
### Required Permissions
24+
Even with manifest permissions, Android apps need to:
25+
1. **Request permission at runtime** when a USB device is detected
26+
2. **Use Android's UsbManager** to enumerate connected USB devices
27+
3. **Handle USB_DEVICE_ATTACHED intent** to detect when devices are plugged in
1428

15-
The script adds:
16-
- `android.permission.USB_PERMISSION` - Required to access USB devices
17-
- `android.hardware.usb.host` - Declares USB host mode support
18-
- USB device intent filter - Prompts user when compatible USB device is connected
19-
- USB device filter - Lists all Betaflight-compatible USB devices (FTDI, STM32, CP210x, etc.)
29+
The plugin version 2.16.0 has Kotlin code for this, but it may need:
30+
- Proper initialization in MainActivity
31+
- USB permission dialog handling
32+
- Event bridging between Android and Tauri
2033

2134
## Usage
2235

ANDROID_USB_DEBUGGING.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Android USB Debugging Guide
2+
3+
## Current Situation
4+
5+
**Status**: APK builds and installs, but USB ports not detected on Android tablet
6+
7+
**What We Know**:
8+
- ✅ Build succeeds without errors
9+
- ✅ Plugin v2.16.0 has Android Kotlin code
10+
- ✅ Manifest patch script runs in CI
11+
- ✅ App prompts for USB device handling when device attached
12+
- ❌ No ports show in the UI after permission granted
13+
14+
## Investigation Steps
15+
16+
### 1. Verify Manifest Patching (FIRST PRIORITY)
17+
18+
Run the test workflow:
19+
```bash
20+
# Push the test workflow
21+
git add .github/workflows/test-android-patch.yml
22+
git commit -m "Add manifest patching test workflow"
23+
git push
24+
25+
# Then go to GitHub Actions and run "Test Android Patch" manually
26+
```
27+
28+
Check the workflow output for:
29+
- `BEFORE patch:` section should show unpatched manifest
30+
- `AFTER patch:` section should show USB permissions
31+
- `device_filter.xml` should exist with VID/PID entries
32+
- `build.gradle.kts` should have usb-serial-for-android dependency
33+
34+
### 2. Check Your USB Device VID/PID
35+
36+
On your Linux machine with the flight controller connected:
37+
```bash
38+
lsusb
39+
```
40+
41+
Look for output like:
42+
```
43+
Bus 001 Device 005: ID 0483:5740 STMicroelectronics Virtual COM Port
44+
^^^^ ^^^^
45+
VID PID
46+
```
47+
48+
Verify this VID/PID combination is in `device_filter.xml`:
49+
```xml
50+
<usb-device vendor-id="0x0483" product-id="0x5740"/>
51+
```
52+
53+
If your device isn't listed, we need to add it to the patch script.
54+
55+
### 3. Check Plugin Initialization
56+
57+
The plugin should auto-initialize on Android, but we can verify by checking the Rust code:
58+
59+
**Current initialization** (src-tauri/src/main.rs):
60+
```rust
61+
.plugin(tauri_plugin_serialplugin::init())
62+
```
63+
64+
This should work, but the plugin may need the Android UsbManager to be explicitly initialized.
65+
66+
### 4. Potential Issues
67+
68+
#### Issue A: Runtime Permission Not Requested
69+
Android requires apps to request USB permission at runtime, not just declare it in the manifest. The plugin's Kotlin code should handle this, but it may need:
70+
71+
```kotlin
72+
// In MainActivity.kt or plugin initialization
73+
val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager
74+
val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0)
75+
usbManager.requestPermission(device, permissionIntent)
76+
```
77+
78+
#### Issue B: Plugin Not Using usb-serial-for-android
79+
The plugin may have its own USB implementation that conflicts with usb-serial-for-android. We need to verify the plugin actually uses this library.
80+
81+
#### Issue C: Port Enumeration Timing
82+
Ports may need to be enumerated AFTER USB permission is granted. The app may need to:
83+
1. Wait for USB_DEVICE_ATTACHED broadcast
84+
2. Request permission via dialog
85+
3. THEN enumerate ports after permission granted
86+
87+
### 5. Next Steps
88+
89+
1. **Run test workflow** to verify patches are applied
90+
2. **Check device VID/PID** matches filter
91+
3. **Review plugin source code** at https://github.com/s00d/tauri-plugin-serialplugin/tree/main/android
92+
4. **Add logging** to see what the plugin sees:
93+
- Is UsbManager finding devices?
94+
- Is permission actually granted?
95+
- Does the plugin call port enumeration after permission?
96+
97+
### 6. Workaround: Custom Android Code
98+
99+
If the plugin doesn't properly handle USB, we may need to add custom Android code:
100+
101+
**Option 1**: Fork and patch the plugin
102+
**Option 2**: Add custom Kotlin code to MainActivity
103+
**Option 3**: Use a different approach (WebUSB, custom serial implementation)
104+
105+
## Key Files
106+
107+
- `scripts/patch-android-manifest.sh` - Adds USB permissions and filters
108+
- `src-tauri/gen/android/app/src/main/AndroidManifest.xml` - Generated manifest (check after patch)
109+
- `src-tauri/gen/android/app/src/main/res/xml/device_filter.xml` - USB VID/PID filter
110+
- `src-tauri/gen/android/app/build.gradle.kts` - Should have usb-serial-for-android dependency
111+
112+
## Supported USB Chips (Currently in device_filter.xml)
113+
114+
- FTDI (VID: 0x0403)
115+
- STM32 Virtual COM (VID: 0x0483)
116+
- Silicon Labs CP210x (VID: 0x10c4)
117+
- GD32 (VID: 0x28e9)
118+
- AT32 (VID: 0x2e3c)
119+
- APM32 (VID: 0x314b)
120+
- Raspberry Pi Pico (VID: 0x2e8a)
121+
122+
If your device isn't listed, add it to `patch-android-manifest.sh` in the device_filter.xml section.

0 commit comments

Comments
 (0)