File Transfer Guide
chevron down
 

File Transfer Guide

Overview

The File Transfer API allows developers to easily and reliably transfer binary and text files from the mobile companion to the device, even if the application is not running on the device. The API exposes a simplified file queue, and provides a number of events which allow applications to easily interact with that queue.

How It Works

When a file is queued in the Outbox, the system will begin transferring it to a temporary folder. The file is held in this temporary folder until the transfer has completed. At this point, the file is automatically moved into a staging folder, but is not yet accessible by the application. Finally, an event is raised that a new file exists, and can be processed.

This process is transparent to the developer. The mobile application and device will take care of the connection handshake and retries (if required).

Note: File transfers and retries are handled automatically, even when if the application or companion are not currently running.

Companion Outbox

In order to send a file from the companion to the device, we must first generate or download that file. In this example, we will download an image using the Fetch API, then add that file to the Outbox queue in order to transfer it to the device.

// Import Outbox from the file-transfer module
import { outbox } from "file-transfer"

// Source image on the internet
let srcImage = "https://placekitten.com/348/250";

// Destination filename
let destFilename = "kitten.jpg";

// Fetch the image from the internet
fetch(srcImage).then(function (response) {
  // We need an arrayBuffer of the file contents
  return response.arrayBuffer();
}).then(function (data) {
  // Queue the file for transfer
  outbox.enqueue(destFilename, data).then(function (ft) {
    // Queued successfully
    console.log("Transfer of '" + destFilename + "' successfully queued.");
  }).catch(function (error) {
    // Failed to queue
    throw new Error("Failed to queue '" + destFilename + "'. Error: " + error);
  });
}).catch(function (error) {
  // Log the error
  console.log("Failure: " + error);
});

At this stage, we know if our file was queued successfully, or not. We could now queue additional files, or retry if there was an issue. If you queue a file with the same filename, it will overwrite the previous file.

You can find out more information in the Companion File Transfer API reference documentation.

Device Inbox

In the previous example, we saw how to queue a file for transfer from the companion outbox to the device. In order to use that file on the device, we must listen for incoming file transfers, and move files from the staging folder into the application folder (/private/data/). This is achieved by calling nextFile() on the inbox. The inbox may contain multiple files, so keep processing until the inbox is empty.

Files may also be received while the device application is not running, so it's important to process the inbox queue when the application is first launched too.

import { inbox } from "file-transfer"

function processAllFiles() {
  let fileName;
  while (fileName = inbox.nextFile()) {
    console.log(`/private/data/${fileName} is now available`);
  }
}
inbox.addEventListener("newfile", processAllFiles);
processAllFiles();

If you want to list the contents of the /private/data/ folder, you can use the listDirSync() method.

import { listDirSync } from "fs";
const listDir = listDirSync("/private/data");
do {
  const dirIter = listDir.next();
  if (dirIter.done) {
    break;
  }
  console.log(dirIter.value);
} while (true);

You can find out more information in the Device File Transfer API reference documentation.

Device Outbox

In order to send a file from the device to the companion, we must add that file to the Outbox queue in order for the system to transfer it.

import { outbox } from "file-transfer";

outbox
  .enqueueFile("/private/data/app.txt")
  .then((ft) => {
    console.log(`Transfer of ${ft.name} successfully queued.`);
  })
  .catch((error) => {
    console.log(`Failed to schedule transfer: ${error}`);
  })

Companion Inbox

In the previous example, we saw how to queue a file for transfer from the device outbox to the companion. In order to use that file, we must listen for incoming file transfers, and process each file in the queue. This is achieved by calling pop() on the inbox. The inbox may contain multiple files, so keep processing until the inbox is empty.

Files may also be received while the companion is not running, so it's important to process the inbox queue as files are received, and also when the companion is first launched.

import { inbox } from "file-transfer";

// Process the inbox queue for files, and read their contents as text
async function processAllFiles() {
  let file;
  while ((file = await inbox.pop())) {
    const payload = await file.text();
    console.log(`file contents: ${payload}`);
  }
}

// Process new files as they are received
inbox.addEventListener("newfile", processAllFiles);

// Also process any files that arrived when the companion wasn’t running
processAllFiles()

Best Practices

Here's a simple list of best practices to follow when using the File Transfer API:

  1. The name of the file must be less than 64 characters and can only include the following characters: a-z A-Z 0-9 ! # $ % & ' ( ) - @ ^ _ { } ~ + , . ; = [ ] Files with invalid names will be rejected.
  2. Try to minimize the size of your files before transferring them to the device.
  3. Images sent to the device must be in JPG or TXI format only.
  4. Check the inbox queue when your application or companion is launched.

File Transfer in Action

If you're interested in using the File Transfer API within your application, please review the Companion File Transfer API or Device File Transfer API reference documentation.