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

Delphi Android调用requestPermissions报错:方法未找到

解决Delphi中申请LOCATION_HARDWARE权限出现“invoke method not found”的问题

首先咱们得先理清核心问题:你不仅用错了权限,还选错了权限申请的方式。

为什么会报“invoke method not found”?

LOCATION_HARDWARE是Android的系统级权限,它不属于需要动态申请的「危险权限」范畴。requestPermissions()方法只适用于Android定义的危险权限(比如位置、存储、相机这类涉及用户隐私的权限),对于系统权限,这个方法根本不适用——强行调用就会触发“方法未找到”的异常,因为系统没有为这类权限开放这个调用入口。

而且更关键的是:这个权限和你要实现的「读取USB设备」需求完全不相关,完全没必要去申请它。

读取USB设备的正确操作流程

要在Android上读取USB设备,你需要的是USB Host相关的权限和配置,具体步骤如下:

1. 配置AndroidManifest.xml

首先在你的项目Manifest文件里添加以下内容:

<!-- 声明App需要USB Host功能 -->
<uses-feature android:name="android.hardware.usb.host" android:required="true" />
<!-- 声明USB设备访问权限 -->
<uses-permission android:name="android.permission.USB_PERMISSION" />

2. 在Delphi中动态请求USB设备权限

USB设备的权限请求不是通过requestPermissions(),而是通过发送广播请求+监听权限结果的方式实现。这里给你一个完整的实现示例:

uses
  Androidapi.JNI.App, Androidapi.JNI.OS, Androidapi.JNI.Usb, Androidapi.Helpers,
  Androidapi.JNI.JavaTypes;

type
  TUSBReceiver = class(TJavaLocal, JBroadcastReceiver)
  public
    procedure onReceive(context: JContext; intent: JIntent); cdecl;
  end;

var
  USBReceiver: TUSBReceiver;
  USBFilter: JIntentFilter;

procedure TUSBReceiver.onReceive(context: JContext; intent: JIntent);
var
  USBManager: JUsbManager;
  TargetDevice: JUsbDevice;
begin
  if intent.getAction.Equals(StringToJString(TJUsbManager.JavaClass.ACTION_USB_PERMISSION)) then
  begin
    TargetDevice := TJUsbDevice.Wrap(intent.getParcelableExtra(TJUsbManager.JavaClass.EXTRA_DEVICE));
    if intent.getBooleanExtra(TJUsbManager.JavaClass.EXTRA_PERMISSION_GRANTED, False) then
    begin
      // 权限已授予,这里可以开始操作目标USB设备
      ShowMessage('USB权限已授予,可操作设备:' + JStringToString(TargetDevice.getDeviceName));
    end
    else
    begin
      ShowMessage('USB权限被拒绝,无法操作设备');
    end;
  end;
end;

procedure RequestTargetUSBPermission;
var
  USBManager: JUsbManager;
  DeviceList: JHashMap;
  DeviceIter: JIterator;
  TargetDevice: JUsbDevice;
  PermissionIntent: JPendingIntent;
begin
  USBManager := TJUsbManager.Wrap(TAndroidHelper.Context.getSystemService(TJContext.JavaClass.USB_SERVICE));
  // 获取当前已连接的USB设备列表
  DeviceList := USBManager.getDeviceList;
  DeviceIter := DeviceList.values.iterator;
  
  if DeviceIter.hasNext then
  begin
    // 示例取第一个连接的设备,实际开发中建议通过getVendorId()/getProductId()筛选特定设备
    TargetDevice := TJUsbDevice.Wrap(DeviceIter.next);
    // 创建权限请求的PendingIntent
    PermissionIntent := JPendingIntent.Wrap(PendingIntent.getBroadcast(TAndroidHelper.Context, 0,
      TJIntent.JavaClass.init(StringToJString(TJUsbManager.JavaClass.ACTION_USB_PERMISSION)), 0));
    // 注册广播接收器
    USBFilter := TJIntentFilter.JavaClass.init(StringToJString(TJUsbManager.JavaClass.ACTION_USB_PERMISSION));
    TAndroidHelper.Context.registerReceiver(USBReceiver, USBFilter);
    // 向系统请求该USB设备的访问权限
    USBManager.requestPermission(TargetDevice, PermissionIntent);
  end
  else
  begin
    ShowMessage('未检测到已连接的USB设备');
  end;
end;

// 在窗体创建时初始化广播接收器
procedure TForm1.FormCreate(Sender: TObject);
begin
  USBReceiver := TUSBReceiver.Create;
end;

// 在窗体销毁时注销广播接收器,避免内存泄漏
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Assigned(USBReceiver) then
  begin
    TAndroidHelper.Context.unregisterReceiver(USBReceiver);
    USBReceiver.Free;
  end;
end;

3. 关键注意事项

  • 实际开发中不要直接取第一个USB设备,建议通过设备的厂商ID(getVendorId())和产品ID(getProductId())筛选你需要操作的目标设备
  • 广播接收器必须在使用前注册,使用完成后及时注销,避免内存泄漏
  • USB_PERMISSION只需要在Manifest中声明,不需要通过requestPermissions()申请,而是通过requestPermission()方法向用户请求特定USB设备的访问权限

总结

你原来的代码错误点在于:

  1. 申请了和读取USB设备完全无关的系统权限LOCATION_HARDWARE
  2. 错误地用了仅适用于危险权限的requestPermissions()方法来申请系统权限

换成上面的USB权限请求流程,就能解决你的问题,顺利实现读取USB设备的需求了。

内容的提问来源于stack exchange,提问作者Márcio Rossato

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:01:05