Skip to content

Commit 97208d8

Browse files
authored
Merge pull request #2 from sophisticode/master
PR pauldemarco#919
2 parents 2a12252 + 0d10c02 commit 97208d8

File tree

11 files changed

+239
-75
lines changed

11 files changed

+239
-75
lines changed

android/src/main/java/com/pauldemarco/flutter_blue/FlutterBluePlugin.java

+24
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,24 @@ public void onMethodCall(MethodCall call, Result result) {
627627
break;
628628
}
629629

630+
case "readRssi":
631+
{
632+
String remoteId = (String)call.arguments;
633+
BluetoothGatt gatt;
634+
try {
635+
gatt = locateGatt(remoteId);
636+
if(gatt.readRemoteRssi()) {
637+
result.success(null);
638+
} else {
639+
result.error("readRssi", "gatt.readRemoteRssi returned false", null);
640+
}
641+
} catch(Exception e) {
642+
result.error("readRssi", e.getMessage(), e);
643+
}
644+
645+
break;
646+
}
647+
630648
default:
631649
{
632650
result.notImplemented();
@@ -964,6 +982,12 @@ public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
964982
@Override
965983
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
966984
log(LogLevel.DEBUG, "[onReadRemoteRssi] rssi: " + rssi + " status: " + status);
985+
if(status == BluetoothGatt.GATT_SUCCESS) {
986+
Protos.ReadRssiResult.Builder p = Protos.ReadRssiResult.newBuilder();
987+
p.setRemoteId(gatt.getDevice().getAddress());
988+
p.setRssi(rssi);
989+
invokeMethodUIThread("ReadRssiResult", p.build().toByteArray());
990+
}
967991
}
968992

969993
@Override

example/ios/Podfile

+14-63
Original file line numberDiff line numberDiff line change
@@ -10,78 +10,29 @@ project 'Runner', {
1010
'Release' => :release,
1111
}
1212

13-
def parse_KV_file(file, separator='=')
14-
file_abs_path = File.expand_path(file)
15-
if !File.exists? file_abs_path
16-
return [];
13+
def flutter_root
14+
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15+
unless File.exist?(generated_xcode_build_settings_path)
16+
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
1717
end
18-
generated_key_values = {}
19-
skip_line_start_symbols = ["#", "/"]
20-
File.foreach(file_abs_path) do |line|
21-
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22-
plugin = line.split(pattern=separator)
23-
if plugin.length == 2
24-
podname = plugin[0].strip()
25-
path = plugin[1].strip()
26-
podpath = File.expand_path("#{path}", file_abs_path)
27-
generated_key_values[podname] = podpath
28-
else
29-
puts "Invalid plugin specification: #{line}"
30-
end
31-
end
32-
generated_key_values
33-
end
34-
35-
target 'Runner' do
36-
# Flutter Pod
37-
38-
copied_flutter_dir = File.join(__dir__, 'Flutter')
39-
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
40-
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
41-
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
42-
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
43-
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
44-
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
4518

46-
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
47-
unless File.exist?(generated_xcode_build_settings_path)
48-
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
49-
end
50-
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
51-
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
52-
53-
unless File.exist?(copied_framework_path)
54-
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
55-
end
56-
unless File.exist?(copied_podspec_path)
57-
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
58-
end
19+
File.foreach(generated_xcode_build_settings_path) do |line|
20+
matches = line.match(/FLUTTER_ROOT\=(.*)/)
21+
return matches[1].strip if matches
5922
end
23+
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24+
end
6025

61-
# Keep pod path relative so it can be checked into Podfile.lock.
62-
pod 'Flutter', :path => 'Flutter'
26+
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
6327

64-
# Plugin Pods
28+
flutter_ios_podfile_setup
6529

66-
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
67-
# referring to absolute paths on developers' machines.
68-
system('rm -rf .symlinks')
69-
system('mkdir -p .symlinks/plugins')
70-
plugin_pods = parse_KV_file('../.flutter-plugins')
71-
plugin_pods.each do |name, path|
72-
symlink = File.join('.symlinks', 'plugins', name)
73-
File.symlink(path, symlink)
74-
pod name, :path => File.join(symlink, 'ios')
75-
end
30+
target 'Runner' do
31+
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
7632
end
7733

78-
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
79-
install! 'cocoapods', :disable_input_output_paths => true
80-
8134
post_install do |installer|
8235
installer.pods_project.targets.each do |target|
83-
target.build_configurations.each do |config|
84-
config.build_settings['ENABLE_BITCODE'] = 'NO'
85-
end
36+
flutter_additional_ios_build_settings(target)
8637
end
8738
end

example/ios/Podfile.lock

+3-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
PODS:
2-
- e2e (0.0.1):
3-
- Flutter
42
- Flutter (1.0.0)
53
- flutter_blue (0.0.1):
64
- Flutter
@@ -11,7 +9,6 @@ PODS:
119
- Protobuf (3.11.4)
1210

1311
DEPENDENCIES:
14-
- e2e (from `.symlinks/plugins/e2e/ios`)
1512
- Flutter (from `Flutter`)
1613
- flutter_blue (from `.symlinks/plugins/flutter_blue/ios`)
1714

@@ -20,19 +17,16 @@ SPEC REPOS:
2017
- Protobuf
2118

2219
EXTERNAL SOURCES:
23-
e2e:
24-
:path: ".symlinks/plugins/e2e/ios"
2520
Flutter:
2621
:path: Flutter
2722
flutter_blue:
2823
:path: ".symlinks/plugins/flutter_blue/ios"
2924

3025
SPEC CHECKSUMS:
31-
e2e: 967b9b1fc533b7636a3b7a719f840c27f301fe1f
32-
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
26+
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
3327
flutter_blue: eeb381dc4727a0954dede73515f683865494b370
3428
Protobuf: 176220c526ad8bd09ab1fb40a978eac3fef665f7
3529

36-
PODFILE CHECKSUM: 3dbe063e9c90a5d7c9e4e76e70a821b9e2c1d271
30+
PODFILE CHECKSUM: 8e679eca47255a8ca8067c4c67aab20e64cb974d
3731

38-
COCOAPODS: 1.9.1
32+
COCOAPODS: 1.10.1

example/lib/main.dart

+16-3
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,22 @@ class DeviceScreen extends StatelessWidget {
247247
stream: device.state,
248248
initialData: BluetoothDeviceState.connecting,
249249
builder: (c, snapshot) => ListTile(
250-
leading: (snapshot.data == BluetoothDeviceState.connected)
251-
? Icon(Icons.bluetooth_connected)
252-
: Icon(Icons.bluetooth_disabled),
250+
leading: Column(
251+
mainAxisAlignment: MainAxisAlignment.end,
252+
children: [
253+
Icon(snapshot.data == BluetoothDeviceState.connected
254+
? Icons.bluetooth_connected
255+
: Icons.bluetooth_disabled),
256+
snapshot.data == BluetoothDeviceState.connected
257+
? FutureBuilder<int>(
258+
future: device.readRssi(),
259+
builder: (context, snapshot) {
260+
return Text(snapshot.hasData ? '${snapshot.data}' : '',
261+
style: Theme.of(context).textTheme.caption);
262+
})
263+
: Text('', style: Theme.of(context).textTheme.caption),
264+
],
265+
),
253266
title: Text(
254267
'Device is ${snapshot.data.toString().split('.')[1]}.'),
255268
subtitle: Text('${device.id}'),

ios/Classes/FlutterBluePlugin.m

+16
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
253253
}
254254
} else if([@"requestMtu" isEqualToString:call.method]) {
255255
result([FlutterError errorWithCode:@"requestMtu" message:@"iOS does not allow mtu requests to the peripheral" details:NULL]);
256+
} else if([@"readRssi" isEqualToString:call.method]) {
257+
NSString *remoteId = [call arguments];
258+
@try {
259+
CBPeripheral *peripheral = [self findPeripheral:remoteId];
260+
[peripheral readRSSI];
261+
result(nil);
262+
} @catch(FlutterError *e) {
263+
result(e);
264+
}
256265
} else {
257266
result(FlutterMethodNotImplemented);
258267
}
@@ -538,6 +547,13 @@ - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDesc
538547
[_channel invokeMethod:@"WriteDescriptorResponse" arguments:[self toFlutterData:result]];
539548
}
540549

550+
- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)rssi error:(NSError *)error {
551+
ProtosReadRssiResult *result = [[ProtosReadRssiResult alloc] init];
552+
[result setRemoteId:[peripheral.identifier UUIDString]];
553+
[result setRssi:[rssi intValue]];
554+
[_channel invokeMethod:@"ReadRssiResult" arguments:[self toFlutterData:result]];
555+
}
556+
541557
//
542558
// Proto Helper methods
543559
//

ios/gen/Flutterblue.pbobjc.h

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ios/gen/Flutterblue.pbobjc.m

+56
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/gen/flutterblue.pb.dart

+61
Original file line numberDiff line numberDiff line change
@@ -2186,3 +2186,64 @@ class MtuSizeResponse extends $pb.GeneratedMessage {
21862186
void clearMtu() => clearField(2);
21872187
}
21882188

2189+
class ReadRssiResult extends $pb.GeneratedMessage {
2190+
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ReadRssiResult', createEmptyInstance: create)
2191+
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'remoteId')
2192+
..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rssi', $pb.PbFieldType.O3)
2193+
..hasRequiredFields = false
2194+
;
2195+
2196+
ReadRssiResult._() : super();
2197+
factory ReadRssiResult({
2198+
$core.String? remoteId,
2199+
$core.int? rssi,
2200+
}) {
2201+
final _result = create();
2202+
if (remoteId != null) {
2203+
_result.remoteId = remoteId;
2204+
}
2205+
if (rssi != null) {
2206+
_result.rssi = rssi;
2207+
}
2208+
return _result;
2209+
}
2210+
factory ReadRssiResult.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
2211+
factory ReadRssiResult.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
2212+
@$core.Deprecated(
2213+
'Using this can add significant overhead to your binary. '
2214+
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
2215+
'Will be removed in next major version')
2216+
ReadRssiResult clone() => ReadRssiResult()..mergeFromMessage(this);
2217+
@$core.Deprecated(
2218+
'Using this can add significant overhead to your binary. '
2219+
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
2220+
'Will be removed in next major version')
2221+
ReadRssiResult copyWith(void Function(ReadRssiResult) updates) => super.copyWith((message) => updates(message as ReadRssiResult)) as ReadRssiResult; // ignore: deprecated_member_use
2222+
$pb.BuilderInfo get info_ => _i;
2223+
@$core.pragma('dart2js:noInline')
2224+
static ReadRssiResult create() => ReadRssiResult._();
2225+
ReadRssiResult createEmptyInstance() => create();
2226+
static $pb.PbList<ReadRssiResult> createRepeated() => $pb.PbList<ReadRssiResult>();
2227+
@$core.pragma('dart2js:noInline')
2228+
static ReadRssiResult getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ReadRssiResult>(create);
2229+
static ReadRssiResult? _defaultInstance;
2230+
2231+
@$pb.TagNumber(1)
2232+
$core.String get remoteId => $_getSZ(0);
2233+
@$pb.TagNumber(1)
2234+
set remoteId($core.String v) { $_setString(0, v); }
2235+
@$pb.TagNumber(1)
2236+
$core.bool hasRemoteId() => $_has(0);
2237+
@$pb.TagNumber(1)
2238+
void clearRemoteId() => clearField(1);
2239+
2240+
@$pb.TagNumber(2)
2241+
$core.int get rssi => $_getIZ(1);
2242+
@$pb.TagNumber(2)
2243+
set rssi($core.int v) { $_setSignedInt32(1, v); }
2244+
@$pb.TagNumber(2)
2245+
$core.bool hasRssi() => $_has(1);
2246+
@$pb.TagNumber(2)
2247+
void clearRssi() => clearField(2);
2248+
}
2249+

lib/gen/flutterblue.pbjson.dart

+11
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,14 @@ const MtuSizeResponse$json = const {
415415

416416
/// Descriptor for `MtuSizeResponse`. Decode as a `google.protobuf.DescriptorProto`.
417417
final $typed_data.Uint8List mtuSizeResponseDescriptor = $convert.base64Decode('Cg9NdHVTaXplUmVzcG9uc2USGwoJcmVtb3RlX2lkGAEgASgJUghyZW1vdGVJZBIQCgNtdHUYAiABKA1SA210dQ==');
418+
@$core.Deprecated('Use readRssiResultDescriptor instead')
419+
const ReadRssiResult$json = const {
420+
'1': 'ReadRssiResult',
421+
'2': const [
422+
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
423+
const {'1': 'rssi', '3': 2, '4': 1, '5': 5, '10': 'rssi'},
424+
],
425+
};
426+
427+
/// Descriptor for `ReadRssiResult`. Decode as a `google.protobuf.DescriptorProto`.
428+
final $typed_data.Uint8List readRssiResultDescriptor = $convert.base64Decode('Cg5SZWFkUnNzaVJlc3VsdBIbCglyZW1vdGVfaWQYASABKAlSCHJlbW90ZUlkEhIKBHJzc2kYAiABKAVSBHJzc2k=');

0 commit comments

Comments
 (0)