有人有使用Xamarin的Android MTPDevice的经验吗? 我支持Xamarin中的一个应用程序,该应用程序可在Android上运行,并且需要使用MTP协议通过USB电缆从Nikon DSLR下载图像。
尽管我可以获得访问设备,读取设备属性,获取存储信息和下载的权限,但是只能在单个功能内进行。
下面有很多代码,因此我删除了大约90%的代码,其中包括try / catch,记录调试信息,创建我自己的类的对象并插入SQLite数据库。
问题是,如果我从Recurse函数中退出对DownloadFileAsync的调用,而只是返回一个ObjectHandles列表,然后从调用GetFilesAsync的同一后台服务中调用DownloadFileAsync,则读取设备信息的调用将失败,并且存储设备为空。
即使该代码有效,也只能运行一次。如果我然后断开相机的连接并重新连接它,甚至退出应用程序然后重新启动,我也会遇到同样的问题。
private UsbDevice GetAttachedDevice()
{
// find devices
UsbDevice usbDevice = null;
if (UsbManager.DeviceList != null && UsbManager.DeviceList.Count > 0)
{
foreach (var usbAccessory in UsbManager.DeviceList)
{
return usbAccessory.Value; // yeah, i know
}
}
return null;
}
public async Task<bool> OpenAttachedDevice()
{
var connectedDevice = await GetAttachedDevice();
if (connectedDevice == null)
return false;
usbDeviceConnection = UsbManager.OpenDevice(connectedDevice);
mtpDevice = new MtpDevice(connectedDevice);
mtpDevice.Open(usbDeviceConnection);
MtpDeviceInfo info = mtpDevice.DeviceInfo;
if (info != null)
Log.Information($"Device Info: {info.Manufacturer} {info.Model} {info.SerialNumber}");
else
Log.Information($"Device Info is null");
return true;
}
// finds each storage unit and calls the recursive function to find and download files
public async Task<List<string>> GetFilesAsync()
{
var results = new List<string>();
if (await OpenAttachedDevice())
{
storageUnits = mtpDevice.GetStorageIds();
if (storageUnits == null || storageUnits.Length == 0)
{
Log.Information("GetFileListAsync: StorageUnits is empty");
return results;
}
foreach (var storageUnitId in storageUnits)
{
var storageUnit = mtpDevice.GetStorageInfo(storageUnitId);
if (storageUnit != null)
{
var objectHandles = mtpDevice.GetObjectHandles(storageUnitId, 0, 0);
// this works, I get all the object handles
foreach (var objectHandle in objectHandles)
{
// do stuff here
}
await RecurseMTPDirectories(results, storageUnitId);
}
}
}
return results;
}
// look through all objects in the given folder - download files, recurse back in for folders
private async Task RecurseMTPDirectories(List<string> exhibits, int storageUnitId, string parentFolder = "\\", int parentHandle = -1)
{
// find all the objects in the folder - download the files, add the folders to a list and then recurse into each
var directories = new List<MtpObjectInfo>();
var objectHandles = mtpDevice.GetObjectHandles(storageUnitId, 0, parentHandle);
if (objectHandles != null && objectHandles.Length > 0)
{
foreach (var objectHandle in objectHandles)
{
MtpObjectInfo objectInfo = mtpDevice.GetObjectInfo(objectHandle);
if (objectInfo != null)
{
if (objectInfo.Format == MtpFormat.Association)
{
// add to list of directories
directories.Add(objectInfo);
}
else
{
var imagePath = await GetImagePathForFile();
await DownloadFileAsync(objectHandle, objectInfo.Name, imagePath, thumbPath, objectInfo.CompressedSize);
exhibits.Add(objectInfo.Name);
}
}
}
}
foreach (var objectInfo in directories)
{
string fullname = parentFolder + objectInfo.Name;
await RecurseMTPDirectories(exhibits, storageUnitId, $"{fullname}\\", objectInfo.ObjectHandle);
}
}
// download the actual file, and thumbnail
public async Task DownloadFileAsync(int objectHandle, string nameOnCamera, string destination, string thumbdestination, int size)
{
int receivedBytes = 0;
if (await OpenAttachedDevice())
{
var rootFolder = await FileSystem.Current.GetFolderFromPathAsync(destination);
var thumbFolder = await FileSystem.Current.GetFolderFromPathAsync(thumbdestination);
var fileService = DependencyService.Get<IFileStorageService>();
// download the image data here
byte[] imageData = await mtpDevice.GetObjectAsync(objectHandle, size);
var fileWriter = await rootFolder.CreateFileAsync(nameOnCamera + ".part", CreationCollisionOption.ReplaceExisting);
using (var fileStream = await fileWriter.OpenAsync(PCLStorage.FileAccess.ReadAndWrite))
{
await fileStream.WriteAsync(imageData, 0, size);
}
await fileWriter.RenameAsync(nameOnCamera, NameCollisionOption.ReplaceExisting);
}
}
因此,问题(似乎很疯狂)是,尽管我可以访问MTP设备,但是如果我离开调用该函数的函数来创建MTPdevice,即使MTPdevice对象是全局的,它也只会起作用一次。
我还尝试过关闭连接,MTP设备甚至处置它们,都没有关系。