You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Delphi 10.4访问Android TV的USB大容量存储?

Delphi 10.4 Android TV USB大容量存储读写解决方案

一、正确的USB存储访问路径

  • Android从API 21开始,USB大容量存储的挂载路径不再是固定的/mnt/usbxxx这类硬编码路径,不同设备的挂载点可能存在差异,且API 29+系统直接限制了对这类路径的直接访问。
  • 推荐采用Storage Access Framework (SAF) 访问:无需硬编码路径,通过系统文件选择器让用户选择USB存储的根目录或目标文件,再通过返回的Uri进行文件操作,这种方式能适配所有符合规范的Android设备(包括TV端),且兼容高版本系统。
  • 若需在API 28及以下获取挂载路径,可读取/proc/mounts文件解析挂载信息提取USB设备挂载点,但该方式在API 29+被限制,不推荐长期使用。

二、权限获取与版本适配

1. 配置清单权限(AndroidManifest.xml)

在Delphi的Project -> Options -> Application -> Permission中勾选对应权限,同时手动补充USB相关配置:

  • API 23-28需勾选:
    • READ_EXTERNAL_STORAGE
    • WRITE_EXTERNAL_STORAGE
  • API 29+无需上述存储权限,但需在Manifest的application节点添加:
    <application android:requestLegacyExternalStorage="true" ...>
    
  • 补充USB设备权限:
    <uses-feature android:name="android.hardware.usb.host" android:required="false" />
    <uses-permission android:name="android.permission.USB_PERMISSION" />
    

2. 动态申请权限(API 23+)

在Delphi代码中动态申请存储权限:

uses
  Androidapi.Helpers, Androidapi.JNI.JavaTypes, Androidapi.JNI.Os;

procedure RequestStoragePermissions;
var
  Permissions: TJavaObjectArray<JString>;
begin
  if TJBuild_VERSION.JavaClass.SDK_INT >= 23 then
  begin
    Permissions := TJavaObjectArray<JString>.Create(2);
    Permissions.Items[0] := StringToJString('android.permission.READ_EXTERNAL_STORAGE');
    Permissions.Items[1] := StringToJString('android.permission.WRITE_EXTERNAL_STORAGE');
    TAndroidHelper.Activity.requestPermissions(Permissions, 100);
  end;
end;

需重写Activity的onRequestPermissionsResult方法处理权限申请结果(需自定义ActivityWrapper)。

3. 使用SAF访问USB存储(推荐适配方案)

调用系统文件选择器让用户选择USB存储:

uses
  Androidapi.Helpers, Androidapi.JNI.Content, Androidapi.JNI.GraphicsContentViewText;

procedure OpenSAFDialog;
var
  Intent: JIntent;
begin
  Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_OPEN_DOCUMENT_TREE);
  TAndroidHelper.Activity.startActivityForResult(Intent, 200);
end;

在onActivityResult中处理返回的Uri并操作文件,同时持久化权限:

procedure HandleSAFResult(RequestCode, ResultCode: Integer; Data: JIntent);
var
  Uri: JUri;
  InputStream: JInputStream;
  Reader: JInputStreamReader;
  Buffer: JCharArray;
  Content: string;
begin
  if (RequestCode = 200) and (ResultCode = TJActivity.JavaClass.RESULT_OK) and Assigned(Data) then
  begin
    Uri := Data.getData;
    // 持久化Uri权限,重启应用后仍可访问
    TAndroidHelper.Activity.getContentResolver.takePersistableUriPermission(Uri,
      TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION or TJIntent.JavaClass.FLAG_GRANT_WRITE_URI_PERMISSION);
    
    // 读取文件示例
    InputStream := TAndroidHelper.Activity.getContentResolver.openInputStream(Uri);
    try
      Reader := TJInputStreamReader.JavaClass.init(InputStream);
      Buffer := TJCharArray.JavaClass.init(1024);
      Reader.read(Buffer);
      Content := JStringToString(TJString.JavaClass.init(Buffer));
    finally
      InputStream.close;
    end;
  end;
end;

4. Android TV特殊适配

  • Android TV支持ACTION_OPEN_DOCUMENT_TREE Intent,用户可通过遥控器导航选择USB存储设备。
  • 若需自动检测USB设备,可通过UsbManager枚举设备,但仍需结合SAF操作文件,同时处理USB权限请求。

内容的提问来源于stack exchange,提问作者tedb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:45:54