Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Usb接続するアプリを開発した時に試行錯誤した事

3,187 views

Published on

DroidKaigi 2018 Room 2 - 2018/02/08 16:50-17:20
発表スライドです

Published in: Technology
  • Be the first to comment

Usb接続するアプリを開発した時に試行錯誤した事

  1. 1. USB接続する アプリを開発した時に 試行錯誤したこと SmartDrive Masataka Kono 2018-2-8 DroidKaigi 2018
  2. 2. 自己紹介 ● Android Engineer ● 株式会社スマートドライブ ● Twitter @mapyo ● GitHub @mapyo ● (Server Side Engineer)
  3. 3. We’ re Hiring! https://www.wantedly.com/companies/smartdrive/projects
  4. 4. 質問です
  5. 5. USB接続するアプリを 作った事がある方 質問です
  6. 6. USB接続するアプリを これから作る予定がある方 質問です
  7. 7. 今日お伝えしたいこと ● これから作る予定のある方 ○ 基礎知識 ○ 雰囲気 ● これから作る予定もない方 ○ 雑学として
  8. 8. 今日お話すること ● どんなアプリを作ったか? ● USB接続の基礎知識 ● アプリ開発した時の事
  9. 9. どんなアプリを 作ったか?
  10. 10. どんなアプリを作ったか? ● 車のシガーソケットにつけるハードウェア ● センサーが内蔵されている
  11. 11. どんなアプリを作ったか? ● ハードウェアのセンサの情報をBLE経由で スマホにアップ ● スマホ経由でサーバにアップ サーバ BLE
  12. 12. どんなアプリを作ったか? ● ハードウェアのセンサの情報をBLE経由で スマホで取得 ● スマホ経由でサーバにアップ サーバ BLE USBでも出来るようにし たい!!
  13. 13. USB接続の 基礎知識
  14. 14. USB接続の基礎知識 ● Accessory modeとHost mode ● 基本的な使い方 ● permission
  15. 15. Accessory modeとHost mode ● Accessory mode ○ USB機器からAndroid端末 が電力をもらう ● Host mode ○ USB機器にAndroid端末が 電力を供給する
  16. 16. 出典: https://developer.android.com/guide/topics/connectivity/usb/index.html
  17. 17. 出典: https://developer.android.com/guide/topics/connectivity/usb/index.html
  18. 18. 出典: https://developer.android.com/guide/topics/connectivity/usb/index.html
  19. 19. 出典: https://developer.android.com/guide/topics/connectivity/usb/index.html Accessory modeでやりとりする アプリを作ったので、こちらにつ いて説明していきます。 使うAPIも違います。
  20. 20. 注意 スマホの機種自体で Accessory modeをサポートしている 必要があります ※とはいえ、検証した範囲の端末で はサポートされてない端末はなかっ た。(Android 5.0以上)
  21. 21. Accessory Modeと接続するハード ウェアの仕様 ● Android Open Acessory(AOA) protocolをサポートする必要あり ● Android Open Accessory Development Kit(ADK)がAOAの リファレンス実装 ○ Arduinoなどでも動作可能
  22. 22. USB接続の基礎知識 ● Accessory modeとHost mode ● 基本的な使い方 ● permission
  23. 23. USB接続の基礎知識 ※ここからはソースコード多め です。 事前にスライドをアップしてます ので、そちらも合わせてご確認 下さい。
  24. 24. 基本的な使い方 1. USB接続を検知する 2. データのやりとりをする 3. USBの切断を検知する この流れを実現するサンプルで 説明します
  25. 25. USB接続を検知する ● AndroidManifestに追加 ● usb-accessoryを書いたxml を追加
  26. 26. AndroidManifestに追加 <activity ...> <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESS ORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESS ORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity>
  27. 27. AndroidManifestに追加 <activity ...> <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESS ORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESS ORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity>
  28. 28. AndroidManifestに追加 <activity ...> <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESS ORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESS ORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity>
  29. 29. AndroidManifestに追加 <activity ...> <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESS ORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESS ORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity> Activityでないと検知出来ない!
  30. 30. accessory_filter <resources> <usb-accessory manufacturer="Sample, Inc." model="DemoKit" version="1.0" /> </resources> ※HW側の設定と一致させる必 要があります。
  31. 31. accessory_filter <resources> <usb-accessory manufacturer="Sample, Inc." model="DemoKit" version="1.0" /> </resources> manufacturerの指定だけでも OK! 自社製のデバイスであれば起動 させるというイメージ
  32. 32. 設定がうまく行っていると、 USB接続すると次のダイアログが開きます
  33. 33. USB接続された時
  34. 34. USB接続された時 AndroidManifestで指定した Activityが起動
  35. 35. USB接続された時 ダイアログが出ずにActivityが起 動します
  36. 36. USB接続された時 何も起きません。。。
  37. 37. 設定がうまくいっていない もしくは 対応するアプリがインストールされていない 状態でUSB接続した時は次のダイアログが開きま す
  38. 38. 対応したアプリがない時
  39. 39. 対応したアプリがない時 HW側で設定可能
  40. 40. 対応したアプリがない時 指定したURLが開きます。 アプリの説明のリンクに飛ばす のが良いでしょう。
  41. 41. 基本的な使い方 1. USB接続を検知する 2. データのやりとりをする 3. USBの切断を検知する この流れを実現するサンプルで 説明します
  42. 42. データのやりとりをする 準備 val usbAccessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY ) val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager
  43. 43. データのやりとりをする 準備 val usbAccessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY ) val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager val parcelFileDescriptor = usbManager.openAccessory(usbAccessory) val fileDescriptor = parcelFileDescriptor.fileDescriptor
  44. 44. データのやりとりをする 準備 val usbAccessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY ) val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager val parcelFileDescriptor = usbManager.openAccessory(usbAccessory) val fileDescriptor = parcelFileDescriptor.fileDescriptor val usbInputStream = FileInputStream(fileDescriptor) val usbOutputStream = FileOutputStream(fileDescriptor)
  45. 45. データのやりとりをする 送受信 // 文字列を送信する時 val message = "ほげほげ" val data = message.toByteArray(charset("UTF-8")) usbOutputStream.write(data) usbOutputStream.flush()
  46. 46. データのやりとりをする 送受信 // 文字列を送信する時 val message = "ほげほげ" val data = message.toByteArray(charset("UTF-8")) usbOutputStream.write(data) usbOutputStream.flush() // 文字列を受信する時 val byteArray = ByteArray(1024) usbInputStream.read(byteArray) val receiveMessage = String(byteArray, 0, byteArray.size, charset("UTF-8"))
  47. 47. ポイント ● ファイルの読み込み/書き込 みのような形でデータの送受 信が可能 ● 非同期処理で書く必要あり ● 送信と受信の口が別々
  48. 48. 切断を検知する // BroadcastReceiverで // UsbManager.ACTION_USB_ACCESSORY_DETACHED // を受け取る parcelFileDescriptor.close()
  49. 49. USB接続の基礎知識 ● Accessory modeとHost mode ● 基本的な使い方 ● permission
  50. 50. permission ● USB接続された時のダイアログ でOKすればpermissionは付与 済 ● 接続中のUSB一覧を取得して、 接続する時にpermission要求 が必要。
  51. 51. permission ● permissionがないまま接続する と例外を吐く ● 一般的なAndroidのpermission と違います
  52. 52. permission 1. 接続されているUSBアクセサ リを取得 2. permissionを要求する 3. permissionの許可を受け取 る この流れを実現するサンプル
  53. 53. 接続されているUSBアクセサリを取得 val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager val usbAccessory = usbManager.accessoryList?.firstOrNull() if (usbAccessory == null) { // USBがささっていない } else { // USBがささっている }
  54. 54. 接続されているUSBアクセサリを取得 val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager val usbAccessory = usbManager.accessoryList?.firstOrNull() if (usbAccessory == null) { // USBがささっていない } else { // USBがささっている } 一見複数接続に対応しているよ うだが、サポートされるのは、1 度に1接続だけですとドキュメン トに書いてあった
  55. 55. val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager val usbAccessory = usbManager.accessoryList?.firstOrNull() if (usbAccessory == null) { // USBがささっていない } else { // USBがささっている } 接続されているUSBアクセサリを取得 permissionが付与されているか 確認し、なければpermission要 求します
  56. 56. permissionの確認 if (usbManager.hasPermission(usbAccessory)) { // データのやり取りをする } else { // permissionの要求をする }
  57. 57. permissionの要求 val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0) usbManager.requestPermission(usbAccessory, permissionIntent)
  58. 58. permissionの要求 val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0) usbManager.requestPermission(usbAccessory, permissionIntent) 結果を受け取る時に つかいます
  59. 59. permissionの要求をすると こんなダイアログが出ます
  60. 60. permission要求後のダイアログ
  61. 61. permission要求後のダイアログ 最初に説明した、 USB接続した時の ダイアログとけっこうにてます
  62. 62. 接続した時 permission 要求した時
  63. 63. 接続した時 permission 要求した時
  64. 64. permission要求後のダイアログ
  65. 65. permission要求後のダイアログ 許可した状態で ブロードキャストが飛びます
  66. 66. permission要求後のダイアログ 拒否した状態で ブロードキャストが飛びます
  67. 67. permission要求後のダイアログ permission要求だけじゃなくて ATTACHEDイベントの時も自動 的にActivityが起動するようにな ります
  68. 68. permission要求結果を受け取る val usbReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // 中身は次のスライドへ } } } val filter = IntentFilter(ACTION_USB_PERMISSION) registerReceiver(usbReceiver, filter)
  69. 69. permission要求結果を受け取る val usbReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // 中身は次のスライドへ } } } val filter = IntentFilter(ACTION_USB_PERMISSION) registerReceiver(usbReceiver, filter) permission要求した時のアクショ ンを指定します
  70. 70. permission要求結果を受け取る 〜BroadcastReceiverの中身〜 if (ACTION_USB_PERMISSION == intent.action) { val accessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY ) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_ GRANTED, false)) { // 許可された // データのやり取りをする } else { // 拒否された } }
  71. 71. permission要求結果を受け取る 〜BroadcastReceiverの中身〜 if (ACTION_USB_PERMISSION == intent.action) { val accessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY ) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_ GRANTED, false)) { // 許可された // データのやり取りをする } else { // 拒否された } }
  72. 72. USB接続の基礎知識まとめ ● USB Accessoryのページしっかり読みましょう ○ https://developer.android.com/guide/topic s/connectivity/usb/accessory.html ● ドキュメントだけだとわかりにくかった ● 実際に動かしながら挙動を確かめながら確認し ていくとわかりやすいです
  73. 73.  アプリ開発  した時の事
  74. 74. アプリ開発した時のこと ● HWが出来てない時の開発の 進め方 ● デバッグが大変 ● ハマりどころ
  75. 75. アプリ開発した時のこと ● HWが出来てない時の開発の 進め方 ● デバッグが大変 ● ハマりどころ
  76. 76. HWが出来てない時の開発の進め方 ● そもそもハードがまだ出来てない ● 動くものがないから試せない ● 予想で作るしかない。。。? USB
  77. 77. HWが出来てない時の開発の進め方 どうしよう。。? ググる。
  78. 78. HWが出来てない時の開発の進め方 ● AndroidとPCのUSB通信のサンプル ○ http://blog.kotemaru.org/2013/10/0 6/android-usb-adk.html ● androidUSBSample ○ https://github.com/kotemaru/kotem aru/tree/master/androidUSBSampl e ● Arudinoで動かすという事例も
  79. 79. HWが出来てない時の開発の進め方 PCで動かせる!! 圧倒的感謝!!!!
  80. 80. HWが出来てない時の開発の進め方 ● PCとUSB接続して作っていく ● AOAの仕組みで動けばよい ● モックを作って動かしていた USB
  81. 81. HWが出来てない時の開発の進め方 PCで動かせるということ は。。。!!!
  82. 82. HWが出来てない時の開発の進め方 今日からみなさんも開発出来ま すね
  83. 83. アプリの開発 ● HWが出来てない時の開発の 進め方 ● デバッグが大変 ● ハマりどころ
  84. 84. USB接続してハードウエアと通信してい る。。。 デバッグが大変 USB
  85. 85. デバッグが大変 ん?
  86. 86. デバッグが大変 USB接続しているからPCと接 続できない。。。
  87. 87. デバッグが大変 Wi-Fi経由でadb接続出来 る!!!
  88. 88. デバッグが大変 Wi-Fi経由でadb接続 adb tcpip 5555 adb connect <device-ip-address>:5555
  89. 89. デバッグが大変 しかし何故か手元では出来な かった。。。
  90. 90. デバッグが大変 1. デバッグ用のログを細かくファ イルに保存 2. 後からファイルを参照してデ バッグする これで一旦は解決!
  91. 91. アプリの開発 ● HWが出来てない時の開発の 進め方 ● デバッグが大変 ● ハマりどころ
  92. 92. ハマりどころ その1 Activityでしか接続のイベントを 受けられない
  93. 93. Activityでしか接続のイベントを受け られない ● BroadcastReceiverでは受け られない! ● 受けようしてた。。 ● ドキュメントちゃんと読んでな かった。。。
  94. 94. Activityでしか接続のイベントを受け られない でも。。 BroadcastReceiverで受けた い!
  95. 95. Activityでしか接続のイベントを受け られない ● Serviceで接続する処理書い てた ● 裏側でUSBでデータやり取り ● 毎回Activity立ち上がってほ しくない
  96. 96. Activityでしか接続のイベントを受け られない 1. USB接続イベントActivityで受ける 2. 自分でBroadcast Intent作って放つ 3. すぐにActivityはfinish 4. BroadcastReceiverで受ける!
  97. 97. ハマりどころ その2 DFUする時に とある1機種で挙動が違う
  98. 98. DFUする時に とある1機種で挙動が違う DFUとは? ● Device Firmware Update ● HWの中で動いてるファームを アップデートする処理のこと
  99. 99. DFUする時に とある1機種で挙動が違う DFUする時の正常な処理の 流れ
  100. 100. DFUする時に とある機種で挙動が違う DFUします! わかりました!
  101. 101. DFUする時に とある機種で挙動が違う 1. 再起動(瞬断)
  102. 102. DFUする時に とある機種で挙動が違う 1. 再起動(瞬断) 2. 切断イベント close処理 3. 接続イベント 接続処理 データ送信
  103. 103. DFUする時に とある機種で挙動が違う とある1機種の場合
  104. 104. DFUする時に とある機種で挙動が違う DFUします! わかりました!
  105. 105. DFUする時に とある機種で挙動が違う 1. 再起動(瞬断)
  106. 106. DFUする時に とある機種で挙動が違う 1. 再起動(瞬断) 。。。
  107. 107. DFUする時に とある機種で挙動が違う 1. 再起動(瞬断) 。。。 何もイベントが飛んでこな い。。。
  108. 108. DFUする時に とある機種で挙動が違う こうやって対応した
  109. 109. DFUする時に とある機種で挙動が違う DFUします! わかりました!
  110. 110. DFUする時に とある機種で挙動が違う 1. 再起動(瞬断)
  111. 111. DFUする時に とある機種で挙動が違う 1. 再起動(瞬断) 2. 自分でcolse処理 4. 自分で接続処理      データ送信 3. 数秒待つ。。
  112. 112. DFUする時に とある機種で挙動が違う 1. 再起動(瞬断) 2. 自分でcolse処理 4. 自分で接続処理      データ送信 3. 数秒待つ。。 これをしないと接続出来なくなる!
  113. 113. DFUする時に とある機種で挙動が違う 機種依存的なものは これ以外にはなかったは ず。。。!
  114. 114. ハマりどころ その3 物理的にはささっているけど、 切断・接続イベントが飛んでくる
  115. 115. ケーブルや相性によってはグラグラする と、切断・接続を繰り返す。。。
  116. 116. 物理的にはささっているけど、切断・ 接続イベントが飛んでくる USBケーブルは適切なものを選 びましょう
  117. 117. 最後に
  118. 118. ● USB接続するアプリの開発が 出来るなんてとてもいい経験 だった。 ● なるべく実機で動かさずにテ ストで動作を担保出来るよう になるといいですね 最後に
  119. 119. ● USB接続するアプリ開発され た経験のある方はお話したい です ● スマドラや今日お話したハー ドにご興味ある方は現物もっ てきているのでお話しましょう 最後に
  120. 120. ご清聴ありがと うございまし た!
  121. 121. ふろく
  122. 122. 参考文献 ● USB Host and Accessory ○ https://developer.android.com/guide/topics/connectivity/ usb/index.html ● AOA2.0を実装してみた ○ https://www.slideshare.net/YuuichiAkagawa/aoa20 ● AndroidとPCのUSB通信のサンプル ○ http://blog.kotemaru.org/2013/10/06/android-usb-adk.ht ml ○ https://github.com/kotemaru/kotemaru/tree/master/andr oidUSBSample
  123. 123. ● Android 2.3.4でUSB Accsesoryを使う場合には 別途Google APIs add-on libraryを導入する必要 がありますが、4系以上の端末が殆どだと思いま すので、省いています ● 本スライドに載せたサンプルコードは説明を完結 にする為に省略している部分があります。null チェックや例外の処理など、適切に行いましょう。 補足
  124. 124. ● 参考文献のURLにPCとスマホでUSB接続するサ ンプルがありましたが、僕の方でも作っておりま す。(現在進行形です) ○ https://github.com/mapyo/UsbAccessorySam ple 補足

×