mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 22:09:06 +00:00
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
This commit is contained in:
@@ -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));
|
||||
final completer = Completer<Steps?>();
|
||||
futures.add(completer.future);
|
||||
|
||||
pd.PedometerHelper.startPedometerWithPort_pedometer_start_end_(
|
||||
helpLib,
|
||||
nativePort,
|
||||
client,
|
||||
start,
|
||||
end,
|
||||
);
|
||||
// Handle the data received from native side.
|
||||
futures.add(receivePort.first);
|
||||
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,15 +7,16 @@ 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 app’s Info.plist file
|
||||
|
||||
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;
|
||||
// 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];
|
||||
}
|
||||
|
||||
|
||||
@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);
|
||||
}
|
||||
}];
|
||||
}
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user