حالت لوازم جانبی USB به کاربران امکان میدهد سختافزار میزبان USB را که بهطور ویژه برای دستگاههای مجهز به Android طراحی شده است متصل کنند. لوازم جانبی باید از پروتکل لوازم جانبی Android که در مستندات کیت توسعه لوازم جانبی Android ذکر شده است پیروی کنند. این کار به دستگاههای مجهز به Android که نمیتوانند بهعنوان میزبان USB عمل کنند امکان میدهد همچنان با سختافزار USB تعامل داشته باشند. وقتی دستگاهی با سیستمعامل Android در حالت لوازم جانبی USB باشد، لوازم جانبی Android USB متصل بهعنوان میزبان عمل میکند، به گذرگاه USB برق میدهد، و دستگاههای متصل را فهرست میکند. Android 3.1 (سطح API 12) از حالت لوازم جانبی USB پشتیبانی میکند و این ویژگی به Android 2.3.4 (سطح API 10) نیز برگردانده شده است تا از طیف وسیعتری از دستگاهها پشتیبانی شود.
انتخاب کردن میاناهای برنامهسازی کاربردی لوازم جانبی USB مناسب
اگرچه API لوازم جانبی USB در Android 3.1 به پلاتفرم معرفی شد، اما در Android 2.3.4 نیز بااستفاده از کتابخانه برافزای Google APIs دردسترس است. ازآنجاییکه این میاناهای برنامهسازی کاربردی بااستفاده از کتابخانه خارجی به نسخههای قبلی برگردانده شدهاند، دو بسته وجود دارد که میتوانید برای پشتیبانی از حالت لوازم جانبی USB وارد کنید. بسته به اینکه میخواهید از کدام دستگاههای مجهز به Android پشتیبانی کنید، ممکن است مجبور شوید از یکی بهجای دیگری استفاده کنید:
com.android.future.usb: برای پشتیبانی از حالت لوازم جانبی USB در Android 2.3.4، کتابخانه برافزای Google APIs شامل میاناهای برنامهسازی کاربردی لوازم جانبی USB با قابلیت انتقال به نسخههای قبلی است و در این فضای نام قرار دارد. Android 3.1 همچنین از وارد کردن و فراخوانی کردن کلاسهای درون این فضای نام برای پشتیبانی از برنامههایی که با کتابخانه برافزا نوشته شدهاند پشتیبانی میکند. این کتابخانه برافزا یک بستهبندی نازک در اطرافandroid.hardware.usbAPI لوازم جانبی است و از حالت میزبان 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 با «مدیر کیت توسعه نرمافزار» این کار را انجام دهید. برای اطلاعات بیشتر درباره نصب کتابخانه برافزا، نصب برافزای «میاناهای برنامهسازی کاربردی Google» را ببینید.
نمای کلی میانای برنامهسازی کاربردی
ازآنجاییکه کتابخانه برافزا یک بستهبندی برای میاناهای برنامهسازی کاربردی چارچوب است، کلاسهایی که از ویژگی لوازم جانبی USB پشتیبانی میکنند مشابه هستند. حتی اگر از کتابخانه برافزا استفاده میکنید، میتوانید از اسناد مرجع برای android.hardware.usb استفاده کنید.
توجه: بااینحال، تفاوت جزئی در کاربردبین کتابخانه برافزا و «میاناهای برنامهسازی کاربردی چارچوب» وجود دارد که باید از آن آگاه باشید.
جدول زیر کلاسهایی را که از APIهای لوازم جانبی USB پشتیبانی میکنند شرح میدهد:
| کلاس | شرح |
|---|---|
UsbManager |
به شما امکان میدهد لوازم جانبی USB متصل را فهرست کنید و با آنها ارتباط برقرار کنید. |
UsbAccessory |
لوازم جانبی USB را نشان میدهد و شامل روشهایی برای دسترسی به اطلاعات شناسایی آن است. |
تفاوتهای استفاده بین کتابخانه برافزا و میاناهای برنامهسازی کاربردی پلاتفرم
دو تفاوت در استفاده بین استفاده از کتابخانه برافزای Google APIs و پلاتفرم APIs وجود دارد.
اگر از کتابخانه برافزا استفاده میکنید، باید شیء UsbManager را به روش زیر دریافت کنید:
کاتلین
val manager = UsbManager.getInstance(this)
جاوا
UsbManager manager = UsbManager.getInstance(this);
اگر از کتابخانه برافزایی استفاده نمیکنید، باید شیء UsbManager را به روش زیر دریافت کنید:
کاتلین
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
جاوا
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
وقتی با فیلتر هدف، لوازم جانبی متصل را فیلتر میکنید، شیء UsbAccessory در هدفی که به برنامه شما ارسال میشود قرار دارد. اگر از کتابخانه برافزا استفاده میکنید، باید شیء UsbAccessory را به روش زیر دریافت کنید:
کاتلین
val accessory = UsbManager.getAccessory(intent)
جاوا
UsbAccessory accessory = UsbManager.getAccessory(intent);
اگر از کتابخانه برافزایی استفاده نمیکنید، باید شیء UsbAccessory را به روش زیر دریافت کنید:
کاتلین
val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory
جاوا
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
الزامات مانیفست Android
فهرست زیر توضیح میدهد که قبلاز کار کردن با «میاناهای برنامهسازی کاربردی لوازم جانبی USB»، چه چیزهایی را باید به فایل مانیفست برنامهتان اضافه کنید. مانیفست و فایل منبع نمونهها نحوه اعلام این موارد را نشان میدهد:
- ازآنجاییکه پشتیبانی از «میاناهای برنامهسازی کاربردی لوازم جانبی USB» در همه دستگاههای مجهز به Android تضمین نمیشود،
عنصر
<uses-feature>را اضافه کنید که اعلام میکند برنامه شما از ویژگیandroid.hardware.usb.accessoryاستفاده میکند. - اگر از
کتابخانه برافزا استفاده میکنید،
عنصر
<uses-library>را اضافه کنید وcom.android.future.usb.accessoryرا برای کتابخانه مشخص کنید. - اگر از کتابخانه برافزا استفاده میکنید، حداقل کیت توسعه نرمافزار برنامه را روی «سطح میانای برنامه کاربردی ۱۰» تنظیم کنید
یا اگر از بسته
android.hardware.usbاستفاده میکنید، روی ۱۲ تنظیم کنید. -
اگر میخواهید برنامهتان از پیوست لوازم جانبی USB مطلع شود، یک جفت عنصر
<intent-filter>و<meta-data>برایandroid.hardware.usb.action.USB_ACCESSORY_ATTACHEDقصد در فعالیت اصلیتان مشخص کنید. عنصر<meta-data>به فایل منبع XML خارجی اشاره میکند که اطلاعات شناسایی درباره لوازم جانبی موردنظرتان برای شناسایی را اعلام میکند.در فایل منبع XML، عناصر
<usb-accessory>را برای لوازم جانبیای که میخواهید فیلتر کنید اعلام کنید. هر<usb-accessory>میتواند مشخصههای زیر را داشته باشد:manufacturermodelversion
فیلتر کردن براساس
versionتوصیه نمیشود. لوازم جانبی یا دستگاه ممکن است همیشه رشته نسخه را مشخص نکند (بهصورت عمدی یا غیرعمدی). وقتی برنامه شما مشخصه نسخهای را برای فیلتر کردن براساس آن اعلام میکند و لوازم جانبی یا دستگاه رشته نسخه را مشخص نمیکند، این امر باعث ایجادNullPointerExceptionدر نسخههای قدیمیتر Android میشود. این مشکل در Android 12 برطرف شده است.فایل منبع را در دایرکتوری
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 میتواند تعیین کند که آیا برنامه شما به لوازم جانبی متصل علاقهمند است یا نه. در این صورت، درصورت تمایل میتوانید ارتباط با لوازم جانبی را راهاندازی کنید. برای انجام این کار، برنامه شما باید:
- بااستفاده از فیلتر هدف که رویدادهای پیوست لوازم جانبی را فیلتر میکند یا با فهرست کردن لوازم جانبی متصل و یافتن لوازم جانبی مناسب، لوازم جانبی متصل را کاوش کنید.
- اگر قبلاً اجازه برقراری ارتباط با لوازم جانبی را دریافت نکردهاید، از کاربر بخواهید اجازه دهد.
- با خواندن و نوشتن دادهها در نقطههای پایانی رابط مناسب با لوازم جانبی ارتباط برقرار کنید.
کاوش وسیله جانبی
برنامه شما میتواند بااستفاده از فیلتر هدف برای دریافت اعلان هنگام اتصال وسیله جانبی توسط کاربر یا با فهرست کردن وسایل جانبی که قبلاً متصل شدهاند، وسایل جانبی را شناسایی کند. استفاده از فیلتر هدف درصورتی مفید است که بخواهید برنامهتان بتواند بهطور خودکار وسیله جانبی موردنظر را تشخیص دهد. اگر بخواهید فهرستی از همه لوازم جانبی متصل دریافت کنید یا اگر برنامه شما برای هدف فیلتر نکرده باشد، شمارش لوازم جانبی متصل مفید است.
استفاده از فیلتر قصد
برای اینکه برنامهتان وسیله جانبی 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 را که نشاندهنده
لوازم جانبی پیوستشده از هدف است به این صورت دریافت کنید (با کتابخانه برافزا):
کاتلین
val accessory = UsbManager.getAccessory(intent)
جاوا
UsbAccessory accessory = UsbManager.getAccessory(intent);
یا مانند این (با میاناهای برنامهسازی کاربردی پلاتفرم):
کاتلین
val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory
جاوا
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
فهرست کردن لوازم جانبی
میتوانید برنامهتان را طوری تنظیم کنید که لوازم جانبیای را که درحین اجرای برنامه خودشان را شناسایی کردهاند فهرست کند.
برای دریافت آرایهای از همه لوازم جانبی USB متصل، از روش getAccessoryList() استفاده کنید:
کاتلین
val manager = getSystemService(Context.USB_SERVICE) as UsbManager val accessoryList: Array<out UsbAccessory> = manager.accessoryList
جاوا
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); UsbAccessory[] accessoryList = manager.getAccessoryList();
توجه: هر بار فقط از یک لوازم جانبی متصل پشتیبانی میشود.
دریافت اجازه برای برقراری ارتباط با وسیله جانبی
برنامه شما باید قبلاز برقراری ارتباط با لوازم جانبی USB، از کاربران اجازه بگیرد.
توجه: اگر برنامه شما برای شناسایی وسایل جانبی هنگام اتصال از فیلتر هدف استفاده میکند، درصورتیکه کاربر به برنامه شما اجازه دهد هدف را مدیریت کند، برنامه بهطور خودکار اجازه دریافت میکند. درغیراینصورت، باید قبلاز اتصال به لوازم جانبی، اجازه را بهطور صریح در برنامهتان درخواست کنید.
در برخیاز موقعیتها، مثل زمانی که برنامه شما لوازم جانبی را که قبلاً متصل شدهاند فهرست میکند و سپس میخواهد با یکی از آنها ارتباط برقرار کند، ممکن است لازم باشد بهطور صریح درخواست اجازه کنید. قبلاز تلاش برای برقراری ارتباط با لوازم جانبی، باید اجازه دسترسی به آن را بررسی کنید. درغیراینصورت، اگر کاربر اجازه دسترسی به لوازم جانبی را ندهد، خطای زمان اجرا دریافت خواهید کرد.
برای دریافت صریح اجازه، ابتدا گیرنده همهفرستی ایجاد کنید. این گیرنده به
منظوری که هنگام تماس با requestPermission() همهفرستی میشود گوش میدهد. تماس با requestPermission() کادر گفتگویی را به کاربر نمایش میدهد و از او میخواهد اجازه دهد به لوازم جانبی متصل شود. کد نمونه زیر نحوه ایجاد گیرنده همهفرستی را نشان میدهد:
کاتلین
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") } } } } }
جاوا
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() در فعالیتتان قرار دهید:
کاتلین
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)
جاوا
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() را فراخوانی کنید:
کاتلین
lateinit var accessory: UsbAccessory ... usbManager.requestPermission(accessory, permissionIntent)
جاوا
UsbAccessory accessory; ... usbManager.requestPermission(accessory, permissionIntent);
وقتی کاربران به این چارگوش گفتگو پاسخ میدهند، گیرنده همهفرستی شما هدف حاوی
EXTRA_PERMISSION_GRANTED اضافی را دریافت میکند که یک مقدار بولی است
و پاسخ را نشان میدهد. قبلاز اتصال به لوازم جانبی، این ویژگی اضافی را برای مقدار درست بررسی کنید.
برقراری ارتباط با لوازم جانبی
میتوانید بااستفاده از UsbManager با لوازم جانبی ارتباط برقرار کنید تا
توصیفگر فایلی را دریافت کنید که میتوانید جاریسازیهای ورودی و خروجی را برای خواندن و نوشتن دادهها در
توصیفگر تنظیم کنید. جاریسازیها نشاندهنده نقاط پایانی انبوه ورودی و خروجی لوازم جانبی هستند. باید ارتباط بین دستگاه و لوازم جانبی را در رشته دیگری راهاندازی کنید تا رشته اصلی واسط کاربر را قفل نکنید. مثال زیر نحوه باز کردن وسیله جانبی برای برقراری ارتباط با آن را نشان میدهد:
کاتلین
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() } }
جاوا
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 از
بافرهای بسته تا ۱۶۳۸۴ بایت پشتیبانی میکند، بنابراین میتوانید برای سادگی، همیشه بافر خود را با این
اندازه تعریف کنید.
توجه: در سطح پایینتر، بستهها برای لوازم جانبی USB با سرعت کامل ۶۴ بایت و برای لوازم جانبی USB با سرعت بالا ۵۱۲ بایت هستند. پروتکل لوازم جانبی Android بستهها را برای هر دو سرعت در یک بسته منطقی برای سادگی با هم ترکیب میکند.
برای کسب اطلاعات بیشتر درباره استفاده از رشتهها در Android، به فرایندها و رشتهها مراجعه کنید.
قطع ارتباط با لوازم جانبی
وقتی ارتباط با لوازم جانبی تمام شد یا اگر لوازم جانبی جدا شد، توصیفگر فایل را که با فراخوانی close() باز کردهاید ببندید.
برای گوش دادن به رویدادهای جداشده، گیرنده همهفرستی را مانند زیر ایجاد کنید:
کاتلین
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 } } } }
جاوا
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 } } } };
ایجاد گیرنده رویداد در داخل برنامه، و نه مانیفیست، به برنامه شما اجازه میدهد فقط رویدادهای جداشده را درحین اجرا مدیریت کند. به این ترتیب، رویدادهای جداشده فقط به برنامهای که درحال اجرا است ارسال میشود و به همه برنامهها همفرستی نمیشود.