From 63c728db88476489b71bb7a0ec4c5b85b19412df Mon Sep 17 00:00:00 2001 From: Prome Date: Thu, 18 Aug 2022 22:10:58 +0800 Subject: [PATCH] wip --- .gitignore | 3 + example/lib/main.dart | 9 +- example/macos/Podfile.lock | 2 +- .../macos/Runner.xcodeproj/project.pbxproj | 3 + .../macos/Runner/DebugProfile.entitlements | 4 - example/macos/Runner/Release.entitlements | 5 +- lib/src/webview.dart | 21 ++- macos/Classes/CefWrapper.h | 33 ++++ macos/Classes/CefWrapper.mm | 107 ++++++++++++ macos/Classes/WebviewCefPlugin.m | 67 ++++++-- macos/webview_cef.podspec | 7 +- windows/simple_app.cc | 162 +++++++----------- windows/simple_handler.cc | 10 +- windows/simple_handler.h | 3 +- 14 files changed, 298 insertions(+), 138 deletions(-) create mode 100644 macos/Classes/CefWrapper.h create mode 100644 macos/Classes/CefWrapper.mm diff --git a/.gitignore b/.gitignore index ecae12f..3afe247 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +/macos/third/cef/Chromium Embedded Framework.framework +/macos/third/cef/include \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 2526b96..9cf285d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart'; import 'dart:async'; +import 'package:flutter/material.dart'; import 'package:webview_cef/webview_cef.dart'; void main() { @@ -29,7 +29,7 @@ class _MyAppState extends State { String url = "https://flutter.dev/"; _textController.text = url; await _controller.initialize(); - await _controller.loadUrl(url); + // await _controller.loadUrl(url); // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling // setState to update our non-existent appearance. @@ -54,8 +54,9 @@ class _MyAppState extends State { _controller.loadUrl(url); }, ), - _controller.value ? - Expanded(child: Webview(_controller)) : const Text("not init"), + _controller.value + ? Expanded(child: Webview(_controller)) + : const Text("not init"), ], )), ); diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index de805d7..2d4392e 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -15,7 +15,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 - webview_cef: 133a321203bfe12669fb57ea6cc43897b0a3fbcb + webview_cef: 60cb104c4f5d7454500fa260cfbaeb1da3d45292 PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 99fe0ef..3ab34fa 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -431,6 +431,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + OTHER_LDFLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -557,6 +558,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + OTHER_LDFLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -577,6 +579,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + OTHER_LDFLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/example/macos/Runner/DebugProfile.entitlements b/example/macos/Runner/DebugProfile.entitlements index dddb8a3..d35e43a 100644 --- a/example/macos/Runner/DebugProfile.entitlements +++ b/example/macos/Runner/DebugProfile.entitlements @@ -2,11 +2,7 @@ - com.apple.security.app-sandbox - com.apple.security.cs.allow-jit - com.apple.security.network.server - diff --git a/example/macos/Runner/Release.entitlements b/example/macos/Runner/Release.entitlements index 852fa1a..0c67376 100644 --- a/example/macos/Runner/Release.entitlements +++ b/example/macos/Runner/Release.entitlements @@ -1,8 +1,5 @@ - - com.apple.security.app-sandbox - - + diff --git a/lib/src/webview.dart b/lib/src/webview.dart index dc4fdc5..0e2ba3c 100644 --- a/lib/src/webview.dart +++ b/lib/src/webview.dart @@ -77,7 +77,8 @@ class WebviewController extends ValueNotifier { return; } assert(value); - return _pluginChannel.invokeMethod('cursorClickDown', [position.dx.round(), position.dy.round()]); + return _pluginChannel.invokeMethod( + 'cursorClickDown', [position.dx.round(), position.dy.round()]); } Future _cursorClickUp(Offset position) async { @@ -85,7 +86,8 @@ class WebviewController extends ValueNotifier { return; } assert(value); - return _pluginChannel.invokeMethod('cursorClickUp', [position.dx.round(), position.dy.round()]); + return _pluginChannel.invokeMethod( + 'cursorClickUp', [position.dx.round(), position.dy.round()]); } /// Sets the horizontal and vertical scroll delta. @@ -103,7 +105,8 @@ class WebviewController extends ValueNotifier { return; } assert(value); - return _pluginChannel.invokeMethod('setSize', [size.width.round(), size.height.round()]); + return _pluginChannel + .invokeMethod('setSize', [size.width.round(), size.height.round()]); } } @@ -125,7 +128,8 @@ class WebviewState extends State { void initState() { super.initState(); // Report initial surface size - WidgetsBinding.instance.addPostFrameCallback((_) => _reportSurfaceSize(context)); + WidgetsBinding.instance + .addPostFrameCallback((_) => _reportSurfaceSize(context)); } @override @@ -141,8 +145,7 @@ class WebviewState extends State { }, child: SizeChangedLayoutNotifier( child: Listener( - onPointerHover: (ev) { - }, + onPointerHover: (ev) {}, onPointerDown: (ev) { _controller._cursorClickDown(ev.localPosition); }, @@ -154,8 +157,8 @@ class WebviewState extends State { }, onPointerSignal: (signal) { if (signal is PointerScrollEvent) { - _controller._setScrollDelta( - -signal.scrollDelta.dx.round(), -signal.scrollDelta.dy.round()); + _controller._setScrollDelta(-signal.scrollDelta.dx.round(), + -signal.scrollDelta.dy.round()); } }, child: Texture(textureId: _controller._textureId), @@ -167,7 +170,7 @@ class WebviewState extends State { final box = _key.currentContext?.findRenderObject() as RenderBox?; if (box != null) { await _controller.ready; - unawaited(_controller._setSize(Size(box.size.width * dpi, box.size.height * dpi))); + unawaited(_controller._setSize(Size(box.size.width, box.size.height))); } } } diff --git a/macos/Classes/CefWrapper.h b/macos/Classes/CefWrapper.h new file mode 100644 index 0000000..8845416 --- /dev/null +++ b/macos/Classes/CefWrapper.h @@ -0,0 +1,33 @@ +// +// CefWrapper.h +// Pods +// +// Created by Hao Linwei on 2022/8/18. +// + +#ifndef CefWrapper_h +#define CefWrapper_h +#import + +extern NSObject* tr; +extern int64_t textureId; + +@interface CefWrapper : NSObject + ++ (void) init; + ++ (void) startCef; + ++ (void) scrollUp; + ++ (void) scrollDown; + ++ (void) cursorClickUp: (int)x y:(int)y; + ++ (void) cursorClickDown: (int)x y:(int)y; + ++ (void) sizeChanged: (int)width height:(int)height; + +@end + +#endif /* CefWrapper_h */ diff --git a/macos/Classes/CefWrapper.mm b/macos/Classes/CefWrapper.mm new file mode 100644 index 0000000..267686a --- /dev/null +++ b/macos/Classes/CefWrapper.mm @@ -0,0 +1,107 @@ +// +// CefWrapper.m +// Pods-Runner +// +// Created by Hao Linwei on 2022/8/18. +// + +#import "CefWrapper.h" +#import +#import "include/wrapper/cef_library_loader.h" +#import "include/cef_app.h" +#import "simple_app.h" + +#include + +CefRefPtr handler(new SimpleHandler(false)); +CefRefPtr app(new SimpleApp(handler)); +CefMainArgs mainArgs; + +NSObject* tr; + +static NSTimer* _timer; +static CVPixelBufferRef buf_cache; +static CVPixelBufferRef buf_temp; +dispatch_semaphore_t lock = dispatch_semaphore_create(1); + +int64_t textureId; + +@implementation CefWrapper + ++ (void)init { + CefScopedLibraryLoader loader; + + if(!loader.LoadInMain()) { + printf("load cef err"); + } + + CefMainArgs main_args; + CefExecuteProcess(main_args, nullptr, nullptr); +} + ++ (void)doMessageLoopWork { + CefDoMessageLoopWork(); +} + ++ (void)startCef { + textureId = [tr registerTexture:[CefWrapper alloc]]; + handler.get()->onPaintCallback = [](const void* buffer, int32_t width, int32_t height) { + NSDictionary* dic = @{ + (__bridge NSString*)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA), + (__bridge NSString*)kCVPixelBufferIOSurfacePropertiesKey: @{}, + (__bridge NSString*)kCVPixelBufferOpenGLCompatibilityKey : @YES, + (__bridge NSString*)kCVPixelBufferMetalCompatibilityKey : @YES, + }; + static CVPixelBufferRef buf = NULL; + CVPixelBufferCreate(kCFAllocatorDefault, width, + height, kCVPixelFormatType_32BGRA, + (__bridge CFDictionaryRef)dic, &buf); + CVPixelBufferLockBaseAddress(buf, 0); + void *copyBaseAddress = CVPixelBufferGetBaseAddress(buf); + memcpy(copyBaseAddress, buffer, width * height * 4); + CVPixelBufferUnlockBaseAddress(buf, 0); + + dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); + if(buf_cache) { + CVPixelBufferRelease(buf_cache); + } + buf_cache = buf; + dispatch_semaphore_signal(lock); + [tr textureFrameAvailable:textureId]; + }; + CefSettings cefs; + cefs.windowless_rendering_enabled = true; + CefInitialize(mainArgs, cefs, app.get(), nullptr); + _timer = [NSTimer timerWithTimeInterval:0.016f target:self selector:@selector(doMessageLoopWork) userInfo:nil repeats:YES]; + [[NSRunLoop mainRunLoop] addTimer: _timer forMode:NSRunLoopCommonModes]; +} + ++ (void)scrollUp { + handler.get()->scrollUp(); +} + ++(void)scrollDown { + handler.get()->scrollDown(); +} + ++ (void)cursorClickUp:(int)x y:(int)y { + handler.get()->cursorClick(x, y, true); +} + ++ (void)cursorClickDown:(int)x y:(int)y { + handler.get()->cursorClick(x, y, false); +} + ++ (void)sizeChanged:(int)width height:(int)height { + handler.get()->changeSize(width, height); +} + +- (CVPixelBufferRef _Nullable)copyPixelBuffer { + dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); + buf_temp = buf_cache; + CVPixelBufferRetain(buf_temp); + dispatch_semaphore_signal(lock); + return buf_temp; +} + +@end diff --git a/macos/Classes/WebviewCefPlugin.m b/macos/Classes/WebviewCefPlugin.m index 2b700dc..f6cf5af 100644 --- a/macos/Classes/WebviewCefPlugin.m +++ b/macos/Classes/WebviewCefPlugin.m @@ -1,27 +1,68 @@ #import "WebviewCefPlugin.h" +#import "CefWrapper.h" @implementation WebviewCefPlugin + (void)registerWithRegistrar:(NSObject*)registrar { - FlutterMethodChannel* channel = [FlutterMethodChannel - methodChannelWithName:@"webview_cef" - binaryMessenger:[registrar messenger]]; + FlutterMethodChannel* channel = [FlutterMethodChannel + methodChannelWithName:@"webview_cef" + binaryMessenger:[registrar messenger]]; WebviewCefPlugin *instance = [[WebviewCefPlugin alloc] init]; [registrar addMethodCallDelegate:instance channel:channel]; + + tr = registrar.textures; + + [CefWrapper init]; } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - - if ([@"getPlatformVersion" isEqualToString:call.method]) { - NSOperatingSystemVersion systemVer =[[NSProcessInfo processInfo] operatingSystemVersion]; - NSString *systemVersion = [NSString stringWithFormat:@"%ld.%ld.%ld", - (long)systemVer.majorVersion, (long)systemVer.minorVersion, (long)systemVer.patchVersion]; - result([@"macOS " stringByAppendingString:systemVersion]); - } - else { - result(FlutterMethodNotImplemented); - } + + if ([@"getPlatformVersion" isEqualToString:call.method]) { + NSOperatingSystemVersion systemVer =[[NSProcessInfo processInfo] operatingSystemVersion]; + NSString *systemVersion = [NSString stringWithFormat:@"%ld.%ld.%ld", + (long)systemVer.majorVersion, (long)systemVer.minorVersion, (long)systemVer.patchVersion]; + result([@"macOS " stringByAppendingString:systemVersion]); + } + else if([@"init" isEqualToString:call.method]){ + [CefWrapper startCef]; + result([NSNumber numberWithLong:textureId]); + } + else if([@"setScrollDelta" isEqualToString:call.method]){ + NSArray *_arg = call.arguments; + NSNumber *deltaY = [_arg objectAtIndex:1]; + int delta = [deltaY intValue]; + if(delta > 0) { + [CefWrapper scrollDown]; + } else { + [CefWrapper scrollUp]; + } + result(nil); + } + else if([@"cursorClickUp" isEqualToString:call.method]){ + NSArray *_arg = call.arguments; + NSNumber *x = [_arg objectAtIndex:0]; + NSNumber *y = [_arg objectAtIndex:1]; + [CefWrapper cursorClickUp:[x intValue] y:[y intValue]]; + result(nil); + } + else if([@"cursorClickDown" isEqualToString:call.method]){ + NSArray *_arg = call.arguments; + NSNumber *x = [_arg objectAtIndex:0]; + NSNumber *y = [_arg objectAtIndex:1]; + [CefWrapper cursorClickDown:[x intValue] y:[y intValue]]; + result(nil); + } + else if([@"setSize" isEqualToString:call.method]){ + NSArray *_arg = call.arguments; + NSNumber *width = [_arg objectAtIndex:0]; + NSNumber *height = [_arg objectAtIndex:1]; + [CefWrapper sizeChanged:[width intValue] height:[height intValue]]; + result(nil); + } + else { + result(FlutterMethodNotImplemented); + } } @end diff --git a/macos/webview_cef.podspec b/macos/webview_cef.podspec index 1f694c0..dc6b1ee 100644 --- a/macos/webview_cef.podspec +++ b/macos/webview_cef.podspec @@ -16,7 +16,12 @@ Flutter webview backed by CEF (Chromium Embedded Framework) s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'FlutterMacOS' - s.vendored_frameworks = 'third/cef/Chromium\ Embedded\ Framework.framework' + s.vendored_frameworks = 'third/cef/Chromium Embedded Framework.framework' + s.vendored_libraries = 'third/cef/libcef_dll_wrapper.a' + + $dir = File.dirname(__FILE__) + $dir = $dir + "/third/cef/**" + s.xcconfig = { "HEADER_SEARCH_PATHS" => $dir} s.platform = :osx, '10.11' s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } diff --git a/windows/simple_app.cc b/windows/simple_app.cc index 11c3870..20a8996 100644 --- a/windows/simple_app.cc +++ b/windows/simple_app.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. @@ -11,68 +11,67 @@ #include "include/views/cef_browser_view.h" #include "include/views/cef_window.h" #include "include/wrapper/cef_helpers.h" -#include namespace { // When using the Views framework this object provides the delegate // implementation for the CefWindow that hosts the Views-based browser. class SimpleWindowDelegate : public CefWindowDelegate { - public: - explicit SimpleWindowDelegate(CefRefPtr browser_view) - : browser_view_(browser_view) {} - - void OnWindowCreated(CefRefPtr window) override { - // Add the browser view and show the window. - window->AddChildView(browser_view_); - window->Show(); - - // Give keyboard focus to the browser view. - browser_view_->RequestFocus(); - } - - void OnWindowDestroyed(CefRefPtr window) override { - browser_view_ = nullptr; - } - - bool CanClose(CefRefPtr window) override { - // Allow the window to close if the browser says it's OK. - CefRefPtr browser = browser_view_->GetBrowser(); - if (browser) - return browser->GetHost()->TryCloseBrowser(); - return true; - } - - CefSize GetPreferredSize(CefRefPtr view) override { - return CefSize(800, 600); - } - - private: - CefRefPtr browser_view_; - - IMPLEMENT_REFCOUNTING(SimpleWindowDelegate); - DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate); +public: + explicit SimpleWindowDelegate(CefRefPtr browser_view) + : browser_view_(browser_view) {} + + void OnWindowCreated(CefRefPtr window) override { + // Add the browser view and show the window. + window->AddChildView(browser_view_); + window->Show(); + + // Give keyboard focus to the browser view. + browser_view_->RequestFocus(); + } + + void OnWindowDestroyed(CefRefPtr window) override { + browser_view_ = nullptr; + } + + bool CanClose(CefRefPtr window) override { + // Allow the window to close if the browser says it's OK. + CefRefPtr browser = browser_view_->GetBrowser(); + if (browser) + return browser->GetHost()->TryCloseBrowser(); + return true; + } + + CefSize GetPreferredSize(CefRefPtr view) override { + return CefSize(800, 600); + } + +private: + CefRefPtr browser_view_; + + IMPLEMENT_REFCOUNTING(SimpleWindowDelegate); + DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate); }; class SimpleBrowserViewDelegate : public CefBrowserViewDelegate { - public: - SimpleBrowserViewDelegate() {} - - bool OnPopupBrowserViewCreated(CefRefPtr browser_view, - CefRefPtr popup_browser_view, - bool is_devtools) override { - // Create a new top-level Window for the popup. It will show itself after - // creation. - CefWindow::CreateTopLevelWindow( - new SimpleWindowDelegate(popup_browser_view)); - - // We created the Window. - return true; - } - - private: - IMPLEMENT_REFCOUNTING(SimpleBrowserViewDelegate); - DISALLOW_COPY_AND_ASSIGN(SimpleBrowserViewDelegate); +public: + SimpleBrowserViewDelegate() {} + + bool OnPopupBrowserViewCreated(CefRefPtr browser_view, + CefRefPtr popup_browser_view, + bool is_devtools) override { + // Create a new top-level Window for the popup. It will show itself after + // creation. + CefWindow::CreateTopLevelWindow( + new SimpleWindowDelegate(popup_browser_view)); + + // We created the Window. + return true; + } + +private: + IMPLEMENT_REFCOUNTING(SimpleBrowserViewDelegate); + DISALLOW_COPY_AND_ASSIGN(SimpleBrowserViewDelegate); }; } // namespace @@ -82,56 +81,23 @@ SimpleApp::SimpleApp(CefRefPtr handler) { } void SimpleApp::OnContextInitialized() { - CEF_REQUIRE_UI_THREAD(); - - CefRefPtr command_line = - CefCommandLine::GetGlobalCommandLine(); - - // Create the browser using the Views framework if "--use-views" is specified - // via the command-line. Otherwise, create the browser using the native - // platform framework. - const bool use_views = command_line->HasSwitch("use-views"); - - // SimpleHandler implements browser-level callbacks. - - // Specify CEF browser settings here. - CefBrowserSettings browser_settings; - browser_settings.windowless_frame_rate = 60; - - std::string url; - - // Check if a "--url=" value was provided via the command-line. If so, use - // that instead of the default URL. - url = command_line->GetSwitchValue("url"); - if (url.empty()) - url = "about:blank"; - - if (use_views) { - // Create the BrowserView. - CefRefPtr browser_view = CefBrowserView::CreateBrowserView( - m_handler, url, browser_settings, nullptr, nullptr, - new SimpleBrowserViewDelegate()); - - // Create the Window. It will show itself after creation. - //CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view)); - } else { - // Information used when creating the native window. + CEF_REQUIRE_UI_THREAD(); + + // Specify CEF browser settings here. + CefBrowserSettings browser_settings; + browser_settings.windowless_frame_rate = 60; + + std::string url = "https://www.bilibili.com/"; + CefWindowInfo window_info; - -#if defined(OS_WIN) - // On Windows we need to specify certain flags that will be passed to - // CreateWindowEx(). - //window_info.SetAsPopup(nullptr, "cefsimple"); window_info.SetAsWindowless(nullptr); -#endif - + // Create the first browser window. CefBrowserHost::CreateBrowser(window_info, m_handler, url, browser_settings, nullptr, nullptr); - } } CefRefPtr SimpleApp::GetDefaultClient() { - // Called when a new browser window is created via the Chrome runtime UI. - return SimpleHandler::GetInstance(); + // Called when a new browser window is created via the Chrome runtime UI. + return SimpleHandler::GetInstance(); } diff --git a/windows/simple_handler.cc b/windows/simple_handler.cc index 3e456b2..832e5d0 100644 --- a/windows/simple_handler.cc +++ b/windows/simple_handler.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. @@ -180,8 +180,8 @@ void SimpleHandler::scrollDown() void SimpleHandler::changeSize(int w, int h) { - this->width = w; - this->height = h; +// this->width = w; +// this->height = h; BrowserList::const_iterator it = browser_list_.begin(); if (it != browser_list_.end()) { (*it)->GetHost()->WasResized(); @@ -219,3 +219,7 @@ void SimpleHandler::OnPaint(CefRefPtr browser, CefRenderHandler::Pai onPaintCallback(buffer, w, h); } +void SimpleHandler::PlatformTitleChange(CefRefPtr browser, + const CefString& title) { +} + diff --git a/windows/simple_handler.h b/windows/simple_handler.h index cd172bf..dc56eb8 100644 --- a/windows/simple_handler.h +++ b/windows/simple_handler.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. @@ -8,6 +8,7 @@ #include "include/cef_client.h" #include +#include class SimpleHandler : public CefClient, public CefDisplayHandler,