Simplify experimental pedometer example (#2104)

Since ffigen added support for
[`NativeCallable.listener`](https://api.flutter.dev/flutter/dart-ffi/NativeCallable/NativeCallable.listener.html)
to its ObjC bindings, this example can be simplified. We can replace the
`Dart_Port` logic with `ObjCBlock.listener`, which lets us get rid of
most of the native code.

We still need a small bit of native code to `retain` a reference to the
callback's arguments before invoking the listener, otherwise the
arguments may be ref counted and deleted before the Dart side of the
callback is invoked. See https://github.com/dart-lang/native/issues/835
pull/2106/head
Liam Appelbe 7 months ago committed by GitHub
parent e598d6a771
commit f0e6da6d24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:collection';
import 'dart:ffi' as ffi;
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
@ -73,7 +74,7 @@ class _IOSStepsRepo implements StepsRepo {
// Create a new NSString with the formatted date and timezone.
final nString = pd.NSString(lib, "$formattedDate $tz");
// Convert the NSString to NSDate.
return formatter.dateFromString_(nString);
return formatter.dateFromString_(nString)!;
}
@override
@ -83,37 +84,35 @@ class _IOSStepsRepo implements StepsRepo {
return [];
}
final futures = <Future>[];
final handlers = [];
final futures = <Future<Steps?>>[];
final now = DateTime.now();
for (var h = 0; h <= now.hour; h++) {
// Open up a port to receive data from native side.
final receivePort = ReceivePort();
final nativePort = receivePort.sendPort.nativePort;
final start = dateConverter(DateTime(now.year, now.month, now.day, h));
final end = dateConverter(DateTime(now.year, now.month, now.day, h + 1));
pd.PedometerHelper.startPedometerWithPort_pedometer_start_end_(
helpLib,
nativePort,
client,
start,
end,
);
// Handle the data received from native side.
futures.add(receivePort.first);
final completer = Completer<Steps?>();
futures.add(completer.future);
final handler = helpLib.wrapCallback(
pd.ObjCBlock_ffiVoid_CMPedometerData_NSError.listener(lib,
(pd.CMPedometerData? result, pd.NSError? error) {
if (result != null) {
final stepCount = result.numberOfSteps.intValue;
final startHour =
hourFormatter.stringFromDate_(result.startDate).toString();
completer.complete(Steps(startHour, stepCount));
} else {
debugPrint("Query error: ${error?.localizedDescription}");
completer.complete(null);
}
}));
handlers.add(handler);
client.queryPedometerDataFromDate_toDate_withHandler_(
start, end, handler);
}
final data = await Future.wait(futures);
return data.where((e) => e != null).cast<int>().map((address) {
final result = ffi.Pointer<pd.ObjCObject>.fromAddress(address);
final pedometerData =
pd.CMPedometerData.castFromPointer(lib, result, release: true);
final stepCount = pedometerData.numberOfSteps?.intValue ?? 0;
final startHour =
hourFormatter.stringFromDate_(pedometerData.startDate!).toString();
return Steps(startHour, stepCount);
}).toList();
return (await Future.wait(futures)).nonNulls.toList();
}
}

@ -7,17 +7,18 @@ compiler-opts:
- "-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks"
- "-mios-version-min=13.0"
exclude-all-by-default: true
functions:
include:
- "wrapCallback"
objc-interfaces:
include:
- "CMPedometer"
- "PedometerHelper"
- "NSDate"
- "NSDateFormatter"
headers:
entry-points:
- "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/CoreMotion.framework/Headers/CMPedometer.h"
- "src/pedometerHelper.h"
# To use this API, you must include the NSMotionUsageDescription key in your apps Info.plist file
# and provide a usage description string for this key.
# The usage description appears in the prompt that the user must accept the first time the system asks the user to access motion data for your app.
# The usage description appears in the prompt that the user must accept the first time the system asks the user to access motion data for your app.

File diff suppressed because it is too large Load Diff

@ -1,15 +1,7 @@
#import <CoreMotion/CoreMotion.h>
#import <CoreMotion/CMPedometer.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSDate.h>
#include "dart-sdk/include/dart_api_dl.h"
@interface PedometerHelper : NSObject
+ (void) startPedometerWithPort: (Dart_Port) sendPort
pedometer: (CMPedometer*) pedometer
start: (NSDate*) start
end: (NSDate*) end;
@end
// TODO(https://github.com/dart-lang/native/issues/835): Generate this wrapper
// automatically.
CMPedometerHandler wrapCallback(CMPedometerHandler callback);

@ -2,37 +2,11 @@
#import <CoreMotion/CoreMotion.h>
#import <CoreMotion/CMPedometer.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSDate.h>
#include "dart-sdk/include/dart_api_dl.h"
// Need to import the dart headers to get the definitions Dart_CObject
#include "dart-sdk/include/dart_api_dl.h"
// Helper function that takes a pointer to CMPedometer data and converts it to a Dart C Object
static Dart_CObject NSObjectToCObject(CMPedometerData* n) {
Dart_CObject cobj;
cobj.type = Dart_CObject_kInt64;
cobj.value.as_int64 = (int64_t) n;
return cobj;
}
@implementation PedometerHelper
+(void)startPedometerWithPort: (Dart_Port) sendPort pedometer: (CMPedometer*) pedometer start: (NSDate*) start end: (NSDate*) end {
// Start the pedometer
[pedometer queryPedometerDataFromDate:start toDate:end withHandler:^(CMPedometerData *pedometerData, NSError *error) {
if(error == nil){
pedometerData = [pedometerData retain];
Dart_CObject data = NSObjectToCObject(pedometerData);
const bool success = Dart_PostCObject_DL(sendPort, &data);
NSAssert(success, @"Couldn't send to Dart@");
}
else{
NSLog(@"Error:%@", error);
}
}];
// TODO(https://github.com/dart-lang/native/issues/835): Generate this wrapper
// automatically.
CMPedometerHandler wrapCallback(CMPedometerHandler callback) {
return [^(CMPedometerData *data, NSError *error) {
return callback([data retain], [error retain]);
} copy];
}
@end

Loading…
Cancel
Save