ios - 用于扫描信标的 iOS 上的 Flutter 蓝牙检测
问题描述
我正在开发一个应用程序,我需要扫描 iBeacons。我使用了 beacons_plugin ( https://pub.dev/packages/beacons_plugin ),它在 Android 和 iOS 上运行良好。但自 2.0.0 以来,它不再适用于 iOS。我试图理解为什么,但我无法理解。请问有什么帮助吗?
我的 info.plist :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MiLo</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App needs location permissions to scan nearby beacons.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>App needs location permissions to scan nearby beacons.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>App needs location permissions to scan nearby beacons.</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
我使用插件的小部件:
// All packages needed by the widget
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io' show Platform;
import 'dart:convert';
import 'package:beacons_plugin/beacons_plugin.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_application_1/widgets/beacon_card.dart';
class BeaconDetection extends StatefulWidget {
// Declaration of the variables needed by the widget 1/2
final townId;
final fontsizeValue;
final languageId;
final wordMessageBeforeScan;
final wordButtonLaunchScan;
final wordButtonStopScan;
// Declaration of the variables needed by the widget 2/2
BeaconDetection(
{this.townId,
this.fontsizeValue,
this.languageId,
this.wordMessageBeforeScan,
this.wordButtonLaunchScan,
this.wordButtonStopScan});
@override
_BeaconDetectionState createState() => _BeaconDetectionState();
}
class _BeaconDetectionState extends State<BeaconDetection> {
bool isRunning = false;
String _beaconUuid = '';
double _beaconDistance = 0;
String _beaconDetectedUuid = 'null';
double _beaconDetectedDistance = 0;
final StreamController<String> beaconEventsController =
StreamController<String>.broadcast();
@override
void initState() {
super.initState();
initPlatformState();
}
@override
void dispose() {
beaconEventsController.close();
super.dispose();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
if (Platform.isAndroid) {
// Prominent disclosure
await BeaconsPlugin.setDisclosureDialogMessage(
title: "Need Location Permission",
message: "This app collects location data to work with beacons.");
// Only in case, you want the dialog to be shown again. By Default, dialog will never be shown if permissions are granted.
// await BeaconsPlugin.clearDisclosureDialogShowFlag(false);
}
BeaconsPlugin.listenToBeacons(beaconEventsController);
// Extraction of the name and the uuid of the beacons of the chosen city from the firebase
FirebaseFirestore.instance
.collection('towns/${widget.townId}/beacons')
.snapshots()
.listen((event) {
event.docs.forEach((element) async {
if (element['name'].isNotEmpty == true &&
element['uuid'].isNotEmpty == true &&
element['visibility'] == true) {
await BeaconsPlugin.addRegion(element['name'], element['uuid']);
}
});
});
// When listening the data from beacons detected
beaconEventsController.stream.listen(
(data) {
if (data.isNotEmpty) {
setState(() {
Map _beaconScanned = jsonDecode(data);
_beaconUuid = _beaconScanned['uuid'];
_beaconDistance = double.parse(_beaconScanned['distance']);
});
// print("Beacons DataReceived: " + data);
FirebaseFirestore.instance
.collection('towns/${widget.townId}/beacons')
.where('uuid', isEqualTo: _beaconUuid)
.snapshots()
.listen((event) {
event.docs.forEach((element) {
if (_beaconUuid == element['uuid'] &&
element['visibility'] == true &&
_beaconDistance <= element['distance']) {
print('Beacon: $_beaconUuid | Distance: $_beaconDistance');
_beaconDetectedUuid = _beaconUuid;
_beaconDetectedDistance = _beaconDistance;
}
});
});
}
},
onDone: () {},
onError: (error) {
print("Error: $error");
});
await BeaconsPlugin.runInBackground(
isRunning); // Send 'true' to run in background
if (Platform.isAndroid) {
BeaconsPlugin.channel.setMethodCallHandler((call) async {
if (call.method == 'scannerReady') {
await BeaconsPlugin.startMonitoring();
setState(() {
isRunning = true;
});
}
});
} else if (Platform.isIOS) {
await BeaconsPlugin.startMonitoring();
setState(() {
isRunning = true;
});
}
if (!mounted) return;
}
Widget build(BuildContext context) {
return Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('towns/${widget.townId}/beacons')
.where('uuid', isEqualTo: _beaconDetectedUuid)
.snapshots(),
builder: (ctx, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) // Initialisation state
return Container(
margin: const EdgeInsets.all(10),
height: 314, // Beacon card's size
child: Center(child: CircularProgressIndicator()),
);
if (_beaconDetectedUuid == 'null' &&
isRunning == false) // Before first scan State
return Container(
margin: const EdgeInsets.all(10),
height: 314, // Beacon card's size
child: Center(child: Text(widget.wordMessageBeforeScan)),
);
if (_beaconDetectedUuid == 'null' &&
isRunning == true) // Launch first scan state
return Container(
margin: const EdgeInsets.all(10),
height: 314, // Beacon card's size
child: Center(
child: CircularProgressIndicator(),
),
);
final beacons = snapshot.data!.docs;
return BeaconCard( // When the detection is done => Display the widget 'BeaconCard' with the following data
title: beacons[0]['title'],
monument: beacons[0]['monument'],
image: beacons[0]['image'],
duration: beacons[0]['duration'],
distance: _beaconDetectedDistance,
townId: widget.townId,
uuid: beacons[0]['uuid'],
fontsizeValue: widget.fontsizeValue,
languageId: widget.languageId,
);
}),
isRunning
? FloatingActionButton.extended( // If 'isRunning' is true => Display a button to stop the scan
icon: Icon(Icons.bluetooth_disabled),
label: Text(widget.wordButtonStopScan),
backgroundColor: Colors.red,
onPressed: () async {
await BeaconsPlugin.stopMonitoring();
setState(() {
isRunning = false;
});
},
)
: FloatingActionButton.extended( // If 'isRunning' is false => Display a button to start the scan
icon: Icon(Icons.bluetooth),
label: Text(widget.wordButtonLaunchScan),
backgroundColor: Theme.of(context).primaryColor,
onPressed: () async {
initPlatformState();
await BeaconsPlugin.startMonitoring();
setState(() {
isRunning = true;
_beaconDetectedUuid = 'null';
});
},
),
SizedBox(
height: 16,
)
],
);
}
}
非常感谢
解决方案
推荐阅读
- apache-spark - 由于 PySpark 时间戳,将 Spark 数据帧保存到 Azure Synapse 时出现问题
- java - 保存父对象时,防止休眠自动删除@Transient子对象
- amazon-web-services - 如何允许 kubernetes 中的单个 serviceaccount 使用来自不同集群的角色?
- tensorflow - 在多个音频帧上训练 CNN
- vim - 是否可以将特定标签文件添加到 vim 中的特定窗口/缓冲区?
- django - 有没有办法在开发过程中在移动设备上加载 django 网站?
- azure-api-management - API Management + App Gateway 用于托管面向 Internet 的 API 的用例
- swiftui - SwiftUI Negative Padding Z 顺序
- c++ - 如何使用旧的 stdlib 和 libc 在旧的 linux 发行版中构建 C++17 应用程序?
- flutter - 因此,firebase_core ^0.7.0 与 cloud_firestore ^0.14.0 不兼容