开发Android应用接收Yamaha YDP-113 MIDI事件遇FEATURE_MIDI检测失败求助
我之前也遇到过类似的情况!很多Android设备(尤其是老机型或者定制ROM)虽然硬件支持USB MIDI,但系统并没有正确声明FEATURE_MIDI,这就是你调用hasSystemFeature()返回false的原因。而那些第三方APP比如你提到的USB Midi Keyboard,其实是绕过了系统的feature检查,直接用USB Host API来和电钢琴通信的。下面是具体的实现思路:
1. 直接使用Android USB Host API访问设备
这是核心方案,不需要依赖系统的FEATURE_MIDI声明,只要你的设备支持USB Host(Android 3.1及以上版本基本都支持)就能实现:
步骤1:声明权限与配置
在AndroidManifest.xml中添加USB Host相关权限和广播接收器:<uses-feature android:name="android.hardware.usb.host" android:required="false" /> <uses-permission android:name="android.permission.USB_PERMISSION" /> <receiver android:name=".UsbMidiReceiver"> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> </receiver>然后在
res/xml/device_filter.xml中过滤Yamaha YDP-113的USB VID(厂商ID)和PID(产品ID),Yamaha的VID一般是0x0499,YDP-113的PID可以通过USB调试日志或者第三方工具获取:<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1177" product-id="XXXX" /> <!-- 替换成YDP-113的实际PID --> </resources>步骤2:处理USB设备连接与权限
在广播接收器中接收设备插入事件,请求用户授权访问设备,之后建立UsbDeviceConnection:public class UsbMidiReceiver extends BroadcastReceiver { private static final String ACTION_USB_PERMISSION = "com.your.package.USB_PERMISSION"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (this) { UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if (device != null) { // 建立连接并处理MIDI数据 setupMidiConnection(context, device); } } } } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0); usbManager.requestPermission(device, permissionIntent); } } }步骤3:解析USB MIDI数据包
USB MIDI的数据包格式和标准MIDI消息不同,你需要按照USB MIDI规范(USB Device Class Definition for MIDI Devices)来解析接收到的字节流,提取出实际的MIDI事件(比如琴键按下/松开的消息)。
2. 利用第三方库简化开发
如果不想自己写底层的USB MIDI解析逻辑,可以用现成的开源库,比如一些专门处理Android USB MIDI的库,它们已经封装了设备枚举、权限请求、MIDI消息解析等逻辑,你只需要关注业务层的处理(比如显示琴键、播放声音)。很多第三方APP都是基于这类库开发的。
3. 绕过系统的FEATURE_MIDI检查
不要用PackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)来判断是否支持MIDI功能,而是直接枚举USB设备,检查是否存在目标MIDI设备。因为系统的feature声明不一定准确,直接检测硬件设备才是最可靠的方式。
注意事项
- 确保设备支持USB Host(大部分Android 3.1+设备都支持,但有些平板/手机可能需要OTG线连接电钢琴)
- 不同型号的Yamaha电钢琴PID可能不同,你可以通过USB调试日志获取设备的VID和PID
- 要处理设备插拔的情况,比如设备断开时及时释放
UsbDeviceConnection资源,避免内存泄漏
内容的提问来源于stack exchange,提问作者Ed Poor

