This Capacitor plugin enables file exchange between two devices. They do not need to be connected to the Internet and do not need to be on the same network.
The plugin uses peer-to-peer technologies of the respective platforms. Devices with iOS use MultipeerConnectivity, devices with Android use Google Nearby.
The plugin does not allow data exchange between devices of different systems (iOS vs. Android).
npm install @enertrag/p2pconnect
npx cap sync
// use Capacitor Filesystem plugin to get file uri
const fileUri = await Filesystem.getUri({
directory: Directory.Data,
path: 'foo/bar/example.json',
});
// define ids
const serviceId = 'p2p-test';
const transferId = 'share.json';
// creating resource descriptor
const resource: ResourceDescriptor = {
id: 'example.json', // we use the filename here
uri: fileUri,
};
// call plugin: method will return after the resource was
// sent to client or the user cancelled the process.
const result = await P2pConnect.send({
serviceId,
transferId,
resources: [resource],
});
// on completion a callback will be called
P2pConnect.addListener('transferComplete', async result => {
// We only handle a single file here.
// It is also valid to send multiple files.
// They always arrive in the same order in
// which they were sent.
const resource = result.resources[0];
// The resource uri is a random temp file.
// Especially the file name differs from the sender!
// We use the resource id as the filename
const fileTargetPath = '/target/foobar/' + resource.id;
// We move(!) the file to the final target,
// for we are responsible for cleaning up the temp file.
await Filesystem.rename({
from: resource.uri,
toDirectory: Directory.Data,
to: fileTargetPath,
});
});
// must be equal for sender and receiver,
// otherwise the devices can't see each other
const serviceId = 'p2p-test';
// the method returns immediatly,
// we must call stopReceive() to stop accepting connections.
const result = await P2pConnect.startReceive({
serviceId,
});
// register callback
P2pConnect.addListener('acceptTransfer', request => {
const transferId: string = request.transferId;
let result = false;
if (transferId.startsWith('share.')) {
// decide on the basis of the data provided
// result = customCheck();
result = true;
}
// The method must be executed within 30 seconds,
// otherwise the process terminates.
// The sender is blocked during this time.
P2pConnect.acceptTransfer({
transferId,
accept: result,
});
});
The following flowchart describes the communication between sender and receiver.
sequenceDiagram
actor Sender
participant Plugin/Sender
participant Plugin/Receiver
actor Receiver
Sender->>Plugin/Sender: send
activate Sender
activate Plugin/Sender
Receiver->>Plugin/Receiver: start receive
activate Receiver
activate Plugin/Receiver
Plugin/Sender-->>Plugin/Sender: browse
Plugin/Receiver-->>Plugin/Receiver: advertise
Plugin/Receiver-->>Receiver: ok
deactivate Receiver
Plugin/Sender-->>Plugin/Receiver: connect
deactivate Plugin/Sender
Plugin/Receiver-->>Plugin/Sender: accept
activate Plugin/Sender
Plugin/Sender->>Plugin/Receiver: check version
deactivate Plugin/Sender
Plugin/Receiver->>Plugin/Sender: accept version
activate Plugin/Sender
deactivate Plugin/Receiver
Plugin/Sender->>Plugin/Receiver: check transfer id
deactivate Plugin/Sender
activate Plugin/Receiver
Plugin/Receiver-->>Receiver: notify transfer id
deactivate Plugin/Receiver
activate Receiver
Receiver->>Plugin/Receiver: accept transfer
deactivate Receiver
activate Plugin/Receiver
Plugin/Receiver->>Plugin/Sender: accept transfer
activate Plugin/Sender
Plugin/Sender-->>Plugin/Receiver: transfer resource count
Plugin/Sender-->>Plugin/Receiver: transfer ids (android only)
deactivate Plugin/Receiver
Plugin/Sender->>Plugin/Receiver: send resources
activate Plugin/Receiver
Plugin/Sender->>Plugin/Sender: send
Plugin/Sender-->>Sender: done (iOS)
activate Receiver
Plugin/Receiver->>Receiver: transfer complete
deactivate Plugin/Sender
Plugin/Receiver-->>Plugin/Sender: ok (android)
activate Plugin/Sender
deactivate Plugin/Receiver
Plugin/Sender-->>Sender: done (android)
deactivate Plugin/Sender
deactivate Sender
Receiver-->>Receiver: move files
deactivate Receiver
isAvailable()
removeAllListeners()
addListener(...)
addListener(...)
send(...)
startReceive(...)
stopReceive()
acceptTransfer(...)
- Interfaces
- Enums
The methods of the peer-to-peer interface are described below.
isAvailable() => any
Indicates whether the Peer to Peer function is available on the device.
Returns: any
Since: 1.0.0
removeAllListeners() => any
Remove all native listeners for this plugin.
Returns: any
Since: 1.0.0
addListener(eventName: 'acceptTransfer', listenerFunc: (request: AcceptTransferRequest) => void) => Promise<PluginListenerHandle> & PluginListenerHandle
The notification is triggered on the recipient's side when a new transfer is received that needs to be confirmed.
Param | Type |
---|---|
eventName |
"acceptTransfer" |
listenerFunc |
(request: AcceptTransferRequest) => void |
Returns: any
addListener(eventName: 'transferComplete', listenerFunc: (result: TransferResult) => void) => Promise<PluginListenerHandle> & PluginListenerHandle
Notification is triggered on the recipient's side when a transfer is complete.
Param | Type |
---|---|
eventName |
"transferComplete" |
listenerFunc |
(result: TransferResult) => void |
Returns: any
send(options: SendOptions) => any
Starts a transfer on the sender's side.
Param | Type |
---|---|
options |
SendOptions |
Returns: any
startReceive(options: ReceiveOptions) => any
Activates the reception of a transfer on the recipient's side.
Param | Type |
---|---|
options |
ReceiveOptions |
Returns: any
stopReceive() => any
Cancels the reception on the receiver's side.
Returns: any
acceptTransfer(options: AcceptTransferOptions) => any
Must be called in response to the 'acceptTransfer' notification and determines on the recipient's side whether the transfer should be accepted or rejected.
Param | Type |
---|---|
options |
AcceptTransferOptions |
Returns: any
Describes a request to the recipient to confirm or decline acceptance of the transfer.
Prop | Type | Description |
---|---|---|
transferId |
string |
The ID of the transfer whose status is to be confirmed. |
Prop | Type |
---|---|
remove |
() => any |
The result of a transmission process for the receiver.
Prop | Type | Description |
---|---|---|
transferId |
string |
The ID for the transfer process. |
resources |
{} |
The list of the transferred resources. |
Describes a resource to be transferred.
Prop | Type | Description |
---|---|---|
id |
string |
An identifier for the resource. This will be the same for sender and receiver. |
uri |
string |
The resource URI. This must be an absolute URI. It will include a schema, depending of the target system. The path (especially the last part) will vary between sender and receiver. |
Defines the parameters of the sender to transfer files.
Prop | Type | Description |
---|---|---|
serviceId |
string |
The identifier for the P2P process. Only devices that use the same identifier can be found. To remain compatible with iOS devices, the identifier must meet the following criteria: <ul> <li>Must be 1–15 characters long</li> <li>Can contain only ASCII lowercase letters, numbers, and hyphens</li> <li>Must contain at least one ASCII letter</li> <li>Must not begin or end with a hyphen</li> <li>Must not contain hyphens adjacent to other hyphens.</li> </ul> |
transferId |
string |
The ID for the transfer process. |
resources |
{} |
The list of the resources to be transferred. |
Defines the parameters for receiving a transfer.
Prop | Type | Description |
---|---|---|
serviceId |
string |
The identifier for the P2P process. Only devices that use the same identifier can be found. To remain compatible with iOS devices, the identifier must meet the following criteria: <ul> <li>Must be 1–15 characters long</li> <li>Can contain only ASCII lowercase letters, numbers, and hyphens</li> <li>Must contain at least one ASCII letter</li> <li>Must not begin or end with a hyphen</li> <li>Must not contain hyphens adjacent to other hyphens.</li> </ul> |
Accepts or rejects a transfer.
Prop | Type | Description |
---|---|---|
transferId |
string |
The ID for the transfer process. |
accept |
boolean |
<code>true<code> to accept the transfer, <code>fale</code> otherwise. |
Members | Value | Description |
---|---|---|
transferInterrupted |
'transferInterrupted' |
The transfer was interrupted by either sender or receiver. |
versionMismatch |
'versionMismatch' |
The plugin version differs between sender and receiver. |
transferDenied |
'transferDenied' |
The recipient has refused to receive the transfer. |
cancelled |
'cancelled' |
The sending process was cancelled. |
permissionDenied |
'permissionDenied' |
The user has not granted the requested permissions. |
internalError |
'internalError' |
An internal error occured. Something went terribly wrong. |
connectionFailed |
'connectionFailed' |
The connection between the peers could not be established. |