在 AndroidN 上浏览可移动 USB OTG,存储访问框架真的是唯一的方法吗?

Browsing a removable USB OTG on Android N, is Storage Access Framework really the only way?

我们有一个自定义 android 设备,它是 运行 牛轧糖,并包装在供应商特定的启动器中。我正在尝试使用 API 23 为所述设备实施文件管理器。这是因为我读过从 Android M 开始的唯一方法是使用 SAF。

我正在开发的设备有 3 个 USB 端口,当 USB 驱动器连接到这些端口时,应用程序会检测自定义文件并将其从 USB 传输到设备的内部存储(设备没有 SD 卡)。由于直接访问可挂载存储是不可行的 Android N 我正在考虑使用 SAF 进行此操作。

我已经通过 USB 管理器和 USB 主机实现了 USB 分离和连接的广播接收器,并且可以成功检测到 USB 何时插入或未插入,以徒劳地尝试与设备通信并尝试提取文件。但我也读到 Android USB 框架仅用于发送小字节以与 USB 连接设备(如 Arduino 板等)进行通信。

我现在正在尝试实现一个 USB 文档提供程序来浏览 USB。由于我不能直接根据这个访问文件。

我正在关注此 source code 以实现我的 USB 文档提供程序。

我目前正在实施 class 的 queryRoots 和 queryChildDocuments 部分。 Cursor 的大部分字段我都明白要放什么,但是 COLUMN_DOCUMENT_ID 的部分让我很困惑(对于这两种方法)。

由于该设备是可移动 USB,我不知道该将什么作为该列的值

这是我的 queryRoots 方法实现:

@Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
    final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
    final MatrixCursor.RowBuilder row = result.newRow();
    row.add(Root.COLUMN_ROOT_ID, BuildConfig.DOCUMENTS_AUTHORITY);
    row.add(Root.COLUMN_ICON, R.drawable.ic_menu_manage);
    row.add(Root.COLUMN_TITLE, "Root Title");
    row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_RECENTS);
    row.add(Root.COLUMN_SUMMARY, "USB Reader");
    row.add(Root.COLUMN_DOCUMENT_ID, "/");
    row.add(Root.COLUMN_MIME_TYPES, "*/*");

    Uri rootsUri = DocumentsContract.buildRootsUri(BuildConfig.DOCUMENTS_AUTHORITY);
    getContext().getContentResolver().notifyChange(rootsUri, null);
    return result;
}

如果我错了请纠正我,但由于我要导出的文件不是典型的 mime 类型文件,我已将 COLUMN_MIME_TYPES 设置为

*/*

我的 queryChildDocuments 方法:

   @Override
    public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
                                      String sortOrder) throws FileNotFoundException {
        final MatrixCursor result = new
                MatrixCursor(resolveDocumentProjection(projection));
        String parentDocumenPath = getContext().getFilesDir().getPath() + "/" + parentDocumentId;
        File dir = new File(parentDocumenPath);
                    for (File file : dir.listFiles()) {
            String documentId = parentDocumentId + "/" + file.getName();
            includeFile(result, documentId);
        }

        return result;
    }

除此之外,我的实现没有其他特别之处。

然后我打算使用以下代码通过导航菜单打开文档提供程序:

if (id == R.id.nav_file_explorer) {
            Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            startActivityForResult(intent, 1);
}

自定义文档提供程序显示在列表中,但未列出 U 盘。除此之外,当我单击文档提供程序以从我指定的根目录打开时,它 returns 什么都没有。我做错了什么?

在 Android M 及更高版本中,无需 SAF 即可访问可移动存储数据。您只需要进行低级编码。如此 project 所示。 我们在我们的项目中可能会选择实施与此链接项目类似的东西,因为到目前为止 SAF 被证明是不可靠的。

该项目还包括 SAF 的实现,但以低级 USB 读取库为基础。