mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +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:ffi' as ffi;
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:isolate';
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
@@ -73,7 +74,7 @@ class _IOSStepsRepo implements StepsRepo {
|
|||||||
// Create a new NSString with the formatted date and timezone.
|
// Create a new NSString with the formatted date and timezone.
|
||||||
final nString = pd.NSString(lib, "$formattedDate $tz");
|
final nString = pd.NSString(lib, "$formattedDate $tz");
|
||||||
// Convert the NSString to NSDate.
|
// Convert the NSString to NSDate.
|
||||||
return formatter.dateFromString_(nString);
|
return formatter.dateFromString_(nString)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -83,37 +84,35 @@ class _IOSStepsRepo implements StepsRepo {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
final futures = <Future>[];
|
final handlers = [];
|
||||||
|
final futures = <Future<Steps?>>[];
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
|
|
||||||
for (var h = 0; h <= now.hour; h++) {
|
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 start = dateConverter(DateTime(now.year, now.month, now.day, h));
|
||||||
final end = dateConverter(DateTime(now.year, now.month, now.day, h + 1));
|
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_(
|
final handler = helpLib.wrapCallback(
|
||||||
helpLib,
|
pd.ObjCBlock_ffiVoid_CMPedometerData_NSError.listener(lib,
|
||||||
nativePort,
|
(pd.CMPedometerData? result, pd.NSError? error) {
|
||||||
client,
|
if (result != null) {
|
||||||
start,
|
final stepCount = result.numberOfSteps.intValue;
|
||||||
end,
|
final startHour =
|
||||||
);
|
hourFormatter.stringFromDate_(result.startDate).toString();
|
||||||
// Handle the data received from native side.
|
completer.complete(Steps(startHour, stepCount));
|
||||||
futures.add(receivePort.first);
|
} 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 (await Future.wait(futures)).nonNulls.toList();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,18 @@ compiler-opts:
|
|||||||
- "-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks"
|
- "-F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks"
|
||||||
- "-mios-version-min=13.0"
|
- "-mios-version-min=13.0"
|
||||||
exclude-all-by-default: true
|
exclude-all-by-default: true
|
||||||
|
functions:
|
||||||
|
include:
|
||||||
|
- "wrapCallback"
|
||||||
objc-interfaces:
|
objc-interfaces:
|
||||||
include:
|
include:
|
||||||
- "CMPedometer"
|
- "CMPedometer"
|
||||||
- "PedometerHelper"
|
|
||||||
- "NSDate"
|
- "NSDate"
|
||||||
- "NSDateFormatter"
|
- "NSDateFormatter"
|
||||||
headers:
|
headers:
|
||||||
entry-points:
|
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"
|
- "src/pedometerHelper.h"
|
||||||
|
|
||||||
# To use this API, you must include the NSMotionUsageDescription key in your app’s Info.plist file
|
# To use this API, you must include the NSMotionUsageDescription key in your app’s Info.plist file
|
||||||
# and provide a usage description string for this key.
|
# 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/CoreMotion.h>
|
||||||
#import <CoreMotion/CMPedometer.h>
|
#import <CoreMotion/CMPedometer.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <Foundation/NSDate.h>
|
|
||||||
|
|
||||||
#include "dart-sdk/include/dart_api_dl.h"
|
// TODO(https://github.com/dart-lang/native/issues/835): Generate this wrapper
|
||||||
|
// automatically.
|
||||||
@interface PedometerHelper : NSObject
|
CMPedometerHandler wrapCallback(CMPedometerHandler callback);
|
||||||
|
|
||||||
+ (void) startPedometerWithPort: (Dart_Port) sendPort
|
|
||||||
pedometer: (CMPedometer*) pedometer
|
|
||||||
start: (NSDate*) start
|
|
||||||
end: (NSDate*) end;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|||||||
@@ -2,37 +2,11 @@
|
|||||||
#import <CoreMotion/CoreMotion.h>
|
#import <CoreMotion/CoreMotion.h>
|
||||||
#import <CoreMotion/CMPedometer.h>
|
#import <CoreMotion/CMPedometer.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <Foundation/NSDate.h>
|
|
||||||
|
|
||||||
#include "dart-sdk/include/dart_api_dl.h"
|
// TODO(https://github.com/dart-lang/native/issues/835): Generate this wrapper
|
||||||
|
// automatically.
|
||||||
// Need to import the dart headers to get the definitions Dart_CObject
|
CMPedometerHandler wrapCallback(CMPedometerHandler callback) {
|
||||||
#include "dart-sdk/include/dart_api_dl.h"
|
return [^(CMPedometerData *data, NSError *error) {
|
||||||
|
return callback([data retain], [error retain]);
|
||||||
|
} copy];
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|||||||
Reference in New Issue
Block a user