نظرة عامة على ملحق USB

يتيح وضع ملحق USB للمستخدمين الاتصال جهاز مضيف USB تم تصميمه خصيصًا للأجهزة التي تعمل بنظام التشغيل Android. يجب أن تتقيّد الملحقات بروتوكول ملحقات Android الموضحة في وثائق مجموعة أدوات تطوير ملحقات Android. يسمح هذا الإجراء للأجهزة التي تعمل بنظام التشغيل Android والتي لا يمكنها العمل كمضيف USB بالتفاعل مع USB. الأجهزة. عندما يكون أحد الأجهزة التي تعمل بنظام التشغيل Android في وضع ملحق USB، فإن منفذ USB المتصل بنظام Android يعمل الملحق كمضيف ويوفر الطاقة لناقل USB وتعداد الأجهزة المتصلة. يتوافق الإصدار Android 3.1 (المستوى 12 من واجهة برمجة التطبيقات) مع وضع ملحق USB وسيتم أيضًا نقل هذه الميزة إلى الإصدار 2.3.4 من نظام التشغيل Android (المستوى 10) من أجل إتاحة الدعم لمجموعة أكبر من الأجهزة

اختيار واجهات برمجة التطبيقات المناسبة لملحقات USB

على الرغم من أنه تم تقديم واجهات برمجة التطبيقات لملحقات USB للنظام الأساسي في Android 3.1، إلا أنها كذلك لا متوفرة في Android 2.3.4 باستخدام مكتبة إضافات Google APIs. نظرًا لأن واجهات برمجة التطبيقات هذه الرجوع إلى الإصدار الخلفي باستخدام مكتبة خارجية، فهناك حزمتان يمكنك استيرادهما للتوافق مع أجهزة USB وضع الإكسسوارات. بناءً على أجهزة Android التي تريد دعمها، قد تضطر إلى استخدم أحدهما على الآخر:

  • com.android.future.usb: لإتاحة وضع ملحق USB في الإصدار 2.3.4 من نظام التشغيل Android، يجب استخدام إضافة Google APIs تشتمل على واجهات برمجة التطبيقات لملحقات USB التي تم نقلها إلى جهاز آخر، وهي مضمّنة في هذا مساحة الاسم. يدعم Android 3.1 أيضًا استيراد الصفوف ضمن مساحة الاسم هذه وطلبها دعم التطبيقات المكتوبة باستخدام مكتبة الإضافات. مكتبة الإضافات هذه عبارة عن برنامج تضمين سطحي حول واجهات برمجة التطبيقات لملحقات android.hardware.usb ولا يتوافق مع وضع مضيف USB. في حال حذف إذا كنت تريد دعم أوسع مجموعة من الأجهزة التي تدعم وضع ملحق USB، فاستخدم المكتبة واستيراد هذه الحزمة. من المهم ملاحظة أنه ليست كل أجهزة Android 2.3.4 مطلوب لدعم ميزة ملحق USB. تقرر كل شركة مصنّعة للجهاز ما إذا كان يدعم هذه الإمكانية أم لا، ولهذا السبب يجب الإفصاح عنها في بيان التطبيق. الملف.
  • android.hardware.usb: تحتوي مساحة الاسم هذه على الفئات التي تتوافق مع USB. وضع الملحقات في الإصدار Android 3.1. يتم تضمين هذه الحزمة كجزء من واجهات برمجة التطبيقات الخاصة بإطار العمل، لذا يتوافق Android 3.1 مع وضع ملحق USB بدون استخدام مكتبة إضافية. استخدام هذه الحزمة إذا كان اهتمامك يقتصر على Android 3.1 أو الأجهزة الأحدث التي تتيح استخدام USB وضع الملحق، الذي يمكنك توضيحه في ملف البيان.

تثبيت مكتبة إضافة Google APIs

إذا أردت تثبيت الإضافة، يمكنك إجراء ذلك من خلال تثبيت Google APIs Android API 10. باستخدام أداة "مدير SDK". راجع تثبيت Google APIs الإضافة للحصول على مزيد من المعلومات حول تثبيت مكتبة الإضافات.

نظرة عامة على واجهة برمجة التطبيقات

بما أن مكتبة الإضافات هي برنامج تضمين لواجهات برمجة التطبيقات لإطار العمل، فإن الفئات التي تتيح ميزة ملحقات USB مماثلة. يمكنك استخدام المستندات المرجعية لـ android.hardware.usb حتى إذا كنت تستخدم مكتبة الإضافات.

ملاحظة: مع ذلك، هناك استخدام بسيط بين مكتبة الإضافات وواجهات برمجة تطبيقات إطار العمل التي يجب أن تكون على دراية بها.

يوضّح الجدول التالي الفئات التي تتوافق مع واجهات برمجة التطبيقات لملحقات USB:

الفئة الوصف
UsbManager يسمح لك بتعداد ملحقات USB المتصلة والاتصال بها.
UsbAccessory يمثِّل هذا الجهاز ملحق USB ويحتوي على طرق للوصول إلى معلومات تحديده. المعلومات.

الاختلافات في الاستخدام بين مكتبة الإضافات وواجهات برمجة تطبيقات النظام الأساسي

هناك نوعان من الاختلافات في الاستخدام بين استخدام مكتبة إضافة Google APIs والنظام الأساسي واجهات برمجة التطبيقات.

إذا كنت تستخدم المكتبة الإضافية، يجب الحصول على الكائن UsbManager بالطريقة التالية:

Kotlin

val manager = UsbManager.getInstance(this)

Java

UsbManager manager = UsbManager.getInstance(this);

إذا كنت لا تستخدم المكتبة الإضافية، يجب الحصول على الكائن UsbManager بالطريقة التالية:

Kotlin

val manager = getSystemService(Context.USB_SERVICE) as UsbManager

Java

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);

عند الفلترة بحثًا عن ملحق مرتبط باستخدام فلتر أهداف، يتم تضمين الكائن UsbAccessory داخل الهدف الذي يتم تمريره إلى التطبيق. إذا كنت تستخدم المكتبة الإضافية، يجب الحصول على الكائن UsbAccessory بالطريقة التالية:

Kotlin

val accessory = UsbManager.getAccessory(intent)

Java

UsbAccessory accessory = UsbManager.getAccessory(intent);

إذا كنت لا تستخدم المكتبة الإضافية، يجب الحصول على الكائن UsbAccessory بالطريقة التالية:

Kotlin

val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory

Java

UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

متطلبات بيان Android

توضح القائمة التالية ما يجب إضافته إلى ملف بيان تطبيقك قبل تعمل مع واجهات برمجة تطبيقات ملحقات USB. ملف البيان والموارد أمثلة على كيفية الإشارة إلى هذه البنود:

  • وبما أنّه لا يمكن ضمان توافق جميع الأجهزة التي تعمل بنظام التشغيل Android مع واجهات برمجة التطبيقات لملحقات USB، تضمين عنصر <uses-feature> يذكر أنّ تطبيقك يستخدم ميزة android.hardware.usb.accessory.
  • إذا كنت تستخدم مكتبة الإضافات أضف العنصر <uses-library> لتحديد com.android.future.usb.accessory للمكتبة.
  • اضبط الحد الأدنى لحزمة تطوير البرامج (SDK) للتطبيق على المستوى 10 من واجهة برمجة التطبيقات إذا كنت تستخدم مكتبة الإضافات. أو 12 إذا كنت تستخدم حزمة android.hardware.usb.
  • إذا كنت تريد أن يتم إشعار تطبيقك بملحق USB متصل، اختَر زوج العنصرَين <intent-filter> و<meta-data> من أجل android.hardware.usb.action.USB_ACCESSORY_ATTACHED النية في نشاطك الرئيسي. يشير العنصر <meta-data> إلى ملف موارد XML خارجي تعلن عن معلومات تعريفية عن الملحق الذي تريد اكتشافه.

    في ملف موارد XML، اذكر عناصر <usb-accessory> للإشارة إلى الملحقات التي تريد تصفيتها. يمكن أن تحتوي كل <usb-accessory> على السمات التالية:

    • manufacturer
    • model
    • version

    لا يُنصح بالفلترة على version. أحد الإكسسوارات أو قد لا يحدد الجهاز دائمًا سلسلة إصدار (عن قصد أو عن غير قصد). عندما يفصح تطبيقك عن سمة الإصدار للفلترة وفقًا للملحق أو الجهاز الملحق لا يحدد سلسلة الإصدار، سيؤدي هذا إلى ظهور NullPointerException على الإصدارات السابقة من Android. تمّ إصلاح هذه المشكلة في الإصدار 12 من نظام Android.

    احفظ ملف المورد في دليل res/xml/. اسم ملف المورد (بدون امتداد xml.) يجب أن تكون هي نفسها الإضافة التي حدّدتها في العنصر <meta-data>. ويظهر أيضًا تنسيق ملف موارد XML في المثال أدناه.

أمثلة على ملفات البيانات والموارد

يعرض المثال التالي نموذج بيان وملف الموارد المقابل له:

<manifest ...>
    <uses-feature android:name="android.hardware.usb.accessory" />
    
    <uses-sdk android:minSdkVersion="<version>" />
    ...
    <application>
      <uses-library android:name="com.android.future.usb.accessory" />
        <activity ...>
            ...
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
            </intent-filter>

            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
                android:resource="@xml/accessory_filter" />
        </activity>
    </application>
</manifest>

في هذه الحالة، يجب حفظ ملف المورد التالي في res/xml/accessory_filter.xml وتحدّد أن أي ملحق يحتوي على يجب تصفية الطراز والشركة المصنعة والإصدار. يرسل الملحق هذه لسمات الجهاز الذي يعمل بنظام التشغيل Android:

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

<resources>
    <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/>
</resources>

العمل مع الملحقات

عندما يوصِّل المستخدمون ملحقات USB بجهاز يعمل بنظام التشغيل Android، يمكن لنظام Android تنفيذ ما يلي: لتحديد ما إذا كان تطبيقك مهتمًا بالملحق المتصل. إذا كان الأمر كذلك، يمكنك تعيين الاتصال بالملحق إذا رغبت في ذلك. لإجراء ذلك، يجب أن يستوفي تطبيقك المتطلبات التالية:

  1. استكشِف الأجهزة الملحقة المرتبطة من خلال استخدام فلتر أهداف لفلترة الأجهزة الملحقة. الأحداث المرفقة أو عن طريق تعداد الملحقات المتصلة والعثور على الملحقات المناسبة.
  2. طلب الإذن من المستخدم للتواصل مع الملحق، إذا لم يسبق له ذلك حصلنا عليه.
  3. يمكنك التواصل مع الملحق من خلال قراءة البيانات وكتابتها على الواجهة المناسبة. والنقاط النهائية.

استكشاف أحد الإكسسوارات

يمكن لتطبيقك اكتشاف الملحقات إما باستخدام فلتر الأهداف ليتم إشعارك عند توصيل المستخدم أحد الأجهزة الملحقة أو عن طريق تعداد الملحقات المتصلة بالفعل. استخدام يُعد فلتر الأهداف مفيدًا إذا كنت تريد أن يتمكن تطبيقك من اكتشاف الملحق المطلوب. يكون تعداد الملحقات المتصلة مفيدًا إذا كنت تريد الحصول على قائمة بجميع الأجهزة الملحقة المتصلة أو ما إذا لم يفلتر تطبيقك غرضًا.

استخدام فلتر أهداف

لتمكين التطبيق من اكتشاف ملحق USB معين، يمكنك تحديد فلتر أهداف. للفلترة بحثًا عن هدف android.hardware.usb.action.USB_ACCESSORY_ATTACHED. على طول باستخدام فلتر الأهداف هذا، يجب تحديد ملف موارد يحدد خصائص USB إحدى الملحقات، مثل الشركة المصنّعة والطراز والإصدار.

يوضّح المثال التالي كيفية تعريف فلتر الأهداف:

<activity ...>
    ...
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
    </intent-filter>

    <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
        android:resource="@xml/accessory_filter" />
</activity>

يوضح المثال التالي كيفية الإعلان عن ملف المورد المعني الذي يحدد ملحقات USB التي تهمّك:

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

<resources>
    <usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" />
</resources>

في نشاطك، يمكنك الحصول على UsbAccessory الذي يمثّل الملحق المرفق من الغرض التالي (مع مكتبة الإضافات):

Kotlin

val accessory = UsbManager.getAccessory(intent)

Java

UsbAccessory accessory = UsbManager.getAccessory(intent);

أو ما شابه ذلك (باستخدام واجهات برمجة التطبيقات للنظام الأساسي):

Kotlin

val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory

Java

UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

تعداد الملحقات

يمكنك مطالبة طلبك بتعداد الملحقات التي تم تحديدها نفسها أثناء تطبيقك قيد التشغيل.

استخدام الطريقة getAccessoryList() للحصول على مصفوفة بجميع ملحقات USB المتصلة:

Kotlin

val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val accessoryList: Array<out UsbAccessory> = manager.accessoryList

Java

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbAccessory[] accessoryList = manager.getAccessoryList();

ملاحظة: لا يتوافق أكثر من ملحق متصل واحد في في وقت معين.

الحصول على إذن للتواصل باستخدام أحد الأجهزة الملحقة

قبل الاتصال بملحق USB، يجب أن يحصل التطبيق على إذن من المستخدمين.

ملاحظة: إذا كان تطبيقك يستخدم فلتر الأهداف لاكتشاف الملحقات عند ربطها، يتلقّى التطبيق تلقائيًا إذا كان المستخدم يسمح لتطبيقك بمعالجة النية. إذا لم يكن الأمر كذلك، عليك طلب إذن صريح في التطبيق قبل الاتصال بالملحق.

وقد يكون طلب الإذن صراحةً ضروريًا في بعض المواقف، مثل عندما الملحقات المتصلة بالفعل ثم تريد التواصل مع واحد. يجب التحقّق من إذن الوصول إلى أحد الأجهزة الملحقة قبل محاولة الاتصال به. وإذا لم يكن الأمر كذلك، سيظهر لك خطأ بيئة تشغيل إذا رفض المستخدم منح إذن الوصول إلى ملحق.

للحصول على الإذن صراحةً، يجب أولاً إنشاء جهاز استقبال بث. يستمع هذا الجهاز إلى النية التي يتم بثها عند الاتصال بـ requestPermission(). يعرض الاتصال بـ requestPermission() مربع حوار المستخدم يطلب الإذن بالاتصال بالملحق. يوضح الرمز النموذجي التالي كيفية إنشاء مستقبل البث:

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 accessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY)

                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    accessory?.apply {
                        // call method to set up accessory communication
                    }
                } else {
                    Log.d(TAG, "permission denied for accessory $accessory")
                }
            }
        }
    }
}

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) {
                UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if(accessory != null){
                        // call method to set up accessory communication
                    }
                }
                else {
                    Log.d(TAG, "permission denied for accessory " + accessory);
                }
            }
        }
    }
};

لتسجيل مستقبِل البث، يُرجى إدخال طريقة onCreate() في النشاط:

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), 0)
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), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(usbReceiver, filter);

لعرض مربّع الحوار الذي يطلب من المستخدمين الإذن بالاتصال بالملحق، يُرجى طلب طريقة requestPermission():

Kotlin

lateinit var accessory: UsbAccessory
...
usbManager.requestPermission(accessory, permissionIntent)

Java

UsbAccessory accessory;
...
usbManager.requestPermission(accessory, permissionIntent);

عندما يرد المستخدمون على مربّع الحوار، يتلقّى مستقبل البث الغرض الذي يحتوي على EXTRA_PERMISSION_GRANTED إضافية، وهي قيمة منطقية تمثل الإجابة. تحقق من هذه القيمة الإضافية للتأكد من أنها على القيمة true قبل الاتصال ملحق.

التواصل باستخدام أحد الأجهزة الملحقة

يمكنك الاتصال بالملحق باستخدام UsbManager من أجل الحصول على واصف ملف يمكنك إعداد تدفقات المدخلات والمخرجات لقراءة البيانات وكتابتها واصف البيانات. وتمثّل ساحات المشاركات نقاط نهاية مجمّعة للإدخال والإخراج للجهاز الملحق. يجب عليك تعيين الاتصال بين الجهاز والملحق في سلسلة محادثات أخرى، حتى لا يتم قفل مؤشر ترابط واجهة المستخدم الرئيسية. يوضّح المثال التالي كيفية فتح جهاز ملحق للتواصل معه:

Kotlin

private lateinit var accessory: UsbAccessory
private var fileDescriptor: ParcelFileDescriptor? = null
private var inputStream: FileInputStream? = null
private var outputStream: FileOutputStream? = null
...

private fun openAccessory() {
    Log.d(TAG, "openAccessory: $mAccessory")
    fileDescriptor = usbManager.openAccessory(accessory)
    fileDescriptor?.fileDescriptor?.also { fd ->
        inputStream = FileInputStream(fd)
        outputStream = FileOutputStream(fd)
        val thread = Thread(null, this, "AccessoryThread")
        thread.start()
    }
}

Java

UsbAccessory accessory;
ParcelFileDescriptor fileDescriptor;
FileInputStream inputStream;
FileOutputStream outputStream;
...

private void openAccessory() {
    Log.d(TAG, "openAccessory: " + accessory);
    fileDescriptor = usbManager.openAccessory(accessory);
    if (fileDescriptor != null) {
        FileDescriptor fd = fileDescriptor.getFileDescriptor();
        inputStream = new FileInputStream(fd);
        outputStream = new FileOutputStream(fd);
        Thread thread = new Thread(null, this, "AccessoryThread");
        thread.start();
    }
}

في طريقة run() لسلسلة المحادثات، يمكنك القراءة والكتابة في الملحق باستخدام الكائنات FileInputStream أو FileOutputStream. أثناء القراءة البيانات من الجهاز الملحق الذي يتضمن كائن FileInputStream، يُرجى التأكّد من أنّ المخزن المؤقت التي تستخدمها كبيرة بما يكفي لتخزين بيانات حزمة USB. يتوافق بروتوكول ملحقات Android مع يكون حجم المخزن المؤقت للحِزم يصل إلى 16384 بايت، وبالتالي يمكنك اختيار أن يكون المخزن المؤقت لديك من هذا النوع. الحجم للتبسيط.

ملاحظة: على المستوى الأدنى، يكون حجم حزم البيانات 64 بايت لـ USB ملحقات كاملة السرعة و512 بايت لملحقات USB عالية السرعة. ملحق Android يجمِّع الحزم معًا لكلا السرعات في حزمة منطقية واحدة لمزيد من التبسيط.

لمزيد من المعلومات حول استخدام سلاسل المحادثات في Android، يمكنك الاطّلاع على العمليات سلاسل المحادثات:

إنهاء الاتصال باستخدام أحد الملحقات

عند الانتهاء من الاتصال بأحد الملحقات أو إذا تم فصل الملحق، أغلِق الذي فتحته من خلال استدعاء close(). للاستماع إلى الأحداث التي تم فصلها، يمكنك إنشاء جهاز استقبال بث كما يلي:

Kotlin

var usbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {

        if (UsbManager.ACTION_USB_ACCESSORY_DETACHED == intent.action) {
            val accessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY)
            accessory?.apply {
                // call your method that cleans up and closes communication with the accessory
            }
        }
    }
}

Java

BroadcastReceiver usbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
            UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
            if (accessory != null) {
                // call your method that cleans up and closes communication with the accessory
            }
        }
    }
};

يتيح إنشاء مستقبِل البث داخل التطبيق، وليس في البيان، معالجة الأحداث المنفصلة فقط أثناء تشغيله. بهذه الطريقة، يتم دمج الأحداث يتم إرساله فقط إلى التطبيق قيد التشغيل حاليًا ولا يتم بثه إلى جميع التطبيقات.