Refact. Build flutter web (#7472)

* Refact. Build flutter web

Signed-off-by: fufesou <shuanglongchen@yeah.net>

* Refact. Flutter web, wrap Platform.xx

Signed-off-by: fufesou <shuanglongchen@yeah.net>

---------

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2024-03-22 13:16:37 +08:00 committed by GitHub
parent 285e298a8b
commit 9558974080
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 1625 additions and 54 deletions

1
flutter/.gitignore vendored
View File

@ -32,7 +32,6 @@
/build/ /build/
# Web related # Web related
lib/generated_plugin_registrant.dart
# Symbolication related # Symbolication related
app.*.symbols app.*.symbols

View File

@ -1,12 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:ffi' hide Size;
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:back_button_interceptor/back_button_interceptor.dart'; import 'package:back_button_interceptor/back_button_interceptor.dart';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -25,7 +23,6 @@ import 'package:get/get.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:win32/win32.dart' as win32;
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import 'package:window_size/window_size.dart' as window_size; import 'package:window_size/window_size.dart' as window_size;
@ -37,16 +34,24 @@ import 'models/input_model.dart';
import 'models/model.dart'; import 'models/model.dart';
import 'models/platform_model.dart'; import 'models/platform_model.dart';
import 'package:flutter_hbb/native/win32.dart'
if (dart.library.html) 'package:flutter_hbb/web/win32.dart';
import 'package:flutter_hbb/native/common.dart'
if (dart.library.html) 'package:flutter_hbb/web/common.dart';
final globalKey = GlobalKey<NavigatorState>(); final globalKey = GlobalKey<NavigatorState>();
final navigationBarKey = GlobalKey(); final navigationBarKey = GlobalKey();
final isAndroid = Platform.isAndroid; final isAndroid = isAndroid_;
final isIOS = Platform.isIOS; final isIOS = isIOS_;
final isDesktop = Platform.isWindows || Platform.isMacOS || Platform.isLinux; final isWindows = isWindows_;
var isWeb = false; final isMacOS = isMacOS_;
final isLinux = isLinux_;
final isDesktop = isDesktop_;
final isWeb = isWeb_;
var isWebDesktop = false; var isWebDesktop = false;
var isMobile = isAndroid || isIOS; var isMobile = isAndroid || isIOS;
var version = ""; var version = '';
int androidVersion = 0; int androidVersion = 0;
/// only available for Windows target /// only available for Windows target
@ -2317,35 +2322,7 @@ WindowsTarget getWindowsTarget(int buildNumber) {
/// [Note] /// [Note]
/// Please use this function wrapped with `Platform.isWindows`. /// Please use this function wrapped with `Platform.isWindows`.
int getWindowsTargetBuildNumber() { int getWindowsTargetBuildNumber() {
final rtlGetVersion = DynamicLibrary.open('ntdll.dll').lookupFunction< return getWindowsTargetBuildNumber_();
Void Function(Pointer<win32.OSVERSIONINFOEX>),
void Function(Pointer<win32.OSVERSIONINFOEX>)>('RtlGetVersion');
final osVersionInfo = getOSVERSIONINFOEXPointer();
rtlGetVersion(osVersionInfo);
int buildNumber = osVersionInfo.ref.dwBuildNumber;
calloc.free(osVersionInfo);
return buildNumber;
}
/// Get Windows OS version pointer
///
/// [Note]
/// Please use this function wrapped with `Platform.isWindows`.
Pointer<win32.OSVERSIONINFOEX> getOSVERSIONINFOEXPointer() {
final pointer = calloc<win32.OSVERSIONINFOEX>();
pointer.ref
..dwOSVersionInfoSize = sizeOf<win32.OSVERSIONINFOEX>()
..dwBuildNumber = 0
..dwMajorVersion = 0
..dwMinorVersion = 0
..dwPlatformId = 0
..szCSDVersion = ''
..wServicePackMajor = 0
..wServicePackMinor = 0
..wSuiteMask = 0
..wProductType = 0
..wReserved = 0;
return pointer;
} }
/// Indicating we need to use compatible ui mode. /// Indicating we need to use compatible ui mode.

View File

@ -14,21 +14,21 @@ import 'package:flutter_hbb/desktop/screen/desktop_port_forward_screen.dart';
import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart'; import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart';
import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart';
import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/models/state_model.dart';
import 'package:flutter_hbb/plugin/handlers.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
// import 'package:window_manager/window_manager.dart';
import 'common.dart'; import 'common.dart';
import 'consts.dart'; import 'consts.dart';
import 'mobile/pages/home_page.dart'; import 'mobile/pages/home_page.dart';
import 'mobile/pages/server_page.dart'; import 'mobile/pages/server_page.dart';
import 'models/platform_model.dart'; import 'models/platform_model.dart';
import 'package:flutter_hbb/plugin/handlers.dart'
if (dart.library.html) 'package:flutter_hbb/web/plugin/handlers.dart';
/// Basic window and launch properties. /// Basic window and launch properties.
int? kWindowId; int? kWindowId;
WindowType? kWindowType; WindowType? kWindowType;
@ -36,6 +36,7 @@ late List<String> kBootArgs;
Future<void> main(List<String> args) async { Future<void> main(List<String> args) async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
debugPrint("launch args: $args"); debugPrint("launch args: $args");
kBootArgs = List.from(args); kBootArgs = List.from(args);

View File

@ -3,11 +3,13 @@ import 'package:flutter_gpu_texture_renderer/flutter_gpu_texture_renderer.dart';
import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/models/model.dart'; import 'package:flutter_hbb/models/model.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
import '../../common.dart'; import '../../common.dart';
import './platform_model.dart'; import './platform_model.dart';
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart'
if (dart.library.html) 'package:flutter_hbb/web/texture_rgba_renderer.dart';
// Feature flutter_texture_render need to be enabled if feature gpucodec is enabled. // Feature flutter_texture_render need to be enabled if feature gpucodec is enabled.
final useTextureRender = final useTextureRender =
bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender(); bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender();

View File

@ -9,7 +9,6 @@ import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/generated_bridge.dart';
import 'package:flutter_hbb/models/ab_model.dart'; import 'package:flutter_hbb/models/ab_model.dart';
import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/chat_model.dart';
import 'package:flutter_hbb/models/cm_file_model.dart'; import 'package:flutter_hbb/models/cm_file_model.dart';
@ -39,6 +38,9 @@ import '../common/widgets/dialog.dart';
import 'input_model.dart'; import 'input_model.dart';
import 'platform_model.dart'; import 'platform_model.dart';
import 'package:flutter_hbb/generated_bridge.dart'
if (dart.library.html) 'package:flutter_hbb/web/bridge.dart';
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id); typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
typedef ReconnectHandle = Function(OverlayDialogManager, SessionID, bool); typedef ReconnectHandle = Function(OverlayDialogManager, SessionID, bool);
final _constSessionId = Uuid().v4obj(); final _constSessionId = Uuid().v4obj();

View File

@ -1,5 +1,6 @@
import 'package:flutter_hbb/generated_bridge.dart';
import 'native_model.dart' if (dart.library.html) 'web_model.dart'; import 'native_model.dart' if (dart.library.html) 'web_model.dart';
import 'package:flutter_hbb/generated_bridge.dart'
if (dart.library.html) 'package:flutter_hbb/web/bridge.dart';
final platformFFI = PlatformFFI.instance; final platformFFI = PlatformFFI.instance;
final localeName = PlatformFFI.localeName; final localeName = PlatformFFI.localeName;

View File

@ -3,15 +3,23 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:js'; import 'dart:js';
import '../common.dart';
import 'dart:html'; import 'dart:html';
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_hbb/web/bridge.dart';
import 'package:flutter_hbb/common.dart';
final List<StreamSubscription<MouseEvent>> mouseListeners = []; final List<StreamSubscription<MouseEvent>> mouseListeners = [];
final List<StreamSubscription<KeyboardEvent>> keyListeners = []; final List<StreamSubscription<KeyboardEvent>> keyListeners = [];
typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt);
class PlatformFFI { class PlatformFFI {
final _eventHandlers = <String, Map<String, HandleEvent>>{};
late RustdeskImpl _ffiBind;
static String getByName(String name, [String arg = '']) { static String getByName(String name, [String arg = '']) {
return context.callMethod('getByName', [name, arg]); return context.callMethod('getByName', [name, arg]);
} }
@ -24,15 +32,78 @@ class PlatformFFI {
static final PlatformFFI instance = PlatformFFI._(); static final PlatformFFI instance = PlatformFFI._();
static get localeName => window.navigator.language; static get localeName => window.navigator.language;
RustdeskImpl get ffiBind => _ffiBind;
static Future<void> init(String appType) async { static Future<String> getVersion() async {
isWeb = true; throw UnimplementedError();
}
bool registerEventHandler(
String eventName, String handlerName, HandleEvent handler) {
debugPrint('registerEventHandler $eventName $handlerName');
var handlers = _eventHandlers[eventName];
if (handlers == null) {
_eventHandlers[eventName] = {handlerName: handler};
return true;
} else {
if (handlers.containsKey(handlerName)) {
return false;
} else {
handlers[handlerName] = handler;
return true;
}
}
}
void unregisterEventHandler(String eventName, String handlerName) {
debugPrint('unregisterEventHandler $eventName $handlerName');
var handlers = _eventHandlers[eventName];
if (handlers != null) {
handlers.remove(handlerName);
}
}
Future<bool> tryHandle(Map<String, dynamic> evt) async {
final name = evt['name'];
if (name != null) {
final handlers = _eventHandlers[name];
if (handlers != null) {
if (handlers.isNotEmpty) {
for (var handler in handlers.values) {
await handler(evt);
}
return true;
}
}
}
return false;
}
String translate(String name, String locale) =>
_ffiBind.translate(name: name, locale: locale);
Uint8List? getRgba(SessionID sessionId, int display, int bufSize) {
throw UnimplementedError();
}
int getRgbaSize(SessionID sessionId, int display) =>
_ffiBind.sessionGetRgbaSize(sessionId: sessionId, display: display);
void nextRgba(SessionID sessionId, int display) =>
_ffiBind.sessionNextRgba(sessionId: sessionId, display: display);
void registerPixelbufferTexture(SessionID sessionId, int display, int ptr) =>
_ffiBind.sessionRegisterPixelbufferTexture(
sessionId: sessionId, display: display, ptr: ptr);
void registerGpuTexture(SessionID sessionId, int display, int ptr) =>
_ffiBind.sessionRegisterGpuTexture(
sessionId: sessionId, display: display, ptr: ptr);
Future<void> init(String appType) async {
isWebDesktop = !context.callMethod('isMobile'); isWebDesktop = !context.callMethod('isMobile');
context.callMethod('init'); context.callMethod('init');
version = getByName('version'); version = getByName('version');
} }
static void setEventCallback(void Function(Map<String, dynamic>) fun) { void setEventCallback(void Function(Map<String, dynamic>) fun) {
context["onGlobalEvent"] = (String message) { context["onGlobalEvent"] = (String message) {
try { try {
Map<String, dynamic> event = json.decode(message); Map<String, dynamic> event = json.decode(message);
@ -43,7 +114,7 @@ class PlatformFFI {
}; };
} }
static void setRgbaCallback(void Function(Uint8List) fun) { void setRgbaCallback(void Function(Uint8List) fun) {
context["onRgba"] = (Uint8List? rgba) { context["onRgba"] = (Uint8List? rgba) {
if (rgba != null) { if (rgba != null) {
fun(rgba); fun(rgba);
@ -51,12 +122,12 @@ class PlatformFFI {
}; };
} }
static void startDesktopWebListener() { void startDesktopWebListener() {
mouseListeners.add( mouseListeners.add(
window.document.onContextMenu.listen((evt) => evt.preventDefault())); window.document.onContextMenu.listen((evt) => evt.preventDefault()));
} }
static void stopDesktopWebListener() { void stopDesktopWebListener() {
for (var ml in mouseListeners) { for (var ml in mouseListeners) {
ml.cancel(); ml.cancel();
} }
@ -67,9 +138,14 @@ class PlatformFFI {
keyListeners.clear(); keyListeners.clear();
} }
static void setMethodCallHandler(FMethod callback) {} void setMethodCallHandler(FMethod callback) {}
static Future<bool> invokeMethod(String method, [dynamic arguments]) async { invokeMethod(String method, [dynamic arguments]) async {
return true; return true;
} }
// just for compilation
void syncAndroidServiceAppDirConfigPath() {
throw UnimplementedError();
}
} }

View File

@ -0,0 +1,10 @@
import 'dart:io';
final isAndroid_ = Platform.isAndroid;
final isIOS_ = Platform.isIOS;
final isWindows_ = Platform.isWindows;
final isMacOS_ = Platform.isWindows;
final isLinux_ = Platform.isWindows;
final isWeb_ = false;
final isDesktop_ = Platform.isWindows || Platform.isMacOS || Platform.isLinux;

View File

@ -0,0 +1,41 @@
import 'dart:ffi' hide Size;
import 'package:ffi/ffi.dart';
import 'package:win32/win32.dart' as win32;
/// Get windows target build number.
///
/// [Note]
/// Please use this function wrapped with `Platform.isWindows`.
int getWindowsTargetBuildNumber_() {
final rtlGetVersion = DynamicLibrary.open('ntdll.dll').lookupFunction<
Void Function(Pointer<win32.OSVERSIONINFOEX>),
void Function(Pointer<win32.OSVERSIONINFOEX>)>('RtlGetVersion');
final osVersionInfo = _getOSVERSIONINFOEXPointer();
rtlGetVersion(osVersionInfo);
int buildNumber = osVersionInfo.ref.dwBuildNumber;
calloc.free(osVersionInfo);
return buildNumber;
}
/// Get Windows OS version pointer
///
/// [Note]
/// Please use this function wrapped with `Platform.isWindows`.
Pointer<win32.OSVERSIONINFOEX> _getOSVERSIONINFOEXPointer() {
final pointer = calloc<win32.OSVERSIONINFOEX>();
pointer.ref
..dwOSVersionInfoSize = sizeOf<win32.OSVERSIONINFOEX>()
..dwBuildNumber = 0
..dwMajorVersion = 0
..dwMinorVersion = 0
..dwPlatformId = 0
..szCSDVersion = ''
..wServicePackMajor = 0
..wServicePackMinor = 0
..wSuiteMask = 0
..wProductType = 0
..wReserved = 0;
return pointer;
}

1414
flutter/lib/web/bridge.dart Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
final isAndroid_ = false;
final isIOS_ = false;
final isWindows_ = false;
final isMacOS_ = false;
final isLinux_ = false;
final isWeb_ = true;
final isDesktop_ = false;

View File

@ -0,0 +1,14 @@
abstract class NativeHandler {
bool onEvent(Map<String, dynamic> evt);
}
class NativeUiHandler extends NativeHandler {
NativeUiHandler._();
static NativeUiHandler instance = NativeUiHandler._();
@override
bool onEvent(Map<String, dynamic> evt) {
throw UnimplementedError();
}
}

View File

@ -0,0 +1,20 @@
import 'dart:typed_data';
class TextureRgbaRenderer {
Future<int> createTexture(int key) {
throw UnimplementedError();
}
Future<bool> closeTexture(int key) {
throw UnimplementedError();
}
Future<bool> onRgba(
int key, Uint8List data, int height, int width, int strideAlign) {
throw UnimplementedError();
}
Future<int> getTexturePtr(int key) {
throw UnimplementedError();
}
}

View File

@ -0,0 +1,5 @@
/// No use, for compilation only.
int getWindowsTargetBuildNumber_() {
return 0;
}