Wenn sich Ihr Android-Gerät im USB-Hostmodus befindet, fungiert es als USB-Host, versorgt den Bus mit und listet verbundene USB-Geräte auf. Der USB-Hostmodus wird ab Android 3.1 unterstützt.
API-Übersicht
Bevor Sie beginnen, ist es wichtig, die Kurse zu kennen, mit denen Sie arbeiten müssen. Die
In der folgenden Tabelle werden die USB-Host-APIs im Paket android.hardware.usb
beschrieben.
Tabelle 1 USB-Host-APIs
Klasse | Beschreibung |
---|---|
UsbManager |
Ermöglicht die Auflistung von verbundenen USB-Geräten und die Kommunikation mit ihnen. |
UsbDevice |
Stellt ein verbundenes USB-Gerät dar und enthält Methoden für den Zugriff auf seine identifizierenden Informationen, Schnittstellen und Endpunkte. |
UsbInterface |
Eine Schnittstelle eines USB-Geräts, die eine Reihe von Funktionen für den . Ein Gerät kann eine oder mehrere Schnittstellen haben, über die es kommunizieren kann. |
UsbEndpoint |
Stellt einen Schnittstellenendpunkt dar, der ein Kommunikationskanal für diese Schnittstelle ist. Eine Schnittstelle kann einen oder mehrere Endpunkte haben und hat in der Regel Eingabe- und Ausgabeendpunkte für Zwei-Wege-Kommunikation mit dem Gerät. |
UsbDeviceConnection |
Stellt eine Verbindung zum Gerät dar, das Daten auf Endpunkten überträgt. Dieser Kurs ermöglicht das synchrone oder asynchrone Senden von Daten. |
UsbRequest |
Stellt eine asynchrone Anfrage zur Kommunikation mit einem Gerät über ein UsbDeviceConnection dar. |
UsbConstants |
Definiert USB-Konstanten, die den Definitionen in linux/usb/ch9.h unter Linux entsprechen. Kernel. |
In den meisten Fällen müssen Sie alle diese Klassen verwenden. UsbRequest
ist nur bei asynchroner Kommunikation erforderlich.
wenn Sie mit einem USB-Gerät kommunizieren. Im Allgemeinen rufen Sie einen UsbManager
ab, um die gewünschte UsbDevice
abzurufen.
Wenn du das Gerät zur Hand hast, musst du die entsprechende UsbInterface
und die UsbEndpoint
dafür suchen.
Schnittstelle für die Kommunikation. Sobald du den richtigen Endpunkt ermittelt hast, kannst du einen UsbDeviceConnection
öffnen, um mit dem USB-Gerät zu kommunizieren.
Anforderungen an Android-Manifest
In der folgenden Liste wird beschrieben, was Sie der Manifestdatei Ihrer Anwendung hinzufügen müssen, bevor Sie mit den USB-Host-APIs:
- Da nicht alle Android-Geräte die USB-Host-APIs unterstützen,
Ein
<uses-feature>
-Element enthalten, das deklariert, dass deine App die Funktionandroid.hardware.usb.host
. - Legen Sie für das SDK der Anwendung mindestens API-Level 12 fest. Die USB-Host-APIs sind nicht die auf früheren API-Ebenen vorhanden sind.
- Wenn Sie möchten, dass Ihre Anwendung über ein angeschlossenes USB-Gerät benachrichtigt wird, geben Sie eine
<intent-filter>
- und<meta-data>
-Element-Paar für dieandroid.hardware.usb.action.USB_DEVICE_ATTACHED
Intent in deiner Hauptaktivität. Die Das<meta-data>
-Element verweist auf eine externe XML-Ressourcendatei, die deklariert, zur Identifizierung des Geräts, das erkannt werden soll.Deklariere in der XML-Ressourcendatei
<usb-device>
-Elemente für das USB- die Sie filtern möchten. In der folgenden Liste werden die Attribute der<usb-device>
Verwenden Sie in der Regel die Anbieter- und Produkt-ID, wenn Sie für ein bestimmtes Gerät und verwenden Sie Klasse, Unterklasse und Protokoll, wenn Sie nach einer Gruppe von USB-Geräten wie Massenspeicher oder Digitalkameras. Sie können „Keine“ oder all diese Attribute. Wenn Sie keine Attribute angeben, stimmen dies nur mit jedem USB-Gerät überein. wenn dies für Ihre Anwendung erforderlich ist:vendor-id
product-id
class
subclass
protocol
(Gerät oder Benutzeroberfläche)
Speichern Sie die Ressourcendatei im Verzeichnis
res/xml/
. Der Name der Ressourcendatei (ohne die Erweiterung „.xml“) muss mit der Datei übereinstimmen, die Sie in den<meta-data>
-Element. Das Format für die XML-Ressourcendatei ist im Beispiel unten.
Beispiele für Manifest- und Ressourcendateien
Das folgende Beispiel zeigt ein Beispielmanifest und die zugehörige Ressourcendatei:
<manifest ...> <uses-feature android:name="android.hardware.usb.host" /> <uses-sdk android:minSdkVersion="12" /> ... <application> <activity ...> ... <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" /> </activity> </application> </manifest>
In diesem Fall sollte die folgende Ressourcendatei
res/xml/device_filter.xml
und gibt an, dass jedes USB-Gerät mit der angegebenen
sollten gefiltert werden:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" /> </resources>
Mit Geräten arbeiten
Wenn Nutzer USB-Geräte an ein Android-Gerät anschließen, kann das Android-System ermitteln, ob Ihre App an dem verbundenen Gerät interessiert ist. In diesem Fall können Sie Kommunikation mit dem Gerät. Dazu muss Ihre Anwendung folgende Voraussetzungen erfüllen:
- Du kannst verbundene USB-Geräte mithilfe eines Intent-Filters erkennen und benachrichtigt werden, wenn der Nutzer ein USB-Gerät verbindet oder die bereits verbundenen USB-Geräte auflistet.
- Bitten Sie den Nutzer um die Berechtigung, eine Verbindung zum USB-Gerät herzustellen, falls Sie das noch nicht getan haben.
- Kommunizieren Sie mit dem USB-Gerät durch Lesen und Schreiben von Daten auf der entsprechenden Schnittstelle Endpunkten.
Gerät finden
Ihre App kann USB-Geräte erkennen, indem sie entweder einen Intent-Filter verwendet, um benachrichtigt zu werden, der Nutzer ein Gerät anschließt oder die bereits verbundenen USB-Geräte auflistet. Bei Verwendung eines Intent-Filter ist nützlich, wenn Sie möchten, dass Ihre Anwendung automatisch ein gewünschtes Gerät. Die Auflistung aller verbundenen USB-Geräte ist nützlich, wenn Sie eine Liste aller verbundenen Geräten oder wenn Ihre App nicht nach einem Intent gefiltert hat.
Intent-Filter verwenden
Damit Ihre App ein bestimmtes USB-Gerät erkennt, können Sie einen Intent-Filter angeben, um
Filter für den Intent android.hardware.usb.action.USB_DEVICE_ATTACHED
. Zusammen mit
Bei diesem Intent-Filter müssen Sie eine Ressourcendatei angeben, in der die Attribute der USB-
z. B. die Produkt- und Anbieter-ID. Wenn Nutzer ein mit Ihrem Gerät verknüpftes Gerät verbinden
Filter anwenden, werden sie in einem Dialogfeld gefragt, ob sie Ihre Anwendung starten möchten.
Wenn die Nutzer zustimmen, hat Ihre Anwendung automatisch die Berechtigung für den Zugriff auf das Gerät, bis die
Gerät nicht verbunden ist.
Das folgende Beispiel zeigt, wie der Intent-Filter deklariert wird:
<activity ...> ... <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" /> </activity>
Das folgende Beispiel zeigt, wie die entsprechende Ressourcendatei deklariert wird, die die Interessante USB-Geräte:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources>
In Ihrer Aktivität können Sie die UsbDevice
abrufen, die für
das angeschlossene Gerät aus:
Kotlin
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
Java
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
Geräte auflisten
Wenn Ihre Anwendung alle derzeit verbundenen USB-Geräte prüfen möchte:
während Ihre Anwendung ausgeführt wird, kann sie Geräte auf dem Bus auflisten. Verwenden Sie die Methode getDeviceList()
, um eine Hash-Zuordnung aller
den verbundenen USB-Geräten. Die Hash-Zuordnung wird durch den Namen des USB-Geräts eingegeben, wenn Sie
ein Gerät aus der Karte zu erhalten.
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager ... val deviceList = manager.getDeviceList() val device = deviceList.get("deviceName")
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); ... HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); UsbDevice device = deviceList.get("deviceName");
Bei Bedarf können Sie auch einfach einen Iterator aus der Hash-Zuordnung abrufen und jedes Gerät verarbeiten. nach 1:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager .. val deviceList: HashMap<String, UsbDevice> = manager.deviceList deviceList.values.forEach { device -> // your code }
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); ... HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next(); // your code }
Berechtigung zur Kommunikation mit einem Gerät einholen
Bevor Sie mit dem USB-Gerät kommunizieren können, muss Ihre App über die Berechtigung Ihres Nutzenden.
Hinweis: Wenn Ihre Anwendung einen Intent-Filter, um USB-Geräte zu erkennen, während sie verbunden sind, empfängt sie automatisch gewährt, wenn der Nutzer der Anwendung erlaubt, den Intent zu verarbeiten. Falls nicht, müssen Sie in Ihrer App ausdrücklich bestätigen, bevor Sie eine Verbindung zum Gerät herstellen.
In einigen Situationen kann es notwendig sein, ausdrücklich um Erlaubnis zu bitten, z. B. wenn deine listet die bereits verbundenen USB-Geräte auf, mit denen sie kommunizieren möchte, eins. Sie müssen Ihre Berechtigung für den Zugriff auf ein Gerät prüfen, bevor Sie versuchen, mit ihm zu kommunizieren. Wenn nicht, erhalten Sie einen Laufzeitfehler, wenn der Nutzer den Zugriff auf das Gerät verweigert hat.
Erstellen Sie zuerst einen Übertragungsempfänger, um die Berechtigung explizit einzuholen. Dieser Empfänger wartet auf
Intent, der beim Aufrufen von requestPermission()
übertragen wird. Beim Aufruf von requestPermission()
wird ein Dialogfeld für die
Nutzer bittet um Erlaubnis, sich mit dem Gerät zu verbinden. Der folgende Beispielcode zeigt, wie Sie
den Übertragungsempfänger erstellen:
Kotlin
private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" private val usbReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (ACTION_USB_PERMISSION == intent.action) { synchronized(this) { val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { device?.apply { // call method to set up device communication } } else { Log.d(TAG, "permission denied for device $device") } } } } }
Java
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; private final BroadcastReceiver usbReceiver = new BroadcastReceiver() { 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 (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if(device != null){ // call method to set up device communication } } else { Log.d(TAG, "permission denied for device " + device); } } } } };
Fügen Sie zum Registrieren des Übertragungsempfängers Folgendes in die onCreate()
-Methode in Ihrem
Aktivität:
Kotlin
private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" ... val manager = getSystemService(Context.USB_SERVICE) as UsbManager ... permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE) val filter = IntentFilter(ACTION_USB_PERMISSION) registerReceiver(usbReceiver, filter)
Java
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; ... permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(usbReceiver, filter);
Rufen Sie die Methode requestPermission()
auf, um das Dialogfeld aufzurufen, in dem Nutzer um die Berechtigung gebeten werden, eine Verbindung mit dem Gerät herzustellen:
Kotlin
lateinit var device: UsbDevice ... usbManager.requestPermission(device, permissionIntent)
Java
UsbDevice device; ... usbManager.requestPermission(device, permissionIntent);
Wenn Nutzer auf das Dialogfeld antworten, empfängt der Übertragungsempfänger den Intent mit dem Ereignis
EXTRA_PERMISSION_GRANTED
-Extra, ein boolescher Wert
die die Antwort darstellt. Überprüfen Sie diese Zusatzinformationen auf den Wert "true", bevor Sie eine Verbindung zum
.
Mit einem Gerät kommunizieren
Die Kommunikation mit einem USB-Gerät kann entweder synchron oder asynchron erfolgen. In beiden Fällen
sollte einen neuen Thread erstellen, über den alle Datenübertragungen durchgeführt werden.
UI-Thread. Um die Kommunikation mit einem Gerät richtig einzurichten, müssen Sie die entsprechenden
UsbInterface
und UsbEndpoint
der
Gerät, mit dem Sie kommunizieren möchten und mit dem Sie Anfragen an diesen Endpunkt mit einem UsbDeviceConnection
senden möchten. Im Allgemeinen sollte Ihr Code:
- Prüfe die Attribute eines
UsbDevice
-Objekts, z. B. Produkt-ID, Anbieter-ID oder Geräteklasse, um zu entscheiden, ob Sie mit dem . - Wenn Sie sicher sind, dass Sie mit dem Gerät kommunizieren möchten, suchen Sie das entsprechende
UsbInterface
, die für die Kommunikation mit dem der richtigenUsbEndpoint
dieser Schnittstelle. Schnittstellen können Folgendes aufweisen: oder mehr Endpunkte. Normalerweise haben sie einen Eingabe- und Ausgabeendpunkt für bidirektionale Kommunikation. - Wenn Sie den richtigen Endpunkt gefunden haben, öffnen Sie eine
UsbDeviceConnection
an diesen Endpunkt. - Geben Sie mit der Methode
bulkTransfer()
odercontrolTransfer()
die Daten an, die am Endpunkt übertragen werden sollen. Sie sollten führen Sie diesen Schritt in einem anderen Thread aus, damit der UI-Hauptthread nicht blockiert wird. Weitere Informationen Informationen zur Verwendung von Threads in Android finden Sie unter Prozesse und Threads:
Das folgende Code-Snippet stellt eine einfache Möglichkeit zur Durchführung einer synchronen Datenübertragung dar. Ihr Code sollte über mehr Logik verfügen, um die richtigen Schnittstellen und Endpunkte für die Kommunikation zu finden. Außerdem sollten Daten in einem anderen Thread als dem UI-Hauptthread übertragen werden:
Kotlin
private lateinit var bytes: ByteArray private val TIMEOUT = 0 private val forceClaim = true ... device?.getInterface(0)?.also { intf -> intf.getEndpoint(0)?.also { endpoint -> usbManager.openDevice(device)?.apply { claimInterface(intf, forceClaim) bulkTransfer(endpoint, bytes, bytes.size, TIMEOUT) //do in another thread } } }
Java
private Byte[] bytes; private static int TIMEOUT = 0; private boolean forceClaim = true; ... UsbInterface intf = device.getInterface(0); UsbEndpoint endpoint = intf.getEndpoint(0); UsbDeviceConnection connection = usbManager.openDevice(device); connection.claimInterface(intf, forceClaim); connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread
Wenn Sie Daten asynchron senden möchten, verwenden Sie die Klasse UsbRequest
, um initialize
und queue
eine asynchrone Anfrage zu senden. Warten Sie dann auf das Ergebnis.
mit requestWait()
.
Kommunikation mit einem Gerät beenden
Wenn die Kommunikation mit einem Gerät abgeschlossen ist oder das Gerät getrennt wurde, schließen Sie UsbInterface
und UsbDeviceConnection
wie folgt:
releaseInterface()
anrufen und
close()
. Um auf getrennte Ereignisse zu warten,
Erstellen Sie einen Übertragungsempfänger wie folgt:
Kotlin
var usbReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) { val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) device?.apply { // call your method that cleans up and closes communication with the device } } } }
Java
BroadcastReceiver usbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { // call your method that cleans up and closes communication with the device } } } };
Wenn Sie den Übertragungsempfänger in der Anwendung und nicht im Manifest erstellen, können Sie -Anwendung so ab, dass getrennte Ereignisse nur während ihrer Ausführung verarbeitet werden. So werden getrennte Ereignisse wird nur an die aktuell ausgeführte Anwendung gesendet und nicht an alle Anwendungen gesendet.