Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ description: Demonstrates how to use the flutter_unity_widget plugin.
publish_to: "none" # Remove this line if you wish to publish to pub.dev

environment:
sdk: ">=2.12.0 <4.0.0"
sdk: ">=2.17.0 <4.0.0"
# >=2.17 or higher is needed for pointer_interceptor to work on web with WASM.


dependencies:
cupertino_icons: ^1.0.0
flutter:
sdk: flutter
flutter_unity_widget:
path: ../
pointer_interceptor: ^0.9.3+2
pointer_interceptor: ^0.10.0

dev_dependencies:
flutter_test:
Expand Down
2 changes: 1 addition & 1 deletion lib/flutter_unity_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ library flutter_unity_widget;
export 'src/facade_controller.dart';
export 'src/facade_widget.dart'
if (dart.library.io) 'src/io/unity_widget.dart'
if (dart.library.html) 'src/web/unity_widget.dart';
if (dart.library.js_interop) 'src/web/unity_widget.dart';
export 'src/helpers/events.dart';
export 'src/helpers/misc.dart';
export 'src/helpers/types.dart';
109 changes: 70 additions & 39 deletions lib/src/web/web_unity_widget_controller.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import 'dart:developer';
import 'dart:async';
import 'dart:convert';
import 'dart:html' as html;
import 'dart:js_interop';

import 'package:web/web.dart' as web;
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
Expand All @@ -23,13 +24,16 @@ class UnityWebEvent {
final dynamic data;
}

// use JSON.stringify to turn JS objects into strings which we can json decode.
@JS('JSON.stringify')
external JSString jsonStringify(JSAny value);

class WebUnityWidgetController extends UnityWidgetController {
final WebUnityWidgetState _unityWidgetState;

static Registrar? webRegistrar;

late html.MessageEvent _unityFlutterBiding;
late html.MessageEvent _unityFlutterBidingFn;
late JSFunction _messageListener;

bool unityReady = false;
bool unityPause = true;
Expand Down Expand Up @@ -99,27 +103,52 @@ class WebUnityWidgetController extends UnityWidgetController {

_registerEvents() {
if (kIsWeb) {
html.window.addEventListener('message', (event) {
final raw = (event as html.MessageEvent).data.toString();
// ignore: unnecessary_null_comparison
if (raw == '' || raw == null) return;
if (raw == 'unityReady') {
unityReady = true;
unityPause = false;

_unityStreamController.add(UnityCreatedEvent(0, {}));
return;
}

try {
_processEvents(UnityWebEvent(
name: event.data['name'],
data: event.data['data'],
));
} catch (e) {
log('Unexpected format', error: e);
_messageListener = ((web.Event event) {
if (event is web.MessageEvent) {
final jsData = event.data;
String data = "";

// Handle a raw JS Object [Object object] instead of a json string.
if (jsData is JSObject) {
try {
data = jsonStringify(jsData).toDart;
} catch (e) {
log('Failed to stringify JS object', error: e);
return;
}
}
// this can be either a raw string like "unityReady" or a json string "{\"name\":\"\", ..}"
else if (jsData is JSString) {
data = jsData.toDart;
}

if (data.isNotEmpty) {
if (data == 'unityReady') {
unityReady = true;
unityPause = false;
_unityStreamController.add(UnityCreatedEvent(0, {}));
return;
} else {
try {
final decoded = json.decode(data);
if (decoded is Map<String, dynamic> &&
decoded.containsKey("name") &&
decoded.containsKey("data")) {
_processEvents(UnityWebEvent(
name: decoded['name'],
data: decoded['data'],
));
} else {
log('Unexpected json object', error: data);
}
} catch (e) {
log('Unexpected json object', error: e);
}
}
}
}
});
}).toJS;
web.window.addEventListener('message', _messageListener);
}
}

Expand Down Expand Up @@ -189,11 +218,13 @@ class WebUnityWidgetController extends UnityWidgetController {

void callUnityFn({required String fnName}) {
if (kIsWeb) {
_unityFlutterBidingFn = html.MessageEvent(
final web.MessageEvent _unityFlutterBidingFn = web.MessageEvent(
'unityFlutterBidingFnCal',
data: fnName,
web.MessageEventInit(
data: fnName.toJS,
),
);
html.window.dispatchEvent(_unityFlutterBidingFn);
web.window.dispatchEvent(_unityFlutterBidingFn);
}
}

Expand All @@ -203,27 +234,29 @@ class WebUnityWidgetController extends UnityWidgetController {
required String message,
}) {
if (kIsWeb) {
_unityFlutterBiding = html.MessageEvent(
final web.MessageEvent _unityFlutterBiding = web.MessageEvent(
'unityFlutterBiding',
data: json.encode({
"gameObject": gameObject,
"methodName": methodName,
"message": message,
}),
web.MessageEventInit(
data: json.encode({
"gameObject": gameObject,
"methodName": methodName,
"message": message,
}).toJS,
),
);
html.window.dispatchEvent(_unityFlutterBiding);
web.window.dispatchEvent(_unityFlutterBiding);
postProcess();
}
}

/// This method makes sure Unity has been refreshed and is ready to receive further messages.
void postProcess() {
html.Element? frame = html.document
web.Element? frame = web.window.document
.querySelector('flt-platform-view')
?.querySelector('iframe');

if (frame != null) {
(frame as html.IFrameElement).focus();
if (frame != null && frame is web.HTMLIFrameElement) {
frame.focus();
}
}

Expand Down Expand Up @@ -292,9 +325,7 @@ class WebUnityWidgetController extends UnityWidgetController {
void dispose() {
_cancelSubscriptions();
if (kIsWeb) {
html.window.removeEventListener('message', (_) {});
html.window.removeEventListener('unityFlutterBiding', (event) {});
html.window.removeEventListener('unityFlutterBidingFnCal', (event) {});
web.window.removeEventListener('message', _messageListener);
}
}
}
17 changes: 12 additions & 5 deletions lib/src/web/web_unity_widget_view.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
// ignore: unused_import
import 'package:webview_flutter_web/webview_flutter_web.dart'; // used indirectly through webview_flutter_platform_interface

class WebUnityWidgetView extends StatefulWidget {
const WebUnityWidgetView({
Expand All @@ -16,9 +18,12 @@ class WebUnityWidgetView extends StatefulWidget {
}

class _WebUnityWidgetViewState extends State<WebUnityWidgetView> {
final WebViewController _controller = WebViewController()
..loadRequest(
Uri.parse('${_getBasePath()}/UnityLibrary/index.html'),
final PlatformWebViewController _controller = PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
)..loadRequest(
LoadRequestParams(
uri: Uri.parse('${_getBasePath()}/UnityLibrary/index.html'),
),
);

@override
Expand All @@ -34,7 +39,9 @@ class _WebUnityWidgetViewState extends State<WebUnityWidgetView> {

@override
Widget build(BuildContext context) {
return WebViewWidget(controller: _controller);
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: _controller),
).build(context);
}

static String _getBasePath() {
Expand Down
9 changes: 5 additions & 4 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ version: 2022.2.1
homepage: https://github.com/juicycleff/flutter-unity-view-widget/tree/master

environment:
sdk: ">=2.16.0 <4.0.0"
flutter: ">=3.3.0"
sdk: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"

dependencies:
flutter:
Expand All @@ -19,8 +19,9 @@ dependencies:
flutter_plugin_android_lifecycle: ^2.0.7
stream_transform: ^2.0.0
plugin_platform_interface: ^2.1.2
webview_flutter: ^4.0.0
webview_flutter_web: ^0.2.2
webview_flutter_web: ^0.2.2+4
webview_flutter_platform_interface: ^2.0.0
web: '>=0.3.0 <2.0.0' # Needs to resolve to >=0.5.0 to use WebAssembly (WASM).
# ffi: ^1.2.1 // required for windows support

dev_dependencies:
Expand Down