Download the PHP package sghimire/mobile-file-access without Composer
On this page you can find all versions of the php package sghimire/mobile-file-access. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download sghimire/mobile-file-access
More information about sghimire/mobile-file-access
Files in sghimire/mobile-file-access
Package mobile-file-access
Short Description Generic native file save/open (Storage Access Framework / UIDocumentPicker) for NativePHP Mobile — pick any file into your app or save arbitrary bytes to a user-chosen location, with no storage permissions required.
License MIT
Informations about the package mobile-file-access
Mobile File Access
Generic native "save file" / "open file" for NativePHP Mobile apps, powered by the Storage Access Framework on Android and UIDocumentPickerViewController on iOS.
Not tied to any particular file type or app — use it to import/export a backup, save a generated PDF, let a user attach an arbitrary document, or read any file the user picks from their device or cloud storage (Files app / Google Drive / Dropbox, wherever the system document picker can reach).
Features
- Save arbitrary bytes to a location the user chooses, with a suggested file name.
- Read any file the user picks, back as base64 — including from cloud-backed providers exposed through the system Files app.
- No storage permissions required on either platform. The document picker grants per-file access on the user's behalf; this plugin never requests
WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE(Android) and declares noInfo.plistusage description (iOS). - Fluent, chainable builders in both PHP and JavaScript.
FileSaved/SaveCancelled/FilePicked/PickCancelledLaravel events, or bind straight to Livewire with#[OnNative].- Works from PHP (Blade/Livewire) and from JavaScript (Vue, React, Inertia, or plain JS).
Example App
Authenticator is a full example app built using this plugin
Requirements
- PHP ^8.2
nativephp/mobile^3.0- iOS 14+ / Android API 23+
livewire/livewire— only needed if you use the#[OnNative]attribute
Installation
Laravel's package auto-discovery registers FileAccessServiceProvider for you. Then register the plugin with NativePHP:
This wires up the plugin's nativephp.json manifest (bridge functions — no permissions to merge, there aren't any) into your native build. Rebuild/reinstall the native shell afterwards (php artisan native:install or native:run) so the bridge functions are picked up.
How It Works (Under the Hood)
Same two-phase pattern as every async call in this plugin family — a synchronous "start" acknowledgement, then the real result delivered later through two parallel channels.
- Request out.
FileAccess::save(...)->save()/FileAccess::pick()->pick()(PHP) andFileAccess.save(...)/FileAccess.pick()(JS) both reach the same bridge — JS viafetch('/_native/api/call', { method: 'FileAccess.Save' | 'FileAccess.Pick', params }), PHP vianativephp_call(...). The bridge router opens the native picker:ActivityResultContracts.CreateDocument/OpenDocumenton Android,UIDocumentPickerViewControlleron iOS. - Immediate ack. The call returns right away confirming the picker is open — not that the user has chosen anything yet.
- Result comes back later, once, per call. On Android, the native side calls
NativeActionCoordinator.dispatchEvent(...); on iOS,LaravelBridge.shared.send?(...). Both inject a script that fires anative-eventCustomEventondocument(what the JSOn()/Off()helpers listen for) and make a call back into Laravel that instantiates and dispatches the real event class (whatEvent::listen()/#[OnNative]pick up). The user backing out of the picker deliversSaveCancelled/PickCancelledthe same way.
Because results are asynchronous and delivered to PHP and JS independently, always drive your UI from the events — never from the return value of save()/pick().
PHP Usage
The FileAccess facade
save()/pick() on the builder return bool — true once the request reached the native bridge, false if it couldn't be started (e.g. running outside the native shell, or the builder was already started once).
If you never call ->save()/->pick() explicitly, it fires automatically when the builder object is destructed — so FileAccess::save('report.pdf', $bytes); alone is enough to trigger it. Calling it yourself is recommended so you can check the return value.
PendingFileSave methods
| Method | Description |
|---|---|
mimeType(string $mimeType) |
MIME type hint. Defaults to application/octet-stream. |
id(string $id) |
Custom correlation ID, delivered back on the event. |
getId() |
Read the current correlation ID, or null. |
save() |
Send the save request to the native bridge. Returns bool. |
PendingFilePick methods
| Method | Description |
|---|---|
mimeTypes(array $mimeTypes) |
Restrict the picker to one or more MIME types. Throws InvalidArgumentException if empty. Defaults to ['*/*']. |
id(string $id) |
Custom correlation ID, delivered back on the event. |
getId() |
Read the current correlation ID, or null. |
pick() |
Send the pick request to the native bridge. Returns bool. |
Listening for results
Livewire: #[OnNative]
JavaScript Usage
Importing
This package doesn't publish a #nativephp import alias (that's reserved for NativePHP's first-party plugins). Import the file directly — either from the vendor path, or copy it into your own resources/js/ and import it from there:
Full TypeScript types are included in file-access.d.ts alongside it.
Saving a file
FileAccess.save(fileName, content) returns a thenable builder — await it directly, or chain builder methods first. content accepts a string (assumed already base64), a Uint8Array, or an ArrayBuffer.
Picking a file
Listening for events
Vue 3 example: encrypted backup export/import
JS API reference
| Export | Signature | Description |
|---|---|---|
FileAccess.save(fileName, content) |
(string, string \| Uint8Array \| ArrayBuffer) => PendingFileSave |
Start building a save request. |
.mimeType(mimeType) |
(string) => this |
MIME type hint. Defaults to application/octet-stream. |
.id(id) |
(string) => this |
Custom correlation ID. |
.getId() |
() => string \| null |
Read the current correlation ID. |
FileAccess.pick() |
() => PendingFilePick |
Start building a pick request. |
.mimeTypes(types) |
(string[]) => this |
Restrict the picker to given MIME types. Throws if empty. |
On(event, callback) |
(string, (payload, eventName) => void) => void |
Subscribe to a native event. |
Off(event, callback) |
(string, (payload, eventName) => void) => void |
Unsubscribe. |
toBase64(bytes) |
(string \| Uint8Array \| ArrayBuffer) => string |
Encode bytes to base64 (chunked, safe for large files). |
fromBase64(base64) |
(string) => Uint8Array |
Decode a base64 string back to bytes. |
Events.FileAccess.FileSaved |
string |
Event name constant. |
Events.FileAccess.SaveCancelled |
string |
Event name constant. |
Events.FileAccess.FilePicked |
string |
Event name constant. |
Events.FileAccess.PickCancelled |
string |
Event name constant. |
await-ing (or .then-ing) a PendingFileSave/PendingFilePick sends the request to the native bridge exactly once — awaiting it twice is a no-op the second time.
Events reference
FileSaved
| Property | Type | Description |
|---|---|---|
fileName |
string |
The name the file was saved as. |
size |
int / number |
Bytes written. |
id |
?string / string \| null |
The correlation ID from .id(), if any. |
SaveCancelled
| Property | Type | Description |
|---|---|---|
reason |
?string / string \| null |
"user_cancelled", "write_failed", or "no_root_view_controller" (iOS). |
message |
?string |
Present alongside write_failed. |
id |
?string / string \| null |
The correlation ID from .id(), if any. |
FilePicked
| Property | Type | Description |
|---|---|---|
fileName |
string |
The picked file's display name. |
mimeType |
string |
Best-effort MIME type from the content provider. |
size |
int / number |
Bytes read. |
contentBase64 |
string |
The file's contents, base64-encoded. |
id |
?string / string \| null |
The correlation ID from .id(), if any. |
PickCancelled
| Property | Type | Description |
|---|---|---|
reason |
?string / string \| null |
"user_cancelled", "read_failed", or "no_root_view_controller" (iOS). |
message |
?string |
Present alongside read_failed. |
id |
?string / string \| null |
The correlation ID from .id(), if any. |
- PHP classes:
Sandip\FileAccess\Native\Events\FileAccess\{FileSaved,SaveCancelled,FilePicked,PickCancelled} - JS event name constants:
Events.FileAccess.{FileSaved,SaveCancelled,FilePicked,PickCancelled}
Why no permissions?
Both platforms delegate file access entirely to a system-owned picker:
- Android uses
Intent.ACTION_CREATE_DOCUMENTandIntent.ACTION_OPEN_DOCUMENT(the Storage Access Framework) viaActivityResultContracts.CreateDocument/OpenDocument. The system grants your app a scoped, per-URI permission for exactly the file the user chose — noWRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGEmanifest entry is requested or needed, on any supported API level. - iOS uses
UIDocumentPickerViewController, which similarly hands back a security-scoped URL for just the chosen file/destination. NoInfo.plistusage-description key applies here (those are only for Camera/Photo Library/Microphone-style device resources).
If you need something this plugin doesn't cover — e.g. picking straight from the photo library — pair it with a plugin built for that (like sghimire/mobile-scanner for camera/QR, or NativePHP's own media picker), which will declare whatever permission that flow actually needs.
Platform notes
| Android | iOS | |
|---|---|---|
| Min OS version | API 23 | 14.0 |
| Permission | none | none |
| Native implementation | resources/android/FileAccessFunctions.kt (Storage Access Framework via ActivityResultContracts) |
resources/ios/FileAccessFunctions.swift (UIDocumentPickerViewController) |
Both are configured automatically by nativephp.json — you don't need to edit native project files by hand.
Testing
Outside of a compiled native shell, FileAccess::save(...)->save() and FileAccess::pick()->pick() return false (there's no bridge to call) — this is expected and is exactly what the test suite asserts.
License
MIT