Skip to content

Commit

Permalink
fix: [native] Fix errors when hot restarted (#86)
Browse files Browse the repository at this point in the history
* fix: [native] Fix errors when hot restarted
  • Loading branch information
littleGnAl authored Sep 13, 2023
1 parent 1d5d8f9 commit ab6260e
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 21 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,14 @@ jobs:
flutter-version: '3.10.0' # Run the latest version
cache: true
- name: windows integration test
shell: bash
run: |
flutter packages get
flutter test integration_test -d windows
# It's a little tricky that you should run integration test one by one on flutter macOS/Windows
for filename in integration_test/*.dart; do
flutter test $filename -d windows
done
working-directory: example

integration_test_ios:
Expand Down Expand Up @@ -274,7 +279,11 @@ jobs:
- name: run macos integration test
run: |
flutter packages get
flutter test integration_test/iris_event_smoke_test.dart -d macos
# It's a little tricky that you should run integration test one by one on flutter macOS/Windows
for filename in integration_test/*.dart; do
flutter test $filename -d macos
done
working-directory: example

integration_test_android:
Expand Down
25 changes: 15 additions & 10 deletions example/integration_test/iris_event_smoke_test.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import 'dart:isolate';

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:iris_method_channel/src/platform/io/iris_event_io.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('IrisEvent smoke test', (tester) async {
await tester.pumpAndSettle();
testWidgets(
'IrisEvent smoke test',
(tester) async {
await tester.pumpWidget(Container());

IrisEventIO irisEvent = IrisEventIO();
irisEvent.initialize();
final testPort = ReceivePort();
irisEvent.registerEventHandler(testPort.sendPort);
irisEvent.unregisterEventHandler(testPort.sendPort);
irisEvent.onEventPtr;
irisEvent.dispose();
});
IrisEventIO irisEvent = IrisEventIO();
irisEvent.initialize();
final testPort = ReceivePort();
irisEvent.registerEventHandler(testPort.sendPort);
irisEvent.unregisterEventHandler(testPort.sendPort);
irisEvent.onEventPtr;
irisEvent.dispose();
},
timeout: const Timeout(Duration(minutes: 10)),
);
}
94 changes: 94 additions & 0 deletions example/integration_test/iris_method_channel_smoke_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import 'dart:isolate';
import 'dart:ffi' as ffi;

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:iris_method_channel/iris_method_channel.dart';
import 'package:iris_method_channel/src/platform/io/iris_method_channel_internal_io.dart';

class _FakeNativeBindingDelegate extends PlatformBindingsDelegateInterface {
_FakeNativeBindingDelegate();

@override
int callApi(
IrisMethodCall methodCall,
IrisApiEngineHandle apiEnginePtr,
IrisApiParamHandle param,
) {
return 0;
}

@override
IrisEventHandlerHandle createIrisEventHandler(
IrisCEventHandlerHandle eventHandler,
) {
return IrisEventHandlerHandle(ffi.Pointer<ffi.Void>.fromAddress(123456));
}

@override
CreateApiEngineResult createApiEngine(List<Object> args) {
return CreateApiEngineResult(
IrisApiEngineHandle(ffi.Pointer<ffi.Void>.fromAddress(100)),
extraData: <String, Object>{'extra_handle': 1000},
);
}

@override
void destroyIrisEventHandler(
IrisEventHandlerHandle handler,
) {}

@override
void destroyNativeApiEngine(IrisApiEngineHandle apiEnginePtr) {}

@override
void initialize() {}

@override
Future<CallApiResult> callApiAsync(IrisMethodCall methodCall,
IrisApiEngineHandle apiEnginePtr, IrisApiParamHandle param) async {
return CallApiResult(irisReturnCode: 0, data: {});
}
}

class _FakeNativeBindingDelegateProvider extends PlatformBindingsProvider {
_FakeNativeBindingDelegateProvider(this.nativeBindingDelegate);

final PlatformBindingsDelegateInterface nativeBindingDelegate;

@override
PlatformBindingsDelegateInterface provideNativeBindingDelegate() {
return nativeBindingDelegate;
}
}

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets(
'IrisMethodChannel should call hot restart listener',
(tester) async {
await tester.pumpWidget(Container());

final irisMethodChannel = IrisMethodChannel(
_FakeNativeBindingDelegateProvider(_FakeNativeBindingDelegate()));
await irisMethodChannel.initilize([]);

bool hotRestartListenerCalled = false;
irisMethodChannel.addHotRestartListener((message) {
hotRestartListenerCalled = true;
});

(irisMethodChannel.getIrisMethodChannelInternal()
as IrisMethodChannelInternalIO)
.workerIsolate
.kill(priority: Isolate.immediate);
// Delayed 2 seconds to ensure `irisMethodChannel.workerIsolate.kill` done
await Future.delayed(const Duration(seconds: 2));

expect(hotRestartListenerCalled, true);
},
timeout: const Timeout(Duration(minutes: 10)),
);
}
4 changes: 2 additions & 2 deletions example/test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ void main() {
// Verify that platform version is retrieved.
expect(
find.byWidgetPredicate(
(Widget widget) => widget is Text &&
widget.data!.startsWith('Running on:'),
(Widget widget) =>
widget is Text && widget.data!.startsWith('Running on:'),
),
findsOneWidget,
);
Expand Down
12 changes: 7 additions & 5 deletions lib/src/platform/io/iris_method_channel_internal_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,16 @@ class _HotRestartFinalizer {
nativeBindingDelegate.initialize();

nativeBindingDelegate.destroyNativeApiEngine(IrisApiEngineHandle(
ffi.Pointer.fromAddress(_debugIrisApiEngineNativeHandle!)));
ffi.Pointer<ffi.Void>.fromAddress(_debugIrisApiEngineNativeHandle!)));

calloc.free(ffi.Pointer.fromAddress(_debugIrisCEventHandlerNativeHandle!));
calloc.free(ffi.Pointer<ffi.Void>.fromAddress(
_debugIrisCEventHandlerNativeHandle!));
nativeBindingDelegate.destroyIrisEventHandler(IrisEventHandlerHandle(
ffi.Pointer.fromAddress(_debugIrisEventHandlerNativeHandle!)));
ffi.Pointer<ffi.Void>.fromAddress(
_debugIrisEventHandlerNativeHandle!)));

assert(provider.provideIrisEvent() != null);
final irisEvent = provider.provideIrisEvent()! as IrisEventIO;
final irisEvent =
(provider.provideIrisEvent() ?? IrisEventIO()) as IrisEventIO;
irisEvent.dispose();

_onExitSubscription?.cancel();
Expand Down
2 changes: 1 addition & 1 deletion lib/src/platform/utils_expect.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:typed_data';

/// Stub function for translate the int ptr to the [Uint8List].
/// Stub function for translate the int ptr to the [Uint8List].
/// See implementation:
/// io: `io/utils_actual_io.dart`
/// web: `web/utils_actual_web.dart`(Empty implementation)
Expand Down
2 changes: 1 addition & 1 deletion test/platform/platform_cases.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export 'platform_cases_expect.dart'
if (dart.library.io) 'platform_cases_actual_io.dart'
if (dart.library.io) 'platform_cases_actual_io.dart'
if (dart.library.html) 'platform_cases_actual_web.dart';

0 comments on commit ab6260e

Please sign in to comment.