Skip to content

Commit 355c9db

Browse files
committed
feat(ios): platform channels
1 parent b8689d4 commit 355c9db

File tree

6 files changed

+98
-33
lines changed

6 files changed

+98
-33
lines changed

apps/demo/src/modals/modal-flutter.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
import { Observable, EventData, Page } from '@nativescript/core';
2+
import { FlutterChannelType } from '@nativescript/flutter';
23

34
export function shownModally(args: EventData) {
45
const page = <Page>args.object;
56
page.bindingContext = new DemoModel();
67
}
78

8-
export class DemoModel extends Observable {}
9+
export class DemoModel extends Observable {
10+
channel: FlutterChannelType;
11+
12+
constructor() {
13+
super();
14+
this.channel = {
15+
getBatteryLevel: this._getBatteryLevel,
16+
};
17+
}
18+
19+
private _getBatteryLevel() {
20+
UIDevice.currentDevice.batteryMonitoringEnabled = true;
21+
const batteryLevel = (UIDevice.currentDevice.batteryLevel * 100) | 0;
22+
return Promise.resolve(batteryLevel);
23+
}
24+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<Page xmlns="http://schemas.nativescript.org/tns.xsd" shownModally="shownModally" class="page" xmlns:ui="@nativescript/flutter">
22
<GridLayout>
3-
<ui:Flutter width="100%" width="100%"></ui:Flutter>
3+
<ui:Flutter id="countMain" channel="{{channel}}" width="100%" width="100%"></ui:Flutter>
44
</GridLayout>
55
</Page>

apps/demo/src/plugin-demos/flutter.xml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
<ActionBar title="NativeScript + Flutter" icon="" class="action-bar">
55
</ActionBar>
66
</Page.actionBar>
7-
<GridLayout rows="auto,*" class="p-20">
8-
<!-- <Button row="0" text="UIButton tap > Make Flutter Jump" tap="{{ testIt }}" class="btn btn-primary" backgroundColor="orange" margin="20"/>
9-
<ui:Flutter row="1" loaded="{{loadedFlutter}}"></ui:Flutter> -->
10-
<Button row="0" text="Open Flutter" tap="{{ openFlutter }}" class="btn btn-primary"/>
7+
<GridLayout rows="auto,*,auto" class="p-20">
8+
<Button row="0" text="UIButton tap > Make Flutter Jump" tap="{{ testIt }}" class="btn btn-primary" backgroundColor="orange" marginBottom="20" borderRadius="30"/>
9+
10+
<ui:Flutter row="1" id="listMain" loaded="{{loadedFlutter}}" borderRadius="30" borderColor="#efefef" borderWidth="1"></ui:Flutter>
11+
12+
<Button row="2" text="Open Flutter in Modal" tap="{{ openFlutter }}" class="btn btn-primary" backgroundColor="purple" marginTop="20" borderRadius="30"/>
1113
</GridLayout>
1214
</Page>

packages/flutter/common.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
import { ContentView, Observable } from '@nativescript/core';
22

3-
export class FlutterCommon extends ContentView {}
3+
export type FlutterChannelType = { [key: string]: (...args: any[]) => Promise<any> };
4+
5+
export class FlutterCommon extends ContentView {
6+
static invokeResultEvent = 'invokeResultEvent';
7+
channel: FlutterChannelType;
8+
9+
invoke(name: string, args?: Array<any>, callback?: (value?: any) => void) {
10+
// impl specific
11+
}
12+
}

packages/flutter/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { FlutterCommon } from './common';
2+
export { FlutterChannelType } from './common';
23

34
export declare class Flutter extends FlutterCommon {}
45

packages/flutter/index.ios.ts

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,84 @@
1+
import { Utils, ViewBase } from '@nativescript/core';
12
import { FlutterCommon } from './common';
23

3-
let rootFlutterVc: FlutterViewController;
4+
let flutterEngineGroup: FlutterEngineGroup;
45

56
export class Flutter extends FlutterCommon {
67
flutterViewController: FlutterViewController;
8+
platformChannel: FlutterMethodChannel;
79

810
createNativeView() {
9-
this.flutterViewController = FlutterViewController.alloc().initWithEngineNibNameBundle((<any>UIApplication.sharedApplication.delegate)._flutterEngine, null, null);
10-
rootFlutterVc = this.flutterViewController;
11+
if (!this.id) {
12+
throw new Error(`Flutter requires an 'id' property set to match your Dart entry point name.`);
13+
}
14+
const engine = flutterEngineGroup.makeEngineWithEntrypointLibraryURI(this.id, null);
15+
GeneratedPluginRegistrant.registerWithRegistry(engine);
16+
this.flutterViewController = FlutterViewController.alloc().initWithEngineNibNameBundle(engine, null, null);
1117
return this.flutterViewController.view;
1218
}
13-
}
14-
15-
@NativeClass()
16-
class FlutterDelegate extends UIResponder implements UIApplicationDelegate, FlutterAppLifeCycleProvider {
17-
_flutterEngine: FlutterEngine;
18-
_lifeCycleDelegate: FlutterPluginAppLifeCycleDelegate;
1919

20-
static ObjCProtocols = [UIApplicationDelegate, FlutterAppLifeCycleProvider];
21-
22-
init() {
23-
this._lifeCycleDelegate = FlutterPluginAppLifeCycleDelegate.alloc().init();
24-
return this;
20+
initNativeView() {
21+
this.platformChannel = FlutterMethodChannel.methodChannelWithNameBinaryMessenger('nativescript', this.flutterViewController.binaryMessenger);
22+
this.platformChannel.setMethodCallHandler(this._methodCallHandler.bind(this));
2523
}
2624

27-
applicationDidFinishLaunchingWithOptions(application: UIApplication, launchOptions: NSDictionary<string, any>): boolean {
28-
this._flutterEngine = FlutterEngine.alloc().initWithNameProject('io.flutter', null);
29-
this._flutterEngine.runWithEntrypoint(null);
30-
GeneratedPluginRegistrant.registerWithRegistry(this._flutterEngine);
31-
return this._lifeCycleDelegate.applicationDidFinishLaunchingWithOptions(application, launchOptions);
25+
disposeNativeView() {
26+
if (this.platformChannel) {
27+
this.platformChannel.setMethodCallHandler(null);
28+
this.platformChannel = null;
29+
}
3230
}
3331

34-
touchesBeganWithEvent(touches: NSSet<UITouch>, event: _UIEvent): void {
35-
super.touchesBeganWithEvent(touches, event);
32+
invoke(name: string, args?: Array<any>, callback?: (value?: any) => void) {
33+
if (this.platformChannel) {
34+
if (callback) {
35+
this.platformChannel.invokeMethodArgumentsResult(name, args, (result) => {
36+
this.notify({
37+
eventName: Flutter.invokeResultEvent,
38+
object: this,
39+
data: result,
40+
});
41+
});
42+
} else {
43+
this.platformChannel.invokeMethodArguments(name, args);
44+
}
45+
}
3646
}
3747

38-
rootFlutterViewController() {
39-
return rootFlutterVc;
48+
private _methodCallHandler(call: FlutterMethodCall, result: any) {
49+
// console.log('Flutter called NativeScript with:', call.method);
50+
51+
if (this.channel?.[call.method]) {
52+
const methodArgs = call.arguments ? Utils.dataDeserialize(call.arguments) : null;
53+
this.channel[call.method](methodArgs).then((value) => {
54+
// console.log('value:', value);
55+
result(value);
56+
});
57+
}
4058
}
4159

42-
addApplicationLifeCycleDelegate(delegate: NSObject): void {
43-
this._lifeCycleDelegate.addDelegate(delegate);
60+
onLoaded() {
61+
super.onLoaded();
62+
// we do this on onLoaded as the viewControllers are not properly setup on createNativeView
63+
// eslint-disable-next-line @typescript-eslint/no-this-alias
64+
let vcParent: ViewBase = this;
65+
while (vcParent && !vcParent.viewController) {
66+
vcParent = vcParent.parent;
67+
}
68+
const vc = vcParent?.viewController || Utils.ios.getRootViewController();
69+
if (vc) {
70+
vc.addChildViewController(this.flutterViewController);
71+
this.flutterViewController.didMoveToParentViewController(vc);
72+
}
4473
}
4574
}
4675

47-
export { FlutterDelegate };
76+
@NativeClass()
77+
export class FlutterDelegate extends FlutterAppDelegate implements UIApplicationDelegate {
78+
static ObjCProtocols = [UIApplicationDelegate, FlutterAppLifeCycleProvider, FlutterPluginRegistry];
79+
80+
applicationDidFinishLaunchingWithOptions(application: UIApplication, launchOptions: NSDictionary<string, any>): boolean {
81+
flutterEngineGroup = FlutterEngineGroup.alloc().initWithNameProject('ns_flutter_engine', null);
82+
return true;
83+
}
84+
}

0 commit comments

Comments
 (0)