nodejs
cross-platform android device file management tool based on libmtp. MacOs
, Windows
, and Linux
platforms are supported.
English | 简体中文
npm install luck-node-mtp
const mtp = require('luck-node-mtp');
// Connect to the first found device.
mtp.connect();
// Download a file from the device to the local system.
mtp.download('data/com.ahyungui.android/db/upload.zip', '/Users/tmp/upload.zip', (send, total) => {
console.log('progress', send, total);
});
// Release the device.
mtp.release();
Wrapping your connection in a try/catch block ensures that the device can be released.
const mtp = require('luck-node-mtp');
mtp.connect();
try {
mtp.download('data/com.ahyungui.android/db/upload.zip', '/Users/tmp/upload.zip', (send, total) => {
console.log('progress', send, total);
});
} catch(error) {
console.error(error);
} finally {
mtp.release();
}
Connect to a specific device with its known vendor and product ids. Find its storage named 'DATA' then set that storage. Find a file named 'download.zip' then download that file to your local system.
mtp.connect(0x061a, 0x1100);
// Get a list of storage partitions on the device.
// Search for a partition named 'DATA'.
const foundStorage = mtp.getCurrentDeviceStorageInfo().filter((storage) => storage.StorageDescription.toUpperCase() === 'DATA');
if (foundStorage.length === 1) {
// Set the storage partition.
mtp.setStorage(foundStorage[0].id);
// Get a list of files and folders in the search directory on the device.
// Search for a specific file named 'download.zip'.
const foundObjects = mtp.getList('/Data/User/Download').filter((obj) => obj.type === 'FILE' && obj.name === 'download.zip');
if (foundObjects.length === 1) {
const source = foundObjects[0];
const sourcePath = `/Data/User/Download/${source.name}`;
const targetPath = `/Users/tmp/${source.name}`;
mtp.download(sourcePath, targetPath, (send, total) => {
// Print the progress percentage.
console.log(`${(total / source.size) * 100}%`);
});
}
}
bool connect(uint vid?, uint pid?)
Connect device
If the vendor and product id parameters are not set the first device that is found will be connected.
- @param vid: Vendor id
- @param pid: Product id
- @return Get
true
if the operation was successful
const result = mtp.connect();
To access a certain device through vendor id
and product id
. You can get the device information through the getDeviceInfo method.
const result = mtp.connect(vid, pid);
bool release()
Release the currently connected device.
The device needs to be released after use otherwise an error will be thrown when connecting again.
- @return Get
true
if the operate was successful
const result = mtp.release();
array getList(string parentPath)
Get a list of objects within a given mtp device parent path. A file tree can be build by using this method.
- @param parentPath: Parent path. Use
/
to scan the root directory. - @return: File info array
const result = mtp.getList('/data/com.ahyungui.android/db/');
Example output:
[
{
name: '1',
size: 0,
type: 'FOLDER',
id: 156,
modificationdate: 1672041505,
parent_id: 152,
storage_id: 65537
},
{
name: 'download.zip',
size: 8893742,
type: 'FILE',
id: 158,
modificationdate: 1673321627,
parent_id: 152,
storage_id: 65537
}
]
array getDeviceInfo()
Returns a list of valid connected devices.
- @return Device information array
const result = mtp.getDeviceInfo();
Examples output:
[
{
vendor: 'MediaTek Inc',
vendor_id: 3725,
product: 'Elephone P8000',
product_id: 8221
}
]
bool upload(string localFilePath, string targetFolderPath, string progressCallBackFunction?)
Upload local files to the device.
- @param localFilePath: Source file path
- @param targetFolderPath: Target device parent folder path
- @param progressCallBackFun: Callback function for upload progress (send, total) => {}
- @return Get
true
if the operation was successful
mtp.upload('/Users/tmp/download.zip', 'data/com.ahyungui.android/db', (send, total) => {
console.log('progress', send, total);
});
bool del(string targetPath)
This function deletes a single file, track, playlist, folder or any other object from the MTP device, identified by the object ID.
If you delete a folder there is no guarantee that the device will really delete all the files that were in that folder. It is expected that they will not be deleted and will turn up in object listings its parent set to a non-existant object ID. The safe way to do this is to recursively delete all files (and folders) contained in the folder then the folder itself.
- @param targetPath: The destination address on the device to delete
- @return Get
true
if the operation was successful
mtp.del('/data/com.ahyungui.android/db/download.zip');
object getObject(string targetPath)
Obtain information about an object on the device.
- @param targetPath: File path on device
- @return Return object information
const result = mtp.get('data/com.ahyungui.android/db/upload.zip');
Example output:
{
name: 'upload.zip',
size: 8893742,
type: 'FILE',
id: 163,
modificationdate: 1673149510,
parent_id: 152,
storage_id: 65537
}
bool copy(string sourcePath, string targetFolderPath)
The semantics of copying a folder are not defined in the MTP spec, but it appears to do the right thing when tested. Devices that implement this operation are rare.
Copying an object may take a significant amount of time.
MTP does not provide any kind of progress mechanism so the operation will simply block for the duration.
- @param sourcePath: The path of the file on the device to be copied
- @param targetFolderPath: The destination path on the device
- @return Get
true
if the operation was successful
mtp.copy('/data/com.ahyungui.android/db/download.zip', '/data/com.ahyungui.android/db/8057');
bool move(string sourcePath, string targetFolderPath)
The function moves an object from one location on the device to another location.
The semantics of moving a folder are not defined in the spec, but it appears to do the right thing when tested. Devices that implement this operation are rare.
Moving an object may take a significant amount of time, particularly if being moved between storage locations. MTP does not provide any kind of progress mechanism, so the operation will simply block for the duration.
- @param sourcePath: The path of the file on the device to be moved
- @param targetFolderPath: The destination path on the device
- @return Get
true
if the operation was successful
mtp.move('/data/com.ahyungui.android/db/download.zip', '/data/com.ahyungui.android/db/8057');
bool setFileName(string targetPath, string newName)
Set the file name of an object on the device.
- @param targetPath: Path to the file on the device
- @param newName: New file name
- @return Get
true
if the operation was successful
mtp.setFileName('/data/com.ahyungui.android/db/download.zip', 'download1.zip');
bool setFolderName(string targetPath, string newName)
Set the name of a folder on the device.
- @param targetPath: Folder path on device
- @param newName: New folder name
- @return Get
true
if the operation was successful
mtp.setFolderName('/data/com.ahyungui.android/db/8057', '8067');
uint createFolder(string parentFolderPath, string newName)
Create a folder on the device.
- @param targetPath: The path to the parent folder into which the new folder will be created
- @param newName: Folder name
- @return id
mtp.createFolder('/data/com.ahyungui.android/db', 'test_folder');
array getCurrentDeviceStorageInfo()
Get the storage information of the currently connected device.
- @return Store information array
mtp.getCurrentDeviceStorageInfo();
Example output:
[
{
id: 65537,
StorageDescription: 'DATA',
VolumeIdentifier: ''
}
]
bool setStorage(uint storageId)
Select the device storage for the currently connected device.
If there are multiple storages in the device you can first obtain the device storage list through getCurrentDeviceStorageInfo.
After setting the storage all of the file management operations will be based on this storage.
If the storage is not set the device will select the first storage automatically when connecting.
- @param storageId: Storage id
- @return Get
true
if the operation was successful
mtp.connect();
mtp.getCurrentDeviceStorageInfo();
mtp.setStorage(result[0].id);
mtp.release();
The current version has prebuilt binary files for darwin-x64
and win32-x64
which means that users of these two operating systems can use them without recompiling.
Users of other operating systems need to build their own development environment to recompile. Refer to the Development Environment chapter.
You can help out by issuing a pull request against prebuild
if you've compiled for other systems.
The Windows platform needs to install the
WinUSB
,libusb-win32
, orlibusbK
driver to work properly. UseZadig
to manage the drivers of each device. The way to manage the drivers throughZadig
is as follows:
-
Connect your device to the system
-
List all
USB
devices viaZadig
menu -
Then select the
MTP
device to replace the driverAs shown in the picture:
When a mobile phone is connected you need to select the
file transfer (MTP)
mode on your phone to use it as a MTP device.
There is an example under the Mac
platform in install/after.js
. You can do some follow-up work after the precompiled file is generated, such as:
if (os.platform() == "darwin") {
// init share obj
shell.exec('cp -rf /usr/local/opt/libmtp/lib/libmtp.9.dylib ' + _rootPath + '/prebuilds/darwin-x64/libmtp.dylib');
shell.exec('cp -rf /usr/local/opt/libusb/lib/libusb-1.0.0.dylib ' + _rootPath + '/prebuilds/darwin-x64/libusb.dylib');
shell.exec('install_name_tool -change /usr/local/opt/libmtp/lib/libmtp.9.dylib @loader_path/libmtp.dylib ' + _rootPath + '/prebuilds/darwin-x64/node.napi.node');
shell.exec('install_name_tool -change /usr/local/opt/libusb/lib/libusb-1.0.0.dylib @loader_path/libusb.dylib ' + _rootPath + '/prebuilds/darwin-x64/libmtp.dylib');
console.log('node.napi.node links:',shell.exec('otool -L '+_rootPath+'/prebuilds/darwin-x64/node.napi.node'));
console.log('libmtp.dylib links:',shell.exec('otool -L '+_rootPath+'/prebuilds/darwin-x64/libmtp.dylib'));
}
xcode
and nodejs 14+
are required.
You also need to install the libmtp
library:
brew install libmtp
Visual Studio
, nodejs 14+
, and python3
are required.
You need to install libmtp-dev
:
sudo apt-get install libmtp-dev
You can run the following command to test the files under the test
directory:
// test test/test_connect.js
npm run test connect
- Under Windows the storage name obtained by the getCurrentDeviceStorageInfo method may contain Chinese language characters.