

flutterで開発を行っております。

bluetoothを使用したアプリを作成しているのですが、flutter_blueを用いた実装が全く上手く行きません。。  
bluetoothを使用するのは初めてで、至らない点や知識不足な点があれば、ご指摘いただければと思います。

スマホ：Android9  
flutter_blue: ^0.7.2

1、スキャンが上手くいかない

ダイソーで購入したBluetoothシャッターを使用して、ボタンを押した時に特定の動作をさせようと考えているのですが、  
startscanを行っても、ほとんどの確率でダイソーシャッターのdeviceが取得できません。  
なぜか、OFF→ONを行った直後にスキャンを行うと、上手く取得できることがあります。

2、Serviceが上手く取得できない  
上手くスキャンができ、コネクトが上手くいった場合（なぜかスキャンが上手く行く時はコネクトが既にされています…）、Serviceを取得し、Notifyによりシャッターボタンが押された時に特定の動作をさせようと目論んでいるのですが、  
ServiceのListは常にlength 0（何も取得できていない）が返ってきます。。  
ダイソーのBluetoothだからServiceが無いということがあるのでしょうか…？

上記２点がいくらやっても上手くいかず、質問をするに至りました。  
また、スマホ自体のBluetoothでダイソーシャッターへの接続は毎回上手くいきます。なのにアプリだとスキャンにも含まれないことがほとんどです。。  
また、どうやらスマホにBluetoothでダイソーシャッターを繋いでいる時はスキャンに必ずと言っていいほど含まれません。繋がってるのに！

以下に今まで奮闘したコードを記載します。  
もし少しでも気になることがありましたら、コメントいただけると幸いです。  
ご回答の程、よろしくお願いします！！  
(他の質問サイトでも質問させていただいています！)

[code]

    　　// スキャンを開始
        try {
          flutterBlue.isOn.then((bool isOn) {
            if (isOn) {
              flutterBlue.isScanning.first.then((isScanning) async {
                if (!isScanning) {
                  await startScanning();
                }
              });
            } else {
              Fluttertoast.showToast(msg: 'BluetoothをONにしてください');
            }
          });
        } on Exception catch (e) {
          print('start scan error:$e');
        }
    
        return SafeArea(
            child: Column(
              children: <Widget>[
    　　　　　　　// ここのscanResultsになぜかダイソーシャッターが引っかからないときがある…
                StreamBuilder<List<ScanResult>>(
                  stream: flutterBlue.scanResults,
                  builder: (context, snapshot) {
                    //　コネクト可能なものに絞る
                    final scanList = snapshot.data
                        .where((scanResult) =>
                            scanResult.advertisementData.connectable)
                        .toList();
    
                    return ListView.builder(
                      shrinkWrap: true,
                      itemCount: scanList.length,
                      itemBuilder: (context, index) {
                        return Card(
    
    　　　　　　　　　　　　　//　既に接続しているものを取得
                          child: StreamBuilder<List<BluetoothDevice>>(
                            stream: flutterBlue.connectedDevices.asStream(),
                            initialData: [],
                            builder: (c, snapshot) {
    
                              // 接続していればtrue
                              var isConnect = false;
    
                              for (final device in snapshot.data) {
                                if (device.id.toString() ==
                                    scanList[index].device.id.toString()) {
                                  isConnect = true;
    
    　　　　　　　　　　　　　　　　　　// ここでservicesのlengthが0になる…
                                  device.services.listen(
                                    (services) {
                                      services.forEach(
                                        (service) {
                                          service.characteristics.forEach(
                                            (characteristics) {
                                              characteristics.setNotifyValue(true);
                                              characteristics.value.listen(
                                                (val) {
                                                  print(val);
                                                },
                                              );
                                            },
                                          );
                                        },
                                      );
                                    },
                                  );
                                }
                              }
    
                              return ListTile(
                                // 接続中かどうか
                                leading: isConnect
                                    ? Icon(
                                        Icons.bluetooth_connected,
                                        color: Colors.blue,
                                      )
                                    : const SizedBox.shrink(),
                                onTap: () async {
                                  if (!isConnect) {
                                    await showBluetoothConnect(
                                        scanList[index].device, showVM);
                                  } else {
                                    await Fluttertoast.showToast(msg: '既に接続されています');
                                  }
                                },
                              );
                            },
                          ),
                        );
                      },
                    );
                  },
                ),
              ],
            ),
        );
      }
    
    // スキャン停止
    Future<void> stopScanning() async {
      await flutterBlue.stopScan();
    }
    
    //　スキャンスタート
    Future<void> startScanning() async {
      await flutterBlue.startScan(timeout: const Duration(seconds: 4));
    }
    
    // 接続
    Future<void> showBluetoothConnect(BluetoothDevice device) async {
      try {
        final state = await device.state.first;
        if (state == BluetoothDeviceState.connected) {
          await Fluttertoast.showToast(msg: '既に接続済みです');
          return;
        }
        await device.disconnect();
        bool isConnect;
        await device.connect().timeout(const Duration(seconds: 5),
            onTimeout: () async {
          debugPrint('timeout occured');
          isConnect = false;
          await Fluttertoast.showToast(msg: 'Bluetoothデバイスに接続できませんでした');
          await device.disconnect();
        }).then((data) {
          if (isConnect == null) {
            Fluttertoast.showToast(msg: 'Bluetoothデバイスに接続できました！');
          }
        });
      } on Exception catch (e) {
        await Fluttertoast.showToast(msg: 'Bluetoothデバイスに接続できませんでした');
        print('Bluetooth connect error:$e');
      }
    }
    
[/code]


CC BY-SA 4.0
2020-04-29T10:04:32.790
66104
2022-04-27T09:01:00.390
2020-04-29T10:38:01.250
39877
39877
question
bluetooth flutter
flutter_blueでスキャンが上手くいかない、コネクトできてもServiceが取得できない


flutter_blueを使用しなくても、ボリュームボタンが操作されていること、またキーボードとして認識されることを利用して、下記のような二つのパターンのいずれかで読み取ることができました！！

・RawKeyboardListenerを使用する  
参考：<https://stackoverflow.com/questions/54200938/external-keyboard-in-flutter-
support>  
<https://api.flutter.dev/flutter/widgets/RawKeyboardListener-class.html>

・hardware_buttonsを使用する  
参考：<https://pub.dev/packages/hardware_buttons>

しかし、ボタンを押すとボリュームの操作も行われてしまうため、そちらは検証しないといけません。。  
現状、検索してもボリューム操作を横取りできる方法はわかっていません。


CC BY-SA 4.0
2020-04-30T04:36:33.473
66137
2020-04-30T04:36:33.473
39877
66104
answer


「しかし、ボタンを押すとボリュームの操作も行われてしまうため、そちらは検証しないといけません。」については、JavaScriptの以下の記事で使われているのと同じ名前のメソッドがあるようなので、それが使えるかもしれません。

JavaScriptの記事  
[What's the difference between event.stopPropagation and
event.preventDefault?](https://stackoverflow.com/q/5963669/9014308)  
Q:

> They seem to be doing the same thing...  
>  Is one modern and one old? Or are they supported by different browsers?
>
> event.stopPropagationとevent.preventDefaultの違いは何ですか？  
>  彼らは同じことをしているようです...  
>  1つはモダンで、もう1つは古いですか または、異なるブラウザでサポートされていますか？

A:

> `stopPropagation` stops the event from bubbling up the event chain.  
>  イベントがイベントチェーンをバブリングしないようにします。
>
> `preventDefault` prevents the default action the browser makes on that
> event.  
>  ブラウザがそのイベントに対して行うデフォルトのアクションを防止します。

MDNの説明  
[Event.preventDefault()](https://developer.mozilla.org/ja/docs/Web/API/Event/preventDefault)

> Event インターフェースの preventDefault()
> メソッドは、ユーザーエージェントに、イベントが明示的に処理されない場合にその既定のアクションを通常どおりに行うべきではないことを伝えます。

[Event.stopPropagation()](https://developer.mozilla.org/ja/docs/Web/API/Event/stopPropagation)

> stopPropagation() は Event
> インターフェイスのメソッドで、現在のイベントのキャプチャリングまたはバブリングの過程におけるこれ以上の伝播を抑止します。

* * *

JavaScriptでのpreventDefault()だけだと止められないという記事  
[event.preventDefault() on keydown isn't working
[duplicate]](https://stackoverflow.com/q/42696059/9014308)  
Q:

> Trying to capture the key presses on a Bootstrap Tab Panel menus, but it
> just bubbles up ignoring the preventDefault() placed on the tabs's keydown
> handler.
>
>
> Bootstrapタブパネルのメニューでキープレスをキャプチャしようとしていますが、タブのキーダウンハンドラに置かれたpreventDefault()を無視してポップアップしてしまいます。
[code]

>     document.onkeydown = function(e) {
>       console.log("document catched the keydown event");
>     };
>     $('body > div > ul > li > a').on("keydown",function (e) {
>       console.log("handled by the child - stop bubbling please");
>       e.preventDefault();
>     });
>  
[/code]

A:

> Try e.stopPropagation()  
>  e.stopPropagation() prevents the event from bubbling up the DOM tree,
> preventing any parent handlers from being notified of the event.
>
> e.stopPropagation()を試してみてください。  
>  e.stopPropagation() は、イベントが DOM ツリー上に湧き上がるのを防ぎ、親ハンドラにイベントが通知されるのを防ぎます。
[code]

>     $('body > div > ul > li > a').on("keydown",function (e) {
>       console.log("handled by the child - stop bubbling please");
>       e.preventDefault();
>       e.stopPropagation();
>     });
>  
[/code]

* * *

Flutterの文書

Flutter > dart:html > KeyEvent class  
[KeyEvent class](https://api.flutter.dev/flutter/dart-html/KeyEvent-
class.html)

> Methods
>
> preventDefault() → void  
>  inherited
>
> stopPropagation() → void  
>  inherited

[preventDefault method](https://api.flutter.dev/flutter/dart-
html/KeyEvent/preventDefault.html)  
[stopPropagation method](https://api.flutter.dev/flutter/dart-
html/KeyEvent/stopPropagation.html)

* * *

丁度Flutterでボリュームキーの動作を無効にしたいが方法はないか？という質問  
何も回答は付いておらず未解決状態ですが。  
[Flutter: How can I prevent default behaviour on key
press?](https://stackoverflow.com/q/53473425/9014308)

> I'm trying to intercept when a user presses the volume buttons to perform a
> specific action and prevent the default behaviour (volume changes).
>
> ユーザーが特定の動作を行うために音量ボタンを押したときに、デフォルトの動作(音量の変更)を阻止しようとしています。
[code]

>     RawKeyboard.instance.addListener(_keyboardListener);
>  
>     void _keyboardListener(RawKeyEvent e) {
>       if(e.runtimeType == RawKeyUpEvent) {
>         RawKeyEventDataAndroid eA = e.data;
>         if(eA.keyCode == 24) { //volume up key
>           _goNextPage();
>         }
>         if(eA.keyCode == 25) { //volume down key
>           _goPrevPage();
>         }
>       }
>     }
>  
[/code]

>
> How would I go about preventing the volume from changing (and stopping the
> volume slider from appearing at the top)?  
>  A Javascript analogous would be calling `event.preventDefault()` on the key
> event.  
>  This seems to be a rather trivial matter, but I haven't been able to find
> any answers in the docs.
>
> 音量が変更されないようにする(のとボリュームスライダーが上部に表示されないようにする)にはどうすればいいのでしょうか？  
>  Javascriptで類似しているのは、キーイベントで `event.preventDefault()` を呼び出すことです。  
>  これはかなり些細なことのようですが、ドキュメントに答えが見つかりませんでした。


CC BY-SA 4.0
2020-04-30T06:16:26.823
66140
2020-04-30T09:04:43.520
2020-06-17T08:14:45.997
-1
26370
66104
answer