如何用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_STORAGEWRITE_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_TREEIntent,用户可通过遥控器导航选择USB存储设备。 - 若需自动检测USB设备,可通过
UsbManager枚举设备,但仍需结合SAF操作文件,同时处理USB权限请求。
内容的提问来源于stack exchange,提问作者tedb
相关产品推荐
相关产品推荐

