1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

flutter_blue_plus を使った BLEスキャンを Flutter で実装してみる: Android Studio で Androidアプリをビルド

Last updated at Posted at 2025-03-26

はじめに

今回の内容は、以下の記事の続きのようなものです。

●Flutterアプリ(flutter_blue_plus の Android用サンプル)と micro:bit CreateAI のプログラムを BLE通信でつないでみる - Qiita
 https://qiita.com/youtoy/items/b8e14601ecab557d3f72

上記の記事では、flutter_blue_plus のサンプルアプリを Androidスマホで動かしてみました。

今回は、flutter_blue_plus を使った Flutter での BLEスキャンを実装してみます。

利用するパッケージ

前回同様、以下のパッケージを使います。

●flutter_blue_plus | Flutter package
 https://pub.dev/packages/flutter_blue_plus

2025-03-26_23-28-32.jpg

実際に試していく

下準備

Android Studio で、新規の Flutter用プロジェクトを作成し、今回用の下準備を進めます。

パッケージのインストール

以下のコマンドで、flutter_blue_plus をインストールします(自分の環境は FVM を使っているので、先頭部分に fvm をつけています)。

fvm flutter pub add flutter_blue_plus

パーミッションの追加

「android/app/src/main/AndroidManifest.xml」にパーミッションを追加します。

追加する内容は、flutter_blue_plus の公式ページの以下に書かれているものです。

●flutter_blue_plus | Flutter package
 https://pub.dev/packages/flutter_blue_plus#add-permissions-for-android-no-location

2025-03-26_23-49-41.jpg

自分のスマホは Android 15 なので、以下の部分だけ追記します。

<!-- Tell Google Play Store that your app uses Bluetooth LE
     Set android:required="true" if bluetooth is necessary -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />

<!-- New Bluetooth permissions in Android 12
https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

追記後の冒頭部分は、以下のとおりです。

2025-03-27_00-57-03.jpg

スキャンする処理を実装する

公式ページの以下の部分に、スキャンに関するコードが載っています。

●flutter_blue_plus | Flutter package
 https://pub.dev/packages/flutter_blue_plus#scan-for-devices

2025-03-27_00-58-44.jpg

これを、処理の中に組み込んでいきます。

画面構成

今回のアプリの画面構成は、とりあえずシンプルなもので試してみます。
具体的には、「スキャンを開始するボタン」と「スキャンできたデバイスを表示する部分」がメインの要素になる形にしました。

コード

コードは以下のとおりです。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BLE Scan Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'BLE Scan Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> _scanResults = [];
  StreamSubscription<List<ScanResult>>? _scanSubscription;

  // スキャン開始
  Future<void> _startScan() async {
    // 前回の結果をクリア
    setState(() {
      _scanResults.clear();
    });

    // BluetoothがONになるまで待機
    await FlutterBluePlus.adapterState
        .firstWhere((state) => state == BluetoothAdapterState.on);

    // 結果の取得
    _scanSubscription = FlutterBluePlus.onScanResults.listen(
          (results) {
        for (var result in results) {
          final deviceId = result.device.remoteId.toString();
          final deviceName = result.advertisementData.advName;
          final info = '$deviceId: "$deviceName"';
          // 重複チェックしつつリストへ追加
          if (!_scanResults.contains(info)) {
            setState(() {
              _scanResults.add(info);
            });
          }
        }
      },
      onError: (e) => print('Error: $e'),
    );

    // タイムアウト15秒でスキャン実行
    await FlutterBluePlus.startScan(timeout: const Duration(seconds: 15));

    await FlutterBluePlus.isScanning
        .firstWhere((isScanning) => isScanning == false);

    FlutterBluePlus.cancelWhenScanComplete(_scanSubscription!);
    _scanSubscription = null;
  }

  @override
  void dispose() {
    _scanSubscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _scanResults.isEmpty
          ? const Center(child: Text('スキャン結果はありません'))
          : ListView.builder(
        itemCount: _scanResults.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(_scanResults[index]),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _startScan,
        tooltip: 'BLEスキャン',
        child: const Icon(Icons.search),
      ),
    );
  }
}

スキャン結果

アプリをビルドして Androidスマホ上で動かします。

画面右下のボタンを押下するとスキャンが始まり、冒頭の記事でも扱っていた micro:bit もスキャン結果の中に出てきました。

おわりに

とりあえず、flutter_blue_plus を使った BLEスキャンの実装を試せました。

最終的にやりたいことは、特定のデバイスに接続して、そのデバイスと Flutterアプリとの間で通信をさせることなので、その実装も試していければと思います。

その他

スキャン用の処理が書かれた部分のリンクで、「Common Problems」というものがあって気になったので、(いつか使う時があるかもしれないのもあり)メモしておきます。

●flutter_blue_plus | Flutter package
 https://pub.dev/packages/flutter_blue_plus#common-problems

image.png

【追記】 対象の絞り込みを行うもの

その後、「デバイス名に特定の文字列を含むもののみを表示する」という処理を加えたものも作ってみました。

●flutter_blue_plus を使った Flutter での BLEスキャン実装で表示するものをフィルタする - Qiita
 https://qiita.com/youtoy/items/0247179d4065c8d69d19

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?