C# 为什么MtpDevice.ImportFile总是失败?

C# 为什么MtpDevice.ImportFile总是失败?,c#,android,xamarin,import,mtp,C#,Android,Xamarin,Import,Mtp,我正在修改一个现有的应用程序,它是用C#in Xamarin编写的,专门为Android构建的 现有的应用程序在摄像头的wifi卡上搜索文件,并通过HTTP接口下载。我试图让它下载的文件使用拴在一个USB电缆代替,但无法得到文件下载 我正在使用MtpDevice尝试下载,但ImportFile函数总是失败。不幸的是,它从未抛出异常,也没有给出任何关于原因的有用信息 下面的代码显示了我正在做的事情,尽管我已经删除了一些与问题无关的东西 当我修改现有的应用程序时,代码有点复杂,因为有一种方法可以找到

我正在修改一个现有的应用程序,它是用C#in Xamarin编写的,专门为Android构建的

现有的应用程序在摄像头的wifi卡上搜索文件,并通过HTTP接口下载。我试图让它下载的文件使用拴在一个USB电缆代替,但无法得到文件下载

我正在使用MtpDevice尝试下载,但ImportFile函数总是失败。不幸的是,它从未抛出异常,也没有给出任何关于原因的有用信息

下面的代码显示了我正在做的事情,尽管我已经删除了一些与问题无关的东西

当我修改现有的应用程序时,代码有点复杂,因为有一种方法可以找到文件,然后后台线程调用另一种方法来进行实际下载,因此用户可以在下载文件时继续工作

另外,我在GetFileListAsync中显示的一些代码实际上也存在于其他方法中,因为它们被多次使用。。。我没有包括权限的东西,因为这一切似乎都很好

这是首先被调用的方法,用于查找对象句柄列表

public async Task<List<MyFileClass>> GetFileListAsync()
{
    var results = new List<MyFileClass>();
    UsbDeviceConnection usbDeviceConnection = null;
    MtpDevice mtpDevice = null;
    UsbDevice usbDevice = null;

    // all this stuff works as expected...

    UsbManager usbManager = (UsbManager)Android.App.Application.Context.GetSystemService(Context.UsbService);

    try
    {
        if (usbManager.DeviceList != null && usbManager.DeviceList.Count > 0)
        {
            foreach (var usbAccessory in usbManager.DeviceList)
            {
                var device = usbAccessory.Value;
                usbDevice = usbAccessory.Value;
                break;  // should only ever be one, but break here anyway
            }
        }
    }
    catch (Exception ex)
    {
        Log.Error(ex, "Error getting USB devices");
    }

    if (usbDevice == null)
    {
        Log.Information("ConnectedDevice is null");
        return false;
    }

    if (!UsbManager.HasPermission(usbDevice))
    {
        Log.Information("Requesting permission must have failed");
        return false;
    }

    try
    {
        usbDeviceConnection = UsbManager.OpenDevice(usbDevice);
    }
    catch (Exception ex)
    {
        Log.Error(ex, "opening usb connection");
        return false;
    }

    try
    {
        mtpDevice = new MtpDevice(usbDevice);
    }
    catch (Exception ex)
    {
        Log.Error(ex, "creating mtpdevice");
        return false;
    }

    try
    {
        mtpDevice.Open(usbDeviceConnection);
    }
    catch (Exception ex)
    {
        Log.Error(ex, " opening mtpdevice");
        usbDeviceConnection.Close();
        return false;
    }

    // then start looking for files

    var storageUnits = mtpDevice.GetStorageIds();
    if (storageUnits == null || storageUnits.Length == 0)
    {
        Log.Information("StorageUnits is empty");
        mtpDevice.Close();
        usbDeviceConnection.Close();
        return false;
    }

    foreach (var storageUnitId in storageUnits)
    {
        var storageUnit = mtpDevice.GetStorageInfo(storageUnitId);
        if (storageUnit != null)
        {
            // recurse directories to get list of files
            await RecurseMTPDirectories(results, storageUnitId, docketId, docket, db);
        }
    }
}

private async Task RecurseMTPDirectories(List<MyFileClass> files, int storageUnitId, string parentFolder = "\\", int parentHandle = -1)
{
    var results = new List<FlashAirFile>();
    var directoryObjects = 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 the list to recurse into, but do this at the end
                    directoryObjects.Add(objectInfo);
                }
                else
                {
                    // it' a file - add it only if it's one we want
                    try
                    {
                        var file = new MyFileClass()
                        {
                            TotalBytes = objectInfo.CompressedSize,
                            FileNameOnCard = objectInfo.Name,
                            DirectoryOnCard = parentFolder,
                            MTPHandle = objectHandle
                        };
                    }
                    catch (Exception e)
                    {
                        Log.Error(e, " trying to create MTP FlashAirFile");
                    }
                }
            }
        }
    }

    foreach (var directoryObject in directoryObjects)
    {
        string fullname = parentFolder + directoryObject.Name;
        await RecurseMTPDirectories(files, storageUnitId, $"{fullname}\\", directoryObject.ObjectHandle);
    }
    return results;
}
公共异步任务GetFileListAsync() { var results=新列表(); UsbDeviceConnection UsbDeviceConnection=null; MtpDevice MtpDevice=null; UsbDevice UsbDevice=null; //所有这些东西都像预期的那样工作。。。 UsbManager UsbManager=(UsbManager)Android.App.Application.Context.GetSystemService(Context.UsbService); 尝试 { if(usbManager.DeviceList!=null&&usbManager.DeviceList.Count>0) { foreach(usbManager.DeviceList中的var usbAccessory) { var设备=usbAccessory.Value; usbDevice=usbAccessory.Value; break;//应该只有一个,但无论如何在这里break } } } 捕获(例外情况除外) { Log.Error(例如,“获取USB设备时出错”); } 如果(usbDevice==null) { 日志信息(“ConnectedDevice为空”); 返回false; } 如果(!UsbManager.HasPermission(usbDevice)) { 日志信息(“请求权限必须失败”); 返回false; } 尝试 { usbDeviceConnection=UsbManager.OpenDevice(usbDevice); } 捕获(例外情况除外) { 日志错误(例如,“打开usb连接”); 返回false; } 尝试 { MTP设备=新的MTP设备(USB设备); } 捕获(例外情况除外) { 日志错误(例如,“创建mtpdevice”); 返回false; } 尝试 { MTP设备打开(usbDeviceConnection); } 捕获(例外情况除外) { 日志错误(例如,“打开MTP设备”); usbDeviceConnection.Close(); 返回false; } //然后开始查找文件 var storageUnits=mtpDevice.GetStorageIds(); if(storageUnits==null | | storageUnits.Length==0) { 日志信息(“存储单元为空”); mtpDevice.Close(); usbDeviceConnection.Close(); 返回false; } foreach(storageUnits中的var storageUnitId) { var storageUnit=mtpDevice.GetStorageInfo(storageUnitId); if(storageUnit!=null) { //递归目录以获取文件列表 等待RecurseMTP目录(结果、storageUnitId、docketId、docket、db); } } } 私有异步任务RecurseMTP目录(列表文件,int-storageUnitId,字符串parentFolder=“\\”,int-parentHandle=-1) { var results=新列表(); var directoryObjects=新列表(); var objectHandles=mtpDevice.GetObjectHandles(storageUnitId,0,parentHandle); if(objectHandles!=null&&objectHandles.Length>0) { foreach(objectHandles中的var objectHandle) { MtpObjectInfo objectInfo=mtpDevice.GetObjectInfo(objectHandle); if(objectInfo!=null) { if(objectInfo.Format==MtpFormat.Association) { //添加到要递归到的列表中,但在末尾执行此操作 添加(objectInfo); } 其他的 { //它是一个文件-仅当它是我们想要的文件时才添加它 尝试 { var file=新的MyFileClass() { TotalBytes=objectInfo.CompressedSize, filenameocard=objectInfo.Name, DirectoryOnCard=parentFolder, MTPHandle=objectHandle }; } 捕获(例外e) { Log.Error(例如,“尝试创建MTP FlashAirFile”); } } } } } foreach(directoryObjects中的var directoryObject) { 字符串fullname=parentFolder+directoryObject.Name; 等待RecurseMTP目录(文件,storageUnitId,$“{fullname}\\”,directoryObject.ObjectHandle); } 返回结果; } 我知道可以一次获取所有句柄,而不是在文件夹中递归,但现在我正在按照旧代码那样做

MyFileClass对象的列表被添加到SQLite数据库中,然后后台线程一次对它们进行一个解队列,并调用DownloadFileAsync来获取每个文件。 此方法使用的设备与GetFileListAsync方法中使用的设备相同,并且它还检查权限是否仍然可用

public async Task<int> DownloadFileAsync(MyFileClass file, string destination)
{
    int receivedBytes = 0;
    int objectHandle = file.MTPHandle;

    connectedDevice = await GetAttachedDevice();
    if (connectedDevice == null || !UsbManager.HasPermission(connectedDevice))
        return receivedBytes;

    if (!await OpenAttachedDevice())
        return receivedBytes;

    var rootFolder = await FileSystem.Current.GetFolderFromPathAsync(destination);
    var localFile = rootFolder.Path;

    try
    {
    Log.Information($"Attempting to download ID {objectHandle} to {localFile}");

        // try downloading just using path
        bool success = mtpDevice.ImportFile(objectHandle, localFile);
        if (!success)
        {
            // try it with a / on the end of the path
            localFile += '/';
            Log.Information($"Attempting to download ID {file.DownloadManagerId} to {localFile}");
            success = mtpDevice.ImportFile(objectHandle, localFile);
        }
        if (!success)
        {
            // try it with the filename on the end of the path as well
            localFile += file.FileNameOnSdCard;
            Log.Information($"Attempting to download ID {file.DownloadManagerId} to {localFile}");
            success = mtpDevice.ImportFile(objectHandle, localFile);
        }


        if (!success)
        {
            throw new Exception($"mtpDevice.ImportFile failed for {file.FileNameOnSdCard}");
        }

        // do stuff here to handle success
    }
    catch (Exception ex) when (ex is OperationCanceledException || ex is TaskCanceledException)
    {
        // do some other stuff here in the database

        //rethrow the exception so it can be handled further up the chain.
        throw;
    }

    return receivedBytes;
}
公共异步任务下载FileAsync(MyFileClass文件,字符串目标)
{
int receivedBytes=0;
int objectHandle=file.MTPHandle;
connectedDevice=等待GetAttachedDevice();
如果(connectedDevice==null | |!UsbManager.HasPermission(连接