美文网首页简书付费文章
Android实现USB连接

Android实现USB连接

作者: 奔跑的佩恩 | 来源:发表于2020-11-30 21:05 被阅读0次

前言

Android开发过程中,我们有时会涉及到USB连接的问题,这里为了方便USB连接的使用,我将相关知识封装成了一个工具类—USBHelper,下面就来介绍下它的使用吧。

今天涉及的内容有:

  1. USB 权限相关设置
  2. USB 设备接口确定
  3. USB 连接流程讲解
  4. USBHelper在 MainActivity 中的使用
  5. 项目结构图
  6. USBHelper 源码

一. USB 权限相关设置

1.1 Android设备上打开 OTG 开关

USB连接涉及到OTG技术,需要我们在带有USB接口的Android设备上打开相关设置。在Android设备上操作如下:

设置 -----> 更多设置 -----> OTG Host    //将OTG Host 开关打开

1.2 在 androidmanifast.xml 中添加 usb 权限

Androidmanifast.xml 中添加如下权限:

    <!-- 声明使用usb -->
    <uses-feature
        android:name="android.hardware.usb.host"
        android:required="true" />

然后在 Androidmanifast.xml 中给要进行USB连接的Activity下添加usb列表文件。假设我们要在MainActivity中进行USB连接,则在 Androidmanifast.xml 中的MainActivity注册下添加以下代码:

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <!-- android设备的信息过滤 -->
            <meta-data
                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/usb" />
        </activity>

主要是在Usb连接相关的Activity注册下添加下面的代码:

            <!-- android设备的信息过滤 -->
            <meta-data
                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/usb" />

这里我们需要在res/下新建xml文件夹,然后在xml文件夹下新建usb.xml文件。即usb.xml路径为:res/xml/usb.xmlusb.xml文件中主要放置的是每个USB接口相关信息(因为一个Android设备可能有多个USB接口),usb.xml文件内容大致如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <usb-device vendor-id="8746" product-id="1"/>
    <usb-device vendor-id="5263" product-id="30329" />
    <usb-device vendor-id="9168" product-id="3200" />
    <usb-device vendor-id="6495" product-id="1" />
    <usb-device vendor-id="2385" product-id="5734" />
</resources>

usb.xml里面基本是放的一个Android设备中所有USB接口的信息了。以上代码中,一个<usb-device ......./>即代表一个USB接口了。通常一个USB接口中有很多信息,包括vendor-id,product-id,DeviceID等信息。这里需要注意的是,同一个usb接口热插拔一次,DeviceID是会变化的,标记一个USB接口的唯一性,我们通常用vendor-idproduct-id

二. USB 设备接口确定

上面我们已经讲过了一个Android设备可能有很多USB接口,而区分一个USB接口的唯一性我们是用vendor-idproduct-id
首先,我们需要获取一个Android设备上所有USB接口信息列表,这里我们可以用USBHelper中的以下方法获得:

    /**
     * 获取设备所有USB接口信息
     *
     * @param context
     * @return 设备无USB接口时,返回 null
     */
    public String getUSBListInfo(Context context)

所有USB接口信息列表我们已经获得了,这样我们就可以把每个USB接口相关信息按上面讲的格式填入res/xml/usb.xml文件中了。那么怎么确定某个USB接口的vendor-id呢?
这里可以使用USBHelper中的以下方法:

        //监听热插拔,找特定usb接口
        mUSBHelper.registerUsb(new USBHelper.OnHotplugListener() {
            @Override
            public void find(UsbDevice device) {
                int vendorId=device.getVendorId();
                int productId=device.getProductId();
                ToastUtil.shortShow("vendorId="+vendorId+"  productId="+productId);
            }

            @Override
            public void permission(boolean status) {
                if(status){
                    LogUtil.i("======USB授权成功======");
                }else{
                    LogUtil.i("======USB授权失败======");
                }
            }
        });

这里其实是监听了USB插拔动作的广播,当我们在给USB接上和拔出的时候,以上方法中的find(UsbDevice device)中便可获得此接口的device,然后我们就可以通过该device获得该USB接口的vendorIdproductId了。

三. USB 连接流程讲解

上面已经讲解了如何配置USB相关设置及找到具体USB接口连接时需要的信息。接下来讲讲USB连接的流程。
USB连接的流程分以下几步:

  1. 找到特定设备UsbDevice(需要根据具体的vendorIdproductId)
  2. 检测USB权限
  3. 找接口对象UsbInterface
  4. usb通信通道
  5. 打开USB设备
  6. usb建立连接
  7. USB数据传输
  8. USB通讯结束后关闭usb

四. USBHelper在 MainActivity 中的使用

下面给出USBHelperMainActivity 中使用代码:

public class MainActivity extends AppCompatActivity{

    private TextView mTv;
    private Button mBtn;

    private USBHelper mUSBHelper;
    private UsbDeviceConnection mUsbDeviceConnection;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        LogUtil.setDebug(true);

        initView();
        initData();
        setListener();
    }

    private void initView() {
        mTv = findViewById(R.id.tv);
        mBtn = findViewById(R.id.btn);
    }

    private void initData() {
        mUSBHelper=new USBHelper(MainActivity.this);
    }

    private void setListener() {
        //监听热插拔,找特定usb接口
        mUSBHelper.registerUsb(new USBHelper.OnHotplugListener() {
            @Override
            public void find(UsbDevice device) {
                int vendorId=device.getVendorId();
                int productId=device.getProductId();
                ToastUtil.shortShow("vendorId="+vendorId+"  productId="+productId);
            }

            @Override
            public void permission(boolean status) {
                if(status){
                    LogUtil.i("======USB授权成功======");
                }else{
                    LogUtil.i("======USB授权失败======");
                }
            }
        });


        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //遍历usb信息
                String info=mUSBHelper.getUSBListInfo(MainActivity.this);
                LogUtil.i("info="+info);

                //建立连接
                Map<String,Object>map=mUSBHelper.connectProcess(6495,1);
                int tag=mUSBHelper.getMapTag(map);
                switch (tag) {
                    case USBHelper.DEVICE_NOT_FOUNT://无usb设备
                        LogUtil.i("无usb设备");
                        break;
                    case USBHelper.NO_PERMISSION://无usb权限
                        LogUtil.i("无usb权限");
//                        //申请权限
//                        mUSBHelper.requestUsbPermission();
                        break;
                    case USBHelper.NO_INTERFACE://查找设备接口失败
                        LogUtil.i("查找设备接口失败");
                        break;
                    case USBHelper.NO_BULKOUT_CHANNEL://查找输出端点失败
                        LogUtil.i("查找输出端点失败");
                        break;
                    case USBHelper.NO_BULKIN_CHANNEL://查找读入端点失败
                        LogUtil.i("查找读入端点失败");
                        break;
                    case USBHelper.NO_CONTROL_CHANNEL://查找控制端点失败
                        LogUtil.i("查找控制端点失败");
                        break;
                    case USBHelper.NO_POINTOUT_CHANNEL://查找中断输出端点失败
                        LogUtil.i("查找中断输出端点失败");
                        break;
                    case USBHelper.NO_POINTIN_CHANNEL://查找中断读入端点失败
                        LogUtil.i("查找中断读入端点失败");
                        break;
                    case USBHelper.NO_OPEN://USB设备打开失败
                        LogUtil.i("USB设备打开失败");
                        break;
                    case USBHelper.CONNECT_FAILED://USB建立连接失败
                        LogUtil.i("USB建立连接失败");
                        break;
                    case USBHelper.CONNECT_SUCCESS://USB建立连接成功
                        LogUtil.i("USB建立连接成功");
                        mUsbDeviceConnection= (UsbDeviceConnection) mUSBHelper.getMapValue(map);
                        break;
                    default:
                        break;
                }

                //发送数据
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //发送数据
                        String message = "我是大神";
                        boolean flag=mUSBHelper.writeMessage(message,mUsbDeviceConnection,null);
                        if(flag){
                            LogUtil.i("发送成功");
                        }else{
                            LogUtil.i("发送失败");
                        }
                    }
                }).start();
            }
        });

    }

    @Override
    protected void onDestroy() {
        //关闭USB
        mUSBHelper.close(mUsbDeviceConnection);
        super.onDestroy();
    }

}

这里需要注意的是, String info=mUSBHelper.getUSBListInfo(MainActivity.this);只是用于罗列一个Android设备上Usb接口信息列表,然后在建立连接:

 Map<String,Object>map=mUSBHelper.connectProcess(6495,1);

中的参数6495,1可以通过插拔USB接口,然后在mUSBHelper.registerUsb(new USBHelper.OnHotplugListener())方法中的find(UsbDevice device)中找到vendorIdproductId
然后USB连接流程已经封装到了:

       /**连接sub流程**/
    public Map<String,Object> connectProcess(int vendorId,int productId)

方法中,大家只要调用此方法就好,若USB无权限,大家可以在case USBHelper.NO_PERMISSION中进行Usb权限申请,就像下面这样:

                    case USBHelper.NO_PERMISSION://无usb权限
                        LogUtil.i("无usb权限");
                        //申请权限
                        mUSBHelper.requestUsbPermission();
                        break;

然后申请结果可以在mUSBHelper.registerUsb(new USBHelper.OnHotplugListener())方法中的permission(boolean status)中看到。
usb建立成功后,可以在case USBHelper.CONNECT_SUCCESS中获得连接对象UsbDeviceConnection,接下来便是新建一个线程向USB接口中写入数据,类似下面这样:

                //发送数据
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //发送数据
                        String message = "我是大神";
                        boolean flag=mUSBHelper.writeMessage(message,mUsbDeviceConnection,null);
                        if(flag){
                            LogUtil.i("发送成功");
                        }else{
                            LogUtil.i("发送失败");
                        }
                    }
                }).start();

写数据的方法已经在USBHelper

    /**写数据**/
    public boolean writeMessage(String message,UsbDeviceConnection connection,String charsetName)

方法中封装好了,大家对照着调用就行。
最后,当我们USB通讯已经用完了,需要在界面销毁时关闭USB,类似下面这样:

    @Override
    protected void onDestroy() {
        //关闭USB
        mUSBHelper.close(mUsbDeviceConnection);
        super.onDestroy();
    }

这样的话,一个完成的USB连接通讯就讲完了。当然,USBHelper中还有很多其他方法,大家有时间也可以看看。

五. 项目结构图

项目结构图.png

六. USBHelper 源码

下面给出USBHelper源码:

相关文章

网友评论

    本文标题:Android实现USB连接

    本文链接:https://www.haomeiwen.com/subject/djedwktx.html