【废话一段】
      前段时间,我的小组开发一个Android主机的系统,这个系统需要外接USB的指纹机、读卡器、U盘,硬件已经有了,主机是一个开发板接口丰富,并且支持Android USB Host模式,外设自然不用说。
     但是碰到了一个问题,驱动!本来这个项目是源于Windows的,外设全部是针对Windows而开发的,如果要用专门的驱动,那么开发Android本身就需要复杂的过程。后来经过硬件工程师的改造,我们将USB换成了HID模式,减轻开发难度。
     经过一段时间搜索网上资料,关于Android USB Host的资料可以说非常少,不是少数,而是几乎雷同。我是百度+google,更换无数中英文关键字,最后我如愿完成自己的项目,和HID设备正常通讯了,并且识别了U盘。对于网络上中文资料的少而单一的现状,我决定自己写一篇文章,让同行们少走弯路。
    我的代码参考了来自“开源中国”部分资料,如果有解决不了的,可以在那里查询。
【基础功能】
    注意:本文的步骤,可能需要你具备Root的权限,否则有些操作可能会无法完成。强烈建议你先root设备。
    步骤一:你必须确定你的Android设备支持USB Host,具体支持与否请参考自己的说明书。确定了才有必要看本文章。
   步骤二:确认Android是否已经开放了USB访问权限,这一步非常重要。操作是:进入系统,找到目录“/system/etc/permissions”,可以用ES或者RE文件管理器进行操作。查看该目录下,是否有一个文件"android.hardware.usb.host.xml",如果没有,则自己创建一个同名文件,内容如下:

      

然后,拷贝到“/system/etc/permissions”目录下。(可以用Eclipse的DDMS帮忙,push进去)
   步骤三:其实呢,有了步骤三基本也就可以了,但是我自己也不是很确定,于是有了步骤四。继续检查目录“/system/etc/permissions”下,将其中的“handheld_core_hardware.xml (手机)或者 tablet_core_hardware.xml(平板)”拖出来,打开文件,看看结点下面有没有下面这个结点:

如果没有,就自己补上一行,保存,并push进去替换原来的文件。比如我的文件内容是:

<?xml version="1.0" encoding="utf-8"?>                                            

步骤四:非常重要,就是重启你的Android设备
【详细代码】
       事实上,做完上面的步骤,剩下的代码就非常地简单了,我之前搜索到的基本就是这些内容了。


      强烈建议大家参考SDK文档下面的google示例:ADBTest,他写的类非常有用,我下面的内容可以忽略过去。我后来就是参考了ADBTest之后,改装成一个通用类,可以让我的主机接多个USB-HID外设,实现同时异步收发。当然,你通过我下面的代码应该也能实现举一反三。


   先看看AndroidManifest.xml文件,为了写这篇文章,我特意做了大量注释:

                                                                                                                                                                                                                                                                               

注意看:上面的文件提到了一个文件“device_filter”,他也是你能否成功的一个重要文件”device_filter.xml“,这个文件必须自己创建:
         在项目工程中的res结点创建一个新的文件夹叫”xml“(不会操作????右键啊!),然后再在xml文件夹下创建一个xml,文件名就叫做“device_filter",内容如下:

<?xml version="1.0" encoding="utf-8"?>                                

     我必须讲清楚,上面的设备是我测试用的,和大家手上的设备根本不一样,请自行查看USB设备VID\PID然后转换

         我们再来看看布局文件activity_main.xml,这个布局是测试用的,非常随意,请大家根据自己的项目布局测试,不一定要用我这个,也不要问我为什么要这么设计布局,哥我只是玩玩而已,不要那么认真嘛~~~~~

                            

       特别是上面提到的一些按钮上的text,大家发挥自己想象力,我不想再贴上values下面的那些文件了。其中有些按钮根本没有用到。我是调试用的。
      
       这回,我们进入了直接的代码模块:MainActivity.java

package com.example.usbmanager;   import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;   import android.os.Bundle;import android.R.string;import android.app.Activity;import android.app.PendingIntent;import android.content.BroadcastReceiver;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.content.IntentFilter;import android.database.DataSetObserver;import android.hardware.usb.UsbConstants;import android.hardware.usb.UsbDevice;import android.hardware.usb.UsbDeviceConnection;import android.hardware.usb.UsbEndpoint;import android.hardware.usb.UsbInterface;import android.hardware.usb.UsbManager;import android.util.Log;import android.view.View.OnClickListener;import android.view.Gravity;import android.view.Menu;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.EditText;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.Toast;   public class MainActivity extends Activity {    private static final String TAG = "MainActivity";   //记录标识    private Button btsend;      //发送按钮    private UsbManager manager;   //USB管理器    private UsbDevice mUsbDevice;  //找到的USB设备    private ListView lsv1;         //显示USB信息的    private UsbInterface mInterface;       private UsbDeviceConnection mDeviceConnection;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btsend = (Button) findViewById(R.id.btsend);           btsend.setOnClickListener(btsendListener);           lsv1 = (ListView) findViewById(R.id.lsv1);        // 获取USB设备        manager = (UsbManager) getSystemService(Context.USB_SERVICE);        if (manager == null) {            return;        } else {            Log.i(TAG, "usb设备:" + String.valueOf(manager.toString()));        }        HashMap deviceList = manager.getDeviceList();        Log.i(TAG, "usb设备:" + String.valueOf(deviceList.size()));        Iterator deviceIterator = deviceList.values().iterator();        ArrayList USBDeviceList = new ArrayList(); // 存放USB设备的数量        while (deviceIterator.hasNext()) {            UsbDevice device = deviceIterator.next();               USBDeviceList.add(String.valueOf(device.getVendorId()));            USBDeviceList.add(String.valueOf(device.getProductId()));               // 在这里添加处理设备的代码            if (device.getVendorId() == 1155 && device.getProductId() == 22352) {                mUsbDevice = device;                Log.i(TAG, "找到设备");            }        }        // 创建一个ArrayAdapter        lsv1.setAdapter(new ArrayAdapter(this,                android.R.layout.simple_list_item_1, USBDeviceList));        findIntfAndEpt();               }       private byte[] Sendbytes;    //发送信息字节    private byte[] Receiveytes;  //接收信息字节    private OnClickListener btsendListener = new OnClickListener() {        int ret = -100;        @Override        public void onClick(View v) {            /*             * 请注意,本模块通信的内容使用的协议是HID读卡器协议,不会和大家手上的设备一样             * 请大家在测试时参考自己手上的设备资料,严格按照HID标准执行发送和接收数据             * 我的范例使用的设备是广州微云电子的WY-M1RW-01非接触式读卡器,outputreport是64,因此我发送的字节长度是64             * 我发送的字节内容是要求读卡器蜂鸣器响两短一长             */            String testString = "90000CB20301F401F401F401F407D447FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";            Sendbytes = clsPublic.HexString2Bytes(testString);                           // 1,发送准备命令            ret = mDeviceConnection.bulkTransfer(epOut, Sendbytes, Sendbytes.length, 5000);             Log.i(TAG,"已经发送!");                           // 2,接收发送成功信息            Receiveytes=new byte[64];     //这里的64是设备定义的,不是我随便乱写,大家要根据设备而定            ret = mDeviceConnection.bulkTransfer(epIn, Receiveytes, Receiveytes.length, 10000);            Log.i(TAG,"接收返回值:" + String.valueOf(ret));            if(ret != 64) {                DisplayToast("接收返回值"+String.valueOf(ret));                return;            }            else {                //查看返回值                DisplayToast(clsPublic.Bytes2HexString(Receiveytes));                Log.i(TAG,clsPublic.Bytes2HexString(Receiveytes));            }        }    };       // 显示提示的函数,这样可以省事,哈哈    public void DisplayToast(CharSequence str) {        Toast toast = Toast.makeText(this, str, Toast.LENGTH_LONG);        // 设置Toast显示的位置        toast.setGravity(Gravity.TOP, 0, 200);        // 显示Toast        toast.show();    }           // 寻找接口和分配结点    private void findIntfAndEpt() {        if (mUsbDevice == null) {            Log.i(TAG,"没有找到设备");            return;        }        for (int i = 0; i < mUsbDevice.getInterfaceCount();) {            // 获取设备接口,一般都是一个接口,你可以打印getInterfaceCount()方法查看接            // 口的个数,在这个接口上有两个端点,OUT 和 IN             UsbInterface intf = mUsbDevice.getInterface(i);            Log.d(TAG, i + " " + intf);            mInterface = intf;            break;        }           if (mInterface != null) {            UsbDeviceConnection connection = null;            // 判断是否有权限            if(manager.hasPermission(mUsbDevice)) {                // 打开设备,获取 UsbDeviceConnection 对象,连接设备,用于后面的通讯                connection = manager.openDevice(mUsbDevice);                 if (connection == null) {                    return;                }                if (connection.claimInterface(mInterface, true)) {                    Log.i(TAG,"找到接口");                    mDeviceConnection = connection;                    //用UsbDeviceConnection 与 UsbInterface 进行端点设置和通讯                    getEndpoint(mDeviceConnection,mInterface);                } else {                    connection.close();                }            } else {                Log.i(TAG,"没有权限");            }        }        else {            Log.i(TAG,"没有找到接口");        }    }                  private UsbEndpoint epOut;    private UsbEndpoint epIn;    //用UsbDeviceConnection 与 UsbInterface 进行端点设置和通讯    private void getEndpoint(UsbDeviceConnection connection, UsbInterface intf) {        if (intf.getEndpoint(1) != null) {            epOut = intf.getEndpoint(1);        }        if (intf.getEndpoint(0) != null) {            epIn = intf.getEndpoint(0);        }    }              }

         
【调试】

      如果一切顺利的话,你接上你的USB设备后,android会弹出一个访问硬件的权限提示框,你要点击“确定“。

      调试的内容应该我不需要讲了,Eclipse会帮你搞定的。

更多相关文章

  1. 如何在 iOS、Android、macOS、Windows 之间快速文件互传?
  2. Android资源文件夹及资源文件的详细介绍
  3. Android Layout布局文件里的android:layout_height等属性为什么.
  4. 在Android设备上搭建Web服务器的方法
  5. Android多语言支持以及各国语言Values文件夹命名规则
  6. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流
  7. android之播放多媒体文件一(播放音频)

随机推荐

  1. 阿里云云服务器mysql密码找回的方法
  2. 关于MySQL中的查询开销查看方法详解
  3. MySQL存储结构用法案例分析
  4. Mysql实现增量恢复的方法详解
  5. mysql中find_in_set()函数的使用及in()用
  6. Mysql 相邻两行记录某列的差值方法
  7. Mysql Binlog数据查看的方法详解
  8. MySQL中有哪些情况下数据库索引会失效详
  9. Ubuntu18.04 安装mysql8.0.11的图文教程
  10. mysql保存微信昵称特殊字符的方法