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设备的访问权限
总结
你原来的代码错误点在于:
- 申请了和读取USB设备完全无关的系统权限
LOCATION_HARDWARE - 错误地用了仅适用于危险权限的
requestPermissions()方法来申请系统权限
换成上面的USB权限请求流程,就能解决你的问题,顺利实现读取USB设备的需求了。
内容的提问来源于stack exchange,提问作者Márcio Rossato
相关产品推荐
相关产品推荐

