Flutter蓝牙信标检测插件beacon_flutter的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter蓝牙信标检测插件beacon_flutter的使用

简介

Beacon Flutter Plugin 是一个用于在Flutter中实现Tezos钱包与去中心化应用(dApps)之间通信的插件。该插件实现了 tzip-10 标准,支持iOS和Android平台。

平台支持

平台 支持
Android ✔️
iOS ✔️
MacOS
Web
Linux
Windows

使用步骤

依赖添加

在你的 pubspec.yaml 文件中添加以下依赖:

dependencies:
  beacon_flutter: latest

然后运行:

flutter pub get

导入包

在Dart代码中导入该插件:

import 'package:beacon_flutter/beacon_flutter.dart';

iOS设置

需要iOS 14及以上版本,因为Beacon SDK需要这些版本的支持。

Android设置

创建一个新的文件 proguard-rules.pro 在app目录下,并添加以下内容:

-keep class co.altme.alt.me.altme.** { *; } // Add your id
-keep class it.airgap.beaconsdk.** { *; }  
-keep class com.sun.jna.** { *; }
-keep class * implements com.sun.jna.** { *; }

# Keep `Companion` object fields of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
    static <1>$Companion Companion;
}

# Keep `serializer()` on companion objects (both default and named) of serializable classes.
-if @kotlinx.serialization.Serializable class ** {
    static **$* *;
}
-keepclassmembers class <2>$<3> {
    kotlinx.serialization.KSerializer serializer(...);
}

# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
    public static ** INSTANCE;
}
-keepclassmembers class <1> {
    public static <1> INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}

# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault

修改 build.gradle 文件中的 release 构建类型:

buildTypes {
    release {
        ...
        useProguard true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        ...
    }
}

示例Demo

下面是一个完整的示例demo,展示了如何使用 beacon_flutter 插件进行dApp和钱包之间的配对、发送响应等操作:

import 'dart:convert';
import 'package:beacon_flutter/beacon_flutter.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Beacon Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Beacon Demo Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _beaconPlugin = Beacon();

  final TextEditingController pairingRequestController = TextEditingController(
      text: "GUsRsanpcLYPUk683gtFy4LJ6GAKP5BRe3jonDEQvXdCiYWnEGBq887akzYcKMbBnejMZMcFERAqzm8qqEHDnfPLyfNdjYVZ4qdGazMxu9X8iYeRSH7XUfCfoTfZMmnuQi5rccVEeM3JPRqZ1gUcyiuYQGBrEjyWH85JpV39GBcyw6Tkfiyauf2cUp4CYQqbbdiVRb5yLU3iogNXKn5wWKDBXj5HAHki7c12HgQvRqqiFJwsSPuv3Q8akazJkhX7adSuqEnvxo5LE15BdqM5GgXDic4ReSy3UTGNQbi3L2VXqb2yeiCfv5t1WAbQB1BB1NxT788yVRoS");

  bool hasPeers = false;

  String value = '';

  [@override](/user/override)
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      startBeacon();
    });
  }

  startBeacon() async {
    final Map response = await _beaconPlugin.startBeacon(walletName: "Altme Wallet");
    setState(() {
      hasPeers = json.decode(response['success'].toString());
    });
    getBeaconResponse();
  }

  void getBeaconResponse() {
    _beaconPlugin.getBeaconResponse().listen(
      (data) {
        setState(() {
          value = data.toString();
        });
      },
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Beacon Demo'),
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: <Widget>[
              Container(
                alignment: Alignment.centerLeft,
                child: const Text('Pairing Request: '),
              ),
              TextField(
                controller: pairingRequestController,
                maxLines: 10,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  ElevatedButton(
                    onPressed: !hasPeers
                        ? null
                        : () async {
                            final Map response = await _beaconPlugin.removePeers();

                            setState(() {
                              bool success = json.decode(response['success'].toString());
                              hasPeers = !success;
                            });

                            if (!hasPeers) {
                              ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                                content: Text('Successfully disconnected.'),
                              ));
                            }
                          },
                    child: const Text('Unpair'),
                  ),
                  ElevatedButton(
                    onPressed: hasPeers
                        ? null
                        : () async {
                            final Map response = await _beaconPlugin.pair(
                              pairingRequest: pairingRequestController.text,
                            );

                            setState(() {
                              bool success = json.decode(response['success'].toString());
                              hasPeers = success;
                            });

                            if (hasPeers) {
                              ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                                content: Text('Successfully paired.'),
                              ));
                            } else {
                              ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                                content: Text('Failed to pair.'),
                              ));
                            }
                          },
                    child: const Text('Pair'),
                  ),
                ],
              ),
              Container(
                alignment: Alignment.centerRight,
                child: ElevatedButton(
                  onPressed: value.isEmpty
                      ? null
                      : () async {
                          setState(() {
                            value = '';
                          });
                          await _beaconPlugin.respondExample();
                        },
                  child: const Text('Respond'),
                ),
              ),
              const Divider(),
              const SizedBox(height: 10),
              Container(
                alignment: Alignment.centerLeft,
                child: const Text('Beacon Response: '),
              ),
              SizedBox(
                width: double.infinity,
                child: SelectableText(
                  value,
                  textAlign: TextAlign.left,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter蓝牙信标检测插件beacon_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter蓝牙信标检测插件beacon_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用beacon_flutter插件来检测蓝牙信标的示例代码。这个插件允许你扫描附近的iBeacon、AltBeacon和Eddystone信标。

步骤 1: 添加依赖

首先,你需要在你的pubspec.yaml文件中添加beacon_flutter依赖:

dependencies:
  flutter:
    sdk: flutter
  beacon_flutter: ^0.8.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

步骤 2: 配置权限

在Android和iOS上,你需要添加必要的权限来访问蓝牙。

Android

android/app/src/main/AndroidManifest.xml中添加以下权限:

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

你还需要在android/app/src/main/kotlin/.../MainActivity.kt(或MainActivity.java)中添加对位置权限的请求(如果需要的话):

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        
        // 检查并请求位置权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
        }
    }
}

iOS

ios/Runner/Info.plist中添加以下权限:

<key>NSBluetoothAlwaysUsageDescription</key>
<string>App needs access to bluetooth</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>App needs access to bluetooth</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App needs access to location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>App needs access to location</string>

步骤 3: 使用插件

以下是一个简单的Flutter代码示例,展示如何使用beacon_flutter插件来扫描蓝牙信标:

import 'package:flutter/material.dart';
import 'package:beacon_flutter/beacon_flutter.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Beacon> beacons = [];

  @override
  void initState() {
    super.initState();
    startScanning();
  }

  void startScanning() async {
    BeaconFlutter beaconFlutter = BeaconFlutter();

    beaconFlutter.rangingBeaconsInRegion(
      BeaconRegion(
        identifier: 'my-beacon-region',
        uuid: 'YOUR_BEACON_UUID', // 替换为你的信标UUID
      ),
    ).listen((rangingResult) {
      setState(() {
        beacons = rangingResult.beacons;
      });
    }).onError((error) {
      print("Error scanning for beacons: $error");
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Beacon Scanner'),
        ),
        body: ListView.builder(
          itemCount: beacons.length,
          itemBuilder: (context, index) {
            Beacon beacon = beacons[index];
            return ListTile(
              title: Text('UUID: ${beacon.uuid}'),
              subtitle: Text('Distance: ${beacon.distance.toStringAsFixed(2)} m'),
            );
          },
        ),
      ),
    );
  }
}

注意事项

  1. UUID: 替换代码中的YOUR_BEACON_UUID为你实际使用的信标UUID。
  2. 权限处理: 在实际应用中,你需要更细致地处理权限请求结果,例如当用户拒绝权限时给出提示。
  3. 后台扫描: 在iOS上,后台扫描蓝牙信标需要额外的配置,你可能需要在Info.plist中添加UIBackgroundModes键,并包含bluetooth-central值。

这个示例展示了如何使用beacon_flutter插件扫描并显示附近的蓝牙信标。根据实际需求,你可能需要添加更多的功能和错误处理。

回到顶部