標籤:else 對象 lse byte 產品 模式 equal and 沒有
Android USB 開發詳解
先附上 Android USB 官方文檔
Android通過兩種模式支援各種 USB 外設和 Android USB 附件(實現Android附件協議的硬體):USB附件和USB主機。USB開發需 Android 3.1(API層級12)以上。由於本人工作中只用到了主機模式,所以本文的側重點在主機模式開發。
- Android USB 開發詳解
- 調試
- 一、AndroidManifest 檔案設定
- 二、USB 裝置的串連和使用
- 1.Android 中的 USB
- 2.USB 裝置的插入
- 3.擷取 UsbManager
- 4.擷取 USB 裝置列表
- 5.擷取特定的裝置
- 6.申請 USB 裝置使用許可權
- 7.通訊
- 其他
調試
在使用 USB 串連裝置調試的時候,USB 外設將不能串連至裝置,可以使用 WIFI 的方式串連調試,settings -> plugin -> WiFi ADB 外掛程式好幾個,選個適合自己的就 OK。
或者…我這裡正好有一篇Android 模擬器串連 USB 裝置喜歡點個贊哈!
一、AndroidManifest 檔案設定
- uses-feature 申明這個軟體需要使用 USB 功能,申明這個 Google Play 會把不滿足的裝置過濾掉,一般用 USB 的都是定製開發,忽略就行
<uses-feature android:name="android.hardware.usb.host"/>
- 將應用程式的最低SDK設定為API層級12或更高,早期 API 沒有。
- 如果你希望你的應用程式串連指定的 USB 裝置時被通知,需指定 和 元素對用於 android.hardware.usb.action.USB_DEVICE_ATTACHED。該 元素指向聲明識別有關您要檢測的裝置資訊的外部XML資源檔。
<activity android:name=".MainActivity" android:screenOrientation="landscape"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <!-- 如果這裡是啟動 Activity 的話,點擊 USB 接入的彈窗會啟動該頁面 --> <category android:name="android.intent.category.LAUNCHER" /> <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" /> </activity>
- 在XML資源檔中,聲明要過濾的USB裝置的元素。以下列表描述了屬性 。通常,如果要過濾特定裝置並使用類,子類和協議(如果要過濾一組USB裝置(如大量儲存裝置或數位相機)),請使用供應商(vendor-id)和產品(product-id)ID,在開發中這些過濾ID一般可以在文檔中找到,或者自己連上看也行。你可以指定部分或全部這些屬性。
將資源檔儲存在res/xml/目錄中。資源檔名(不帶.xml副檔名)必須與您在元素中指定的檔案名稱相同 。對於XML資源檔格式的 例子如下:
<?xml version="1.0" encoding="utf-8"?><resources> <usb-device class="255" product-id="5678" protocol="1 " subclass="66" vendor-id="1234" /></resources>
配置好資訊清單檔後當使用者串連與您的裝置過濾器匹配的裝置時,系統會向他們顯示一個對話方塊,詢問他們是否要啟動您的應用程式。如果使用者接受,則應用程式將自動具有訪問裝置的許可權,直到裝置中斷連線。如果給了預設,那麼這個 USB 裝置插入後會自動啟動這個 Activity
二、USB 裝置的串連和使用
在資訊清單檔中配置好以後我們直接進入 Java 代碼環節
1.Android 中的 USB
Android 3.1(API層級12)以上原生提供了 USB 開發的 API,在android.hardware.usb包下提供了開發的相關類。
Class |
說明 |
UsbManager |
獲得 USB 管理器,與串連的 USB 裝置通訊。 |
UsbDevice |
USB 裝置的抽象,每個UsbDevice 都代表一個 USB 裝置。 |
UsbInterface |
定義了裝置的功能集,一個 UsbDevice 可能包含一個或多個UsbInterface,每個 Interface 都是獨立的。 |
UsbEndpoint |
UsbEndpoint 是 interface 的通訊通道。 |
UsbDeviceConnection |
host 與 device 建立的串連,並在 endpoint 傳輸資料。 |
UsbRequest |
USB 請求包。 |
UsbConstants |
USB 常量的定義 |
2.USB 裝置的插入
Android 系統中,USB 裝置的插入和拔出是以系統廣播的形式發送的,我們只要註冊監聽這個廣播就好
public class USBReceiver extends BroadcastReceiver { public static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { // 擷取許可權結果的廣播 synchronized (this) { UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { //call method to set up device communication if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { Log.e("USBReceiver", "擷取許可權成功:" + device.getDeviceName()); } else { Log.e("USBReceiver", "擷取許可權失敗:" + device.getDeviceName()); } } } }else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { // 有新的裝置插入了,在這裡一般會判斷這個裝置是不是我們想要的,是的話就去請求許可權 } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { // 有裝置拔出了 } }}
3.擷取 UsbManager
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
4.擷取 USB 裝置列表
public List<UsbDevice> getDeviceList() { HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); List<UsbDevice> usbDevices = new ArrayList<>(); while (deviceIterator.hasNext()) { UsbDevice device = deviceIterator.next(); usbDevices.add(device); Log.e("USBUtil", "getDeviceList: " + device.getDeviceName()); } return usbDevices; }
5.擷取特定的裝置
/** * mVendorId=1137,mProductId=85 佳博 3150T 標籤印表機 * * @param vendorId 廠商ID * @param productId 產品ID * @return device */ public UsbDevice getUsbDevice(int vendorId, int productId) { HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while (deviceIterator.hasNext()) { UsbDevice device = deviceIterator.next(); if (device.getVendorId() == vendorId && device.getProductId() == productId) { Log.e("USBUtil", "getDeviceList: " + device.getDeviceName()); return device; } } Toast.makeText(context, "沒有對應的裝置", Toast.LENGTH_SHORT).show(); return null; }
6.申請 USB 裝置使用許可權
安卓系統對 USB 裝置的使用需要得到相應的許可權,這個許可權要使用者手動授予,或插入裝置時應用到你的應用中。在使用 USB 裝置前首先我們要確認一下上一節中的device是否已經獲得許可權,如果沒有就要主動申請許可權:
/** * 判斷對應 USB 裝置是否有許可權 */ public boolean hasPermission(UsbDevice device) { return usbManager.hasPermission(device); } /** * 請求擷取指定 USB 裝置的許可權 */ public void requestPermission(UsbDevice device) { if (device != null) { if (usbManager.hasPermission(device)) { Toast.makeText(context, "已經擷取到許可權", Toast.LENGTH_SHORT).show(); } else { if (mPermissionIntent != null) { usbManager.requestPermission(device, mPermissionIntent); Toast.makeText(context, "請求USB許可權", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "請註冊USB廣播", Toast.LENGTH_LONG).show(); } } } }
註冊廣播:
public void registerReceiver(Activity context) { mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); context.registerReceiver(usbReceiver, filter); }
7.通訊
與 USB 裝置的通訊可以是同步的也可以是非同步。無論哪種情況,你都應該建立一個新線程來執行所有資料轉送,避免阻塞UI線程。
第一步,開啟通訊連接埠
public boolean openPort(UsbDevice device) { //擷取裝置介面,一般只有一個,多個的自己研究去 usbInterface = device.getInterface(0); // 判斷是否有許可權 if (hasPermission(device)) { // 開啟裝置,擷取 UsbDeviceConnection 對象,串連裝置,用於後面的通訊 usbConnection = usbManager.openDevice(device); if (usbConnection == null) { return false; } if (usbConnection.claimInterface(usbInterface, true)) { Toast.makeText(Utils.getContext(), "找到 USB 裝置介面", Toast.LENGTH_SHORT).show(); } else { usbConnection.close(); Toast.makeText(Utils.getContext(), "沒有找到 USB 裝置介面", Toast.LENGTH_SHORT).show(); return false; } } else { Toast.makeText(Utils.getContext(), "沒有 USB 許可權", Toast.LENGTH_SHORT).show(); return false; } //擷取介面上的兩個端點,分別對應 OUT 和 IN for (int i = 0; i < usbInterface.getEndpointCount(); ++i) { UsbEndpoint end = usbInterface.getEndpoint(i); if (end.getDirection() == UsbConstants.USB_DIR_IN) { usbEndpointIn = end; } else { usbEndpointOut = end; } } return true; }
第二步,發送資料
usbConnection.bulkTransfer(usbEndpointOut, bytes, bytes.length, 500);
其他
剩餘的 API 我會在項目不斷完善的同時更新上來
附:demo 傳送門
Android USB 開發詳解