mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
[fp-rs] Invoking Rust code from Dart, retrieving stream of incoming bluetooth advertisements.
This commit is contained in:
@@ -9,7 +9,11 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
abstract class Rust {
|
||||
Future<String> hello({dynamic hint});
|
||||
Future<void> init({dynamic hint});
|
||||
|
||||
FlutterRustBridgeTaskConstMeta get kHelloConstMeta;
|
||||
FlutterRustBridgeTaskConstMeta get kInitConstMeta;
|
||||
|
||||
Stream<String> eventStream({dynamic hint});
|
||||
|
||||
FlutterRustBridgeTaskConstMeta get kEventStreamConstMeta;
|
||||
}
|
||||
|
||||
@@ -25,19 +25,35 @@ class RustImpl implements Rust {
|
||||
factory RustImpl.wasm(FutureOr<WasmModule> module) =>
|
||||
RustImpl(module as ExternalLibrary);
|
||||
RustImpl.raw(this._platform);
|
||||
Future<String> hello({dynamic hint}) {
|
||||
Future<void> init({dynamic hint}) {
|
||||
return _platform.executeNormal(FlutterRustBridgeTask(
|
||||
callFfi: (port_) => _platform.inner.wire_hello(port_),
|
||||
parseSuccessData: _wire2api_String,
|
||||
constMeta: kHelloConstMeta,
|
||||
callFfi: (port_) => _platform.inner.wire_init(port_),
|
||||
parseSuccessData: _wire2api_unit,
|
||||
constMeta: kInitConstMeta,
|
||||
argValues: [],
|
||||
hint: hint,
|
||||
));
|
||||
}
|
||||
|
||||
FlutterRustBridgeTaskConstMeta get kHelloConstMeta =>
|
||||
FlutterRustBridgeTaskConstMeta get kInitConstMeta =>
|
||||
const FlutterRustBridgeTaskConstMeta(
|
||||
debugName: "hello",
|
||||
debugName: "init",
|
||||
argNames: [],
|
||||
);
|
||||
|
||||
Stream<String> eventStream({dynamic hint}) {
|
||||
return _platform.executeStream(FlutterRustBridgeTask(
|
||||
callFfi: (port_) => _platform.inner.wire_event_stream(port_),
|
||||
parseSuccessData: _wire2api_String,
|
||||
constMeta: kEventStreamConstMeta,
|
||||
argValues: [],
|
||||
hint: hint,
|
||||
));
|
||||
}
|
||||
|
||||
FlutterRustBridgeTaskConstMeta get kEventStreamConstMeta =>
|
||||
const FlutterRustBridgeTaskConstMeta(
|
||||
debugName: "event_stream",
|
||||
argNames: [],
|
||||
);
|
||||
|
||||
@@ -57,6 +73,10 @@ class RustImpl implements Rust {
|
||||
Uint8List _wire2api_uint_8_list(dynamic raw) {
|
||||
return raw as Uint8List;
|
||||
}
|
||||
|
||||
void _wire2api_unit(dynamic raw) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Section: api2wire
|
||||
@@ -168,17 +188,31 @@ class RustWire implements FlutterRustBridgeWireBase {
|
||||
late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr
|
||||
.asFunction<int Function(ffi.Pointer<ffi.Void>)>();
|
||||
|
||||
void wire_hello(
|
||||
void wire_init(
|
||||
int port_,
|
||||
) {
|
||||
return _wire_hello(
|
||||
return _wire_init(
|
||||
port_,
|
||||
);
|
||||
}
|
||||
|
||||
late final _wire_helloPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>('wire_hello');
|
||||
late final _wire_hello = _wire_helloPtr.asFunction<void Function(int)>();
|
||||
late final _wire_initPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>('wire_init');
|
||||
late final _wire_init = _wire_initPtr.asFunction<void Function(int)>();
|
||||
|
||||
void wire_event_stream(
|
||||
int port_,
|
||||
) {
|
||||
return _wire_event_stream(
|
||||
port_,
|
||||
);
|
||||
}
|
||||
|
||||
late final _wire_event_streamPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
|
||||
'wire_event_stream');
|
||||
late final _wire_event_stream =
|
||||
_wire_event_streamPtr.asFunction<void Function(int)>();
|
||||
|
||||
void free_WireSyncReturn(
|
||||
WireSyncReturn ptr,
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:demo/rust.dart';
|
||||
|
||||
void main() {
|
||||
api.init();
|
||||
runApp(const FastPairApp());
|
||||
}
|
||||
|
||||
@@ -23,22 +24,19 @@ class HomePage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Fast Pair"),
|
||||
appBar: AppBar(title: const Text("Fast Pair")),
|
||||
body: Center(
|
||||
child: StreamBuilder(
|
||||
// All Rust functions are called as Future's
|
||||
stream: api.eventStream(), // The Rust function we are calling.
|
||||
builder: (context, data) {
|
||||
if (data.hasData) {
|
||||
return Text(data.data!); // The string to display
|
||||
}
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
},
|
||||
),
|
||||
body: Center(
|
||||
child: FutureBuilder(
|
||||
// All Rust functions are called as Future's
|
||||
future: api.hello(), // The Rust function we are calling.
|
||||
builder: (context, data) {
|
||||
if (data.hasData) {
|
||||
return Text(data.data!); // The string to display
|
||||
}
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
@@ -9,4 +9,8 @@ edition = "2021"
|
||||
crate-type = ["lib", "cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bluetooth = { version = "0.1", path = "../../bluetooth" }
|
||||
flutter_rust_bridge = "1"
|
||||
futures = { version = "0.3", features = ["executor"] }
|
||||
tracing = "0.1.37"
|
||||
|
||||
@@ -1,3 +1,57 @@
|
||||
pub fn hello() -> String {
|
||||
String::from("Rust says hi!")
|
||||
use std::sync::RwLock;
|
||||
|
||||
use bluetooth::{
|
||||
api::{BleAdapter, BleDevice},
|
||||
BleDataTypeId, Platform,
|
||||
};
|
||||
use flutter_rust_bridge::StreamSink;
|
||||
use futures::executor;
|
||||
use tracing::info;
|
||||
|
||||
// Sends a device name to Flutter via `StreamSink` FFI layer.
|
||||
static NAME_STREAM: RwLock<Option<StreamSink<String>>> = RwLock::new(None);
|
||||
|
||||
/// Sets up initial constructs and infinitely polls for advertisements.
|
||||
pub fn init() {
|
||||
let run = async {
|
||||
info!("start making adapter");
|
||||
|
||||
let mut adapter = Platform::default_adapter().await.unwrap();
|
||||
adapter.start_scan().unwrap();
|
||||
|
||||
let datatype_selector = vec![BleDataTypeId::ServiceData16BitUuid];
|
||||
loop {
|
||||
let advertisement = adapter
|
||||
.next_advertisement(Some(&datatype_selector))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
for service_data in advertisement.service_data_16bit_uuid().unwrap() {
|
||||
let uuid = service_data.uuid();
|
||||
// This is a Fast Pair device.
|
||||
if uuid == 0x2cfe {
|
||||
let addr = advertisement.address();
|
||||
let ble_device = Platform::new_ble_device(addr).await.unwrap();
|
||||
let name = ble_device.name().unwrap();
|
||||
info!("device: {}", name);
|
||||
|
||||
match NAME_STREAM.read().unwrap().as_ref() {
|
||||
Some(s) => {
|
||||
s.add(name);
|
||||
}
|
||||
None => info!("Stream is None"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
executor::block_on(run)
|
||||
}
|
||||
|
||||
/// Sets up `StreamSink` for Dart-Rust FFI.
|
||||
pub fn event_stream(s: StreamSink<String>) -> Result<(), anyhow::Error> {
|
||||
let mut stream = NAME_STREAM.write().unwrap();
|
||||
*stream = Some(s);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,8 +2,13 @@ use super::*;
|
||||
// Section: wire functions
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wire_hello(port_: i64) {
|
||||
wire_hello_impl(port_)
|
||||
pub extern "C" fn wire_init(port_: i64) {
|
||||
wire_init_impl(port_)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wire_event_stream(port_: i64) {
|
||||
wire_event_stream_impl(port_)
|
||||
}
|
||||
|
||||
// Section: allocate functions
|
||||
|
||||
@@ -22,14 +22,24 @@ use std::sync::Arc;
|
||||
|
||||
// Section: wire functions
|
||||
|
||||
fn wire_hello_impl(port_: MessagePort) {
|
||||
FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, String>(
|
||||
fn wire_init_impl(port_: MessagePort) {
|
||||
FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>(
|
||||
WrapInfo {
|
||||
debug_name: "hello",
|
||||
debug_name: "init",
|
||||
port: Some(port_),
|
||||
mode: FfiCallMode::Normal,
|
||||
},
|
||||
move || move |task_callback| Ok(hello()),
|
||||
move || move |task_callback| Ok(init()),
|
||||
)
|
||||
}
|
||||
fn wire_event_stream_impl(port_: MessagePort) {
|
||||
FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, ()>(
|
||||
WrapInfo {
|
||||
debug_name: "event_stream",
|
||||
port: Some(port_),
|
||||
mode: FfiCallMode::Stream,
|
||||
},
|
||||
move || move |task_callback| event_stream(task_callback.stream_sink::<_, String>()),
|
||||
)
|
||||
}
|
||||
// Section: wrapper structs
|
||||
|
||||
Reference in New Issue
Block a user