質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Q&A

解決済

2回答

11851閲覧

【Xamarin.Forms】AndroidにおけるBluetoothの実装(主にスレッド)

naritamago

総合スコア15

Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

0グッド

1クリップ

投稿2018/09/10 08:50

編集2018/09/11 01:04

実現したいこと

Xamarin.FormsでAndroidスマホとBluetoothデバイスの接続をコーディングしています。
スマホ側に保存されているペアリング済デバイスを取得して情報を取得する程度までは出来たのですが、Bluetooth接続を確立して送られて来る値を表示・保存する部分を実装しようとして挫折しそうです。
各所でAndroid(Java)の実装を見て勉強していますが、BluetoothもAndroidも初心者なもので、わからなくなっています。
聞きたい事は主に以下の2点です。

  • スマホ側はサーバーの実装?(ListenUsingRfCommWithServiceRecord()を使う?)

  • Xamarin.FormsでAndroidのスレッドをどう扱えば良い?

チュートリアルとしてよく見るのはスマホ同士で片方をサーバー、片方をクライアントにして接続するものですが、今回接続したいのは画面の無いクラシックBluetooth(SPP)のセンサーです。その場合はセンサーから送られて来るデータを読み込むサーバーとして実装するのが正解でしょうか?
Bluetoothデバイス側の実装が公開されておらず、スマホからMacAddressとUUIDを指定して接続要求をすれば値が返って来るものなのかもよく分かっていませんが、PC向けの純正アプリでは接続され、値が取得できるのを確認しています。

また、MVVM(っぽい)実装を目指していて、ViewにはUI、ViewModelでViewに表示する値の取得、ModelでAndroid固有機能を呼び出すインターフェースの定義、Androidプロジェクトでインターフェースに定義した機能を実装しています。
Android固有機能の呼び出しはインターフェースを介してDependencyService呼び出してます(この解釈で合ってるのか怪しいですが…)
この場合、接続要求を待つ別スレッドはVMに書くのか、Android側に書くのとどちらが望ましいでしょうか?

該当のソースコード

こちらの動画を参考にしています→Youtube
close処理などは省略しています。

Android

1public class BluetoothManager : IBluetoothManager 2{ 3 //UUID:SPP 4 private const string Uuid = "00001101-0000-1000-8000-00805f9b34fb"; 5 private BluetoothServerSocket mServerSocket; 6 private BluetoothSocket mSocket; 7 private BluetoothAdapter mAdapter; 8 private BufferedReader reader; 9 private System.IO.Stream mStream; 10 private InputStreamReader mReader; 11 12 //コンストラクタ 13 public BluetoothManager() 14 { 15 mReader = null; 16 } 17 18 public string getDataFromDevice() 19 { 20 return reader.ReadLine(); 21 } 22 23     private UUID getUUIDFromString() 24 { 25 return UUID.FromString(Uuid); 26 } 27 28 public void getAllPairedDevices() 29 { 30 BluetoothAdapter mAdapter = BluetoothAdapter.DefaultAdapter; 31 BluetoothDevice devices = mAdapter.BondedDevices; 32 if (devices != null && devices.Count > 0) 33 { 34 foreach (var device in devices) 35 { 36 try 37 { 38 mServerSocket = mAdapter.ListenUsingRfcommWithServiceRecord(NAME, getUUIDFromString()); 39 } 40 catch (IOException e) 41 { 42 System.Console.WriteLine(e); 43 } 44 try 45 { 46              //ここからがよくわからない 47 mSocket = mServerSocket.Accept(); 48 }catch(IOException e) 49 { 50 System.Console.WriteLine(e); 51 break; 52 } 53 if(mSocket!=null) 54 { 55 System.Console.WriteLine("connected!"); 56 } 57 else{ 58 System.Console.WriteLine("not connected"); 59 } 60 //mStream = mSocket.InputStream; 61 //System.Console.WriteLine("#debug location:getInputStream"); 62 ////Readerインスタンスの生成 63 //mReader = new InputStreamReader(mStream); 64 //System.Console.WriteLine("#debug location:getStreamReader"); 65 ////stringで読めるようにBuffered型に変換 66 //reader = new BufferedReader(mReader); 67 ////if(mSocket == null) 68 ////openDeviceConnection(device); 69 } 70 } 71 } 72 } 73} 74

ViewModel

1public BTViewModel() 2 { 3 IBluetoothManager btMan = DependencyService.Get<IBluetoothManager>(); 4 btMan.getAllPairedDevices(); //ペアリング済デバイスのリストを取得 5 6       //参考にしたサイトのコピペです。 7 System.Threading.Thread thread = new System.Threading.Thread(() => 8 { 9 while(true) 10 { 11 data = btMan.getDataFromDevice(); 12 Console.WriteLine("#debug {0}", data); 13 } 14 }); 15 thread.IsBackground = true; 16 thread.Start(); 17       //コピペここまで 18 }

試したこと

スレッドの理解が及ばないままmSocket = mServerSocket.Accept();を動かそうとしていましたが、ドキュメントを読むとAccept()は別スレッドでコールバックを受け付けないといけないとのことで、挫折しました。

追記(9/11)

f-miyuさんのご回答を参考に動かしてみましたが、機器の接続のところでIOExceptionが発生(Connect()メソッドがタイムアウトする)し、スレッドに関する動きを確認できていません。
ソース全体はgithubにあげています。問題が発生しているのは以下のメソッドです。

BluetoothManager

1private void openDeviceConnection(BluetoothDevice btDevice) 2{ 3 try 4 { 5 mSocket = btDevice.CreateRfcommSocketToServiceRecord(getUUIDFromString()); 6 System.Console.WriteLine("#debug get socket [{0}]", btDevice.Name); 7 mSocket.Connect(); 8 System.Console.WriteLine("#debug connect[{0}]", btDevice.Name); 9 //input stream 10 mStream = mSocket.InputStream; 11 System.Console.WriteLine("#debug open InputStream [{0}]", btDevice.Name); 12 mReader = new InputStreamReader(mStream); 13 System.Console.WriteLine("#debug get StreamReader [{0}]", btDevice.Name); 14 reader = new BufferedReader(mReader); 15 System.Console.WriteLine("#debug get get BufferedReader [{0}]", btDevice.Name); 16 } 17 catch(IOException e) 18 { 19 close(mSocket); 20 close(mStream); 21 close(mReader); 22 e.PrintStackTrace(); 23 throw e; 24 } 25}

btDeviceはペアリング済みデバイスの情報が格納されています。

CreateRfcommSocketToServiceRecored()の引数として読んでいるgetUUIDFromStrng()は、String型のローカル変数で定義しているUUIDをUUID型に変換して渡しているだけです。

9行目のConnect()メソッドがタイムアウトし、IOExceptionが帰ってきてしまいます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

スマホ側はサーバーの実装?

送られくるものを読み込むだけなので、サーバーではなく、クライアントでいいと思います。

Xamarin.FormsでAndroidのスレッドをどう扱えば良い?

Android側にスレッドを書いた方がいいと思います。
ViewModel側では、データを受け取るイベントを購読するようにします。

Android

C#

1public class DataEventArgs : EventArgs 2{ 3 public string Data { get; } 4 5 public DataEventArgs(string data) 6 { 7 Data = data; 8 } 9} 10 11public class BluetoothManager : IBluetoothManager 12{ 13 public event EventHandler<DataEventArgs> DataReceived; 14 15 public void Start() 16 { 17 var btAdapter = BluetoothAdapter.DefaultAdapter; 18 var devices = btAdapter.BondedDevices; 19 if (devices != null && devices.Count > 0) 20 { 21 foreach (var device in devices) 22 { 23 try 24 { 25 var socket = device.CreateRfcommSocketToServiceRecord(getUUIDFromString()); 26 Task.Run(() => 27 { 28 try 29 { 30 socket.Connect(); 31 32 var br = new BufferedReader(new InputStreamReader(socket.InputStream)); 33 34 string data; 35 while ((data = br.ReadLine()) != null) 36 { 37 DataReceived?.Invoke(this, new DataEventArgs(data)); 38 } 39 } 40 catch (IOException e) 41 { 42 } 43 finally 44 { 45 socket.Close(); 46 } 47 }); 48 } 49 catch (IOException e) 50 { 51 } 52 } 53 } 54 } 55}

ViewModel

C#

1btMan.DataReceived += (sender, e) => 2{ 3 Console.WriteLine("#debug {0}", e.Data); 4}; 5 6btMan.Start();

投稿2018/09/10 12:30

編集2018/09/11 01:58
f-miyu

総合スコア1625

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

naritamago

2018/09/10 15:41

f-miyuさん、知りたいことへの回答ありがとうございます。サーバーではなくクライアント側の実装に変更したのですが、 CreateRfcomm~で作成したソケットのConnect()メソッドを呼んだところでIOExceptionが発生し、接続出来ずスレッドの動作を確認するまでに至れませんでした。SPPのセンサーだけでなくゲームコントローラーやマウスなどいろいろな機器の接続も試している(UUIDプロパティの値を変えてます)のですが、今のところ全滅です。コードが悪いのか・機器が悪いのか、問題の切り分けに有効な手段があればご教示いただけないでしょうか?
f-miyu

2018/09/10 16:02

試したコードを載せてもらえますか?
naritamago

2018/09/10 23:24

githubにコード載せました→https://github.com/johta/XF-BT 時間ができたら追記にも該当部分のコードを記載します。
f-miyu

2018/09/11 01:32

githubを見ると、Uuidが違うと思います。 SPPなら、 00001101-0000-1000-8000-00805F9B34FB です。
naritamago

2018/09/11 01:40

SPPのUUIDは仰るとおりなんですが、色々な機器の接続を試していたので、最後に試したUUIDでそのままpushしちゃいました。たしかゲームコントローラだったと思います。
f-miyu

2018/09/11 01:59

参考にされたコードがあまりよろしくないので、修正したStartメソッドを試してみてください。
naritamago

2018/09/11 04:46 編集

提示していただいたコードでSPPセンサーに繋げて動かすことができました!!本当にありがとうございます!!! やはり、スレッドの理解が肝要だったのですね。わかりやすいコードを提示していただき、ありがとうございました。
guest

0

Rxでやるのが良さそう。

https://blog.okazuki.jp/entry/2017/01/25/183152

投稿2018/09/10 10:25

kiichi54321

総合スコア1984

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問