File Transfer
Send files to the Watch in the background, and receive the files it sends you.
A File Transfer is a file, with optional metadata, queued for background delivery to the Watch. The Watch doesn't have to be reachable.
Each file you send is a Transfer until it's delivered:
transferFilestarts one and returns its Transfer snapshot.outstandingFileTransferslists the ones not delivered yet, with their progress.cancelFileTransfercancels one by its id.onFileTransferFinishedfires exactly once per Transfer: when it's delivered, fails or is cancelled.
Files the Watch sends you are Received files. They arrive through onFileReceived, or through onFileReceiveFailed when one couldn't be kept.
Transfer ids last for one app run
After your app restarts, a Transfer that's still outstanding gets a new id. Read
outstandingFileTransfers at launch to pick them up. Their finish events and
cancelFileTransfer use the new ids.
transferFile
transferFile(file: string, metadata?: Record<string, any>): FileTransferQueues a file for delivery to the Watch and returns at once. The Watch app receives it in session(_:didReceive:).
WatchConnectivity keeps its own copy of the file, so you can delete yours right after calling transferFile. That doesn't stop or fail the Transfer.
Parameters
| Name | Type | Description |
|---|---|---|
file | string | A file:// URL of an existing file, such as the uri of an expo-file-system File. |
metadata | Record<string, any> (optional) | A dictionary sent with the file, for example its original name. |
Returns the Transfer snapshot, FileTransfer, in the same shape as outstandingFileTransfers:
| Field | Type | Description |
|---|---|---|
id | string | The Transfer id, valid for the current app run. |
isTransferring | boolean | Whether the Transfer is in progress right now. |
progress | FileProgress | fractionCompleted (0 to 1), completedUnitCount and totalUnitCount (bytes). |
file | File | fileURL (the file being sent) and metadata (what you passed). |
Throws (synchronously):
| Code | When |
|---|---|
ERR_INVALID_FILE_URL | file isn't a URL the library can read. |
ERR_FILE_NOT_FOUND | There's no file at file. |
ERR_UNSUPPORTED_PLATFORM | Called on a platform other than iOS. |
Its error message starts with Expo's prefix, "Calling the 'transferFile' function has failed", so match on code. Delivery failures don't throw here: they arrive later, in onFileTransferFinished.
Example
import , { type } from "rn-watch-connect";
const = "file:///path/to/Documents/route.gpx";
try {
const = .(, { : "route.gpx" });
.("Queued Transfer", .);
} catch () {
const = ( as { ?: }).;
if ( === "ERR_FILE_NOT_FOUND") {
// The file was moved or deleted before you could send it.
}
}cancelFileTransfer
cancelFileTransfer(transferId: string): { id: string }Cancels an outstanding File Transfer. Its onFileTransferFinished event is sent immediately, with error.code "ERR_TRANSFER_CANCELLED".
Parameters
| Name | Type | Description |
|---|---|---|
transferId | string | The id of an outstanding Transfer, from the current app run. |
Returns { id: string }: the id of the cancelled Transfer.
Throws (synchronously):
| Code | When |
|---|---|
ERR_INVALID_TRANSFER_ID | transferId isn't an outstanding Transfer: it was already delivered, already cancelled, or is from an earlier app run. |
ERR_UNSUPPORTED_PLATFORM | Called on a platform other than iOS. |
Its error message starts with Expo's prefix, "Calling the 'cancelFileTransfer' function has failed", so match on code.
If the Transfer was delivered just before you cancel, the cancel throws ERR_INVALID_TRANSFER_ID and the finish event reports the delivery, with error: null.
Example
import from "rn-watch-connect";
// Cancel every File Transfer still waiting.
for (const of .) {
.(.);
}outstandingFileTransfers
readonly outstandingFileTransfers: FileTransfer[]The File Transfers that haven't been delivered yet, as Transfer snapshots (id, isTransferring, progress, file). It's [] when there are none, and on platforms other than iOS.
WatchConnectivity has no progress event. To show progress, read this property every so often, and use onFileTransferFinished to know when a Transfer is done.
Example
import from "rn-watch-connect";
const = (() => {
for (const { , } of .) {
.(, `${.(. * 100)}%`);
}
}, 1000);
// Later: clearInterval(timer);onFileReceived
onFileReceived: (file: File) => voidFires when a Received file arrives from the Watch.
Event
| Field | Type | Description |
|---|---|---|
fileURL | string | Where the file is now: in your app's temporary directory. |
metadata | Record<string, any> | What the Watch sent with the file. |
The file is yours from this event on. The library moves each Received file into your app's temporary directory, then never moves, overwrites or deletes it again.
- iOS can delete files in the temporary directory while your app isn't running. Move or copy the file somewhere permanent if you need to keep it, and delete it when you're done.
- Received files never overwrite each other. If the name is taken, the new file is numbered the way Finder does it:
photo.jpg, thenphoto(1).jpg,photo(2).jpg, and so on.metadatais passed through unchanged, so you can still read the original name if the Watch sent it there.
Example
import { } from "expo";
import from "rn-watch-connect";
export function () {
(, "onFileReceived", ({ , }) => {
const = .name ?? .("/").();
.(`Received ${} at ${}`);
// Move or copy it somewhere permanent here if you need to keep it.
});
return null;
}onFileReceiveFailed
onFileReceiveFailed: (event: FileReceiveFailedEvent) => voidFires when a file from the Watch arrived but couldn't be kept, for example because the iPhone is out of storage. The file is lost: WatchConnectivity has already deleted it, and onFileReceived doesn't fire for it. Use fileName and metadata to tell which file it was, for example to ask the Watch to send it again.
Event
| Field | Type | Description |
|---|---|---|
message | string | Why the file couldn't be kept. |
code | WatchConnectErrorCode | ERR_INSUFFICIENT_SPACE when the iPhone is out of storage, otherwise ERR_FILE_RECEIVE_FAILED. |
fileName | string | The file name the Watch sent. |
metadata | Record<string, any> | null | What the Watch sent with the file, or null when it sent nothing. |
Example
import { } from "expo";
import from "rn-watch-connect";
export function () {
(, "onFileReceiveFailed", ({ , }) => {
if ( === "ERR_INSUFFICIENT_SPACE") {
.(`Not enough storage to keep ${} from the Watch.`);
} else {
.(`Couldn't keep ${} from the Watch.`);
}
});
return null;
}onFileTransferFinished
onFileTransferFinished: (event: FileTransferFinishedEvent) => voidFires exactly once per File Transfer, however it ends. The event is the Transfer snapshot (id, isTransferring, progress, file) plus error:
| How it ended | error |
|---|---|
| Delivered to the Watch | null |
| Failed | { message, code } from WatchConnectivity, for example code: "ERR_DELIVERY_FAILED" |
Cancelled with cancelFileTransfer | { message, code: "ERR_TRANSFER_CANCELLED" }, sent immediately |
If your Watch app is uninstalled during a Transfer, the Transfer stays outstanding and no finish event is sent, even after a reinstall. Cancel it to end it, for example when onWatchAppInstallChanged reports isWatchAppInstalled: false.
Example
import { } from "expo";
import from "rn-watch-connect";
export function () {
(, "onFileTransferFinished", () => {
if (.?. === "ERR_TRANSFER_CANCELLED") {
.("Cancelled:", .);
} else if (.) {
.("Failed:", ., ..);
} else {
.("Delivered:", ..);
}
});
return null;
}