Skip to content

Add Android ContentResolver support for content:// URI access#30

Merged
kevincarlson merged 1 commit into
masterfrom
claude/fix-android-file-permissions-RPq9z
Mar 30, 2026
Merged

Add Android ContentResolver support for content:// URI access#30
kevincarlson merged 1 commit into
masterfrom
claude/fix-android-file-permissions-RPq9z

Conversation

@kevincarlson

Copy link
Copy Markdown
Member

Summary

This PR adds native Android ContentResolver support to handle content:// URIs, which cannot be accessed via Tauri's plugin-fs (which uses Rust's std::fs). The changes introduce two new Kotlin plugin commands and update the frontend to use them when working with Storage Access Framework (SAF) URIs on Android.

Key Changes

  • UriPermissionPlugin.kt: Extended the plugin with two new commands:

    • readUri: reads all bytes from a content:// URI via ContentResolver.openInputStream
    • writeUri: writes bytes to a content:// URI via ContentResolver.openOutputStream in write-truncate mode
    • Updated class documentation to reflect the expanded functionality
  • commands.ts: Added two new TypeScript command wrappers:

    • readContentUri(uri): invokes the native readUri command and converts the result to Uint8Array
    • writeContentUri(uri, bytes): invokes the native writeUri command with byte array conversion
  • useFileOperations.ts: Updated file I/O logic to route content:// URIs through the new ContentResolver commands:

    • openFile: uses readContentUri for content:// paths instead of readFile
    • saveDocument: uses writeContentUri for content:// paths instead of writeFile
    • saveAsDocument: uses writeContentUri for content:// paths and improved control flow to handle both write paths uniformly
  • SessionManager.ts: Updated saveToOriginal to detect and route content:// URIs through writeContentUri

Implementation Details

  • Byte conversion handles unsigned byte values (0–255) correctly in both directions between Kotlin and TypeScript
  • writeUri uses write-truncate mode ("wt") to replace existing content
  • All new commands include comprehensive JSDoc comments explaining Android-specific behavior
  • Error handling is consistent with existing plugin patterns
  • The changes are backward compatible; non-Android platforms continue using plugin-fs

https://claude.ai/code/session_01J39pMh3ZymXAf9W5K3Ziyi

Tauri's plugin-fs uses Rust's std::fs, which cannot open or write
content:// URIs on Android. All file reads and writes that previously
went through readFile/writeFile from @tauri-apps/plugin-fs now route
through a native Android ContentResolver path for content:// URIs.

Changes:
- UriPermissionPlugin.kt: add readUri and writeUri @command methods that
  use ContentResolver.openInputStream / openOutputStream("wt") to
  reliably read/write SAF URIs from the Kotlin layer.
- commands.ts: add readContentUri and writeContentUri TypeScript wrappers
  for the new plugin commands.
- useFileOperations.ts: loadDocument now uses readContentUri for
  content:// paths instead of readFile; handleSave (non-session path)
  uses writeContentUri; handleSaveAs uses writeContentUri and also moves
  state updates (setPath, startSession, addDocument, markClean) outside
  the `if (bytes)` guard so they execute on desktop saves too.
- SessionManager.saveToOriginal: uses writeContentUri for content:// URIs
  instead of writeFile, fixing Ctrl+S on Android.

https://claude.ai/code/session_01J39pMh3ZymXAf9W5K3Ziyi
@kevincarlson kevincarlson self-assigned this Mar 30, 2026
@kevincarlson kevincarlson merged commit f128131 into master Mar 30, 2026
12 checks passed
@kevincarlson kevincarlson deleted the claude/fix-android-file-permissions-RPq9z branch March 30, 2026 08:32
@AppThere AppThere locked as resolved and limited conversation to collaborators Mar 30, 2026
@kevincarlson kevincarlson restored the claude/fix-android-file-permissions-RPq9z branch March 30, 2026 08:35
@AppThere AppThere unlocked this conversation Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants