This commit is contained in:
Prome
2022-08-18 22:10:58 +08:00
committed by haolinwei
parent 4afcadd175
commit 63c728db88
14 changed files with 298 additions and 138 deletions

3
.gitignore vendored
View File

@@ -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

View File

@@ -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<MyApp> {
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<MyApp> {
_controller.loadUrl(url);
},
),
_controller.value ?
Expanded(child: Webview(_controller)) : const Text("not init"),
_controller.value
? Expanded(child: Webview(_controller))
: const Text("not init"),
],
)),
);

View File

@@ -15,7 +15,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
webview_cef: 133a321203bfe12669fb57ea6cc43897b0a3fbcb
webview_cef: 60cb104c4f5d7454500fa260cfbaeb1da3d45292
PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c

View File

@@ -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;
};

View File

@@ -2,11 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View File

@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
<dict/>
</plist>

View File

@@ -77,7 +77,8 @@ class WebviewController extends ValueNotifier<bool> {
return;
}
assert(value);
return _pluginChannel.invokeMethod('cursorClickDown', [position.dx.round(), position.dy.round()]);
return _pluginChannel.invokeMethod(
'cursorClickDown', [position.dx.round(), position.dy.round()]);
}
Future<void> _cursorClickUp(Offset position) async {
@@ -85,7 +86,8 @@ class WebviewController extends ValueNotifier<bool> {
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<bool> {
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<Webview> {
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<Webview> {
},
child: SizeChangedLayoutNotifier(
child: Listener(
onPointerHover: (ev) {
},
onPointerHover: (ev) {},
onPointerDown: (ev) {
_controller._cursorClickDown(ev.localPosition);
},
@@ -154,8 +157,8 @@ class WebviewState extends State<Webview> {
},
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<Webview> {
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)));
}
}
}

View File

@@ -0,0 +1,33 @@
//
// CefWrapper.h
// Pods
//
// Created by Hao Linwei on 2022/8/18.
//
#ifndef CefWrapper_h
#define CefWrapper_h
#import <FlutterMacOS/FlutterMacOS.h>
extern NSObject<FlutterTextureRegistry>* tr;
extern int64_t textureId;
@interface CefWrapper : NSObject<FlutterTexture>
+ (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 */

107
macos/Classes/CefWrapper.mm Normal file
View File

@@ -0,0 +1,107 @@
//
// CefWrapper.m
// Pods-Runner
//
// Created by Hao Linwei on 2022/8/18.
//
#import "CefWrapper.h"
#import <Foundation/Foundation.h>
#import "include/wrapper/cef_library_loader.h"
#import "include/cef_app.h"
#import "simple_app.h"
#include <thread>
CefRefPtr<SimpleHandler> handler(new SimpleHandler(false));
CefRefPtr<SimpleApp> app(new SimpleApp(handler));
CefMainArgs mainArgs;
NSObject<FlutterTextureRegistry>* 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

View File

@@ -1,27 +1,68 @@
#import "WebviewCefPlugin.h"
#import "CefWrapper.h"
@implementation WebviewCefPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)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<NSNumber *> *_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<NSNumber *> *_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<NSNumber *> *_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<NSNumber *> *_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

View File

@@ -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' }

View File

@@ -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 <cpp_client_wrapper/include/flutter/texture_registrar.h>
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<CefBrowserView> browser_view)
: browser_view_(browser_view) {}
void OnWindowCreated(CefRefPtr<CefWindow> 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<CefWindow> window) override {
browser_view_ = nullptr;
}
bool CanClose(CefRefPtr<CefWindow> window) override {
// Allow the window to close if the browser says it's OK.
CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
if (browser)
return browser->GetHost()->TryCloseBrowser();
return true;
}
CefSize GetPreferredSize(CefRefPtr<CefView> view) override {
return CefSize(800, 600);
}
private:
CefRefPtr<CefBrowserView> browser_view_;
IMPLEMENT_REFCOUNTING(SimpleWindowDelegate);
DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate);
public:
explicit SimpleWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
: browser_view_(browser_view) {}
void OnWindowCreated(CefRefPtr<CefWindow> 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<CefWindow> window) override {
browser_view_ = nullptr;
}
bool CanClose(CefRefPtr<CefWindow> window) override {
// Allow the window to close if the browser says it's OK.
CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
if (browser)
return browser->GetHost()->TryCloseBrowser();
return true;
}
CefSize GetPreferredSize(CefRefPtr<CefView> view) override {
return CefSize(800, 600);
}
private:
CefRefPtr<CefBrowserView> browser_view_;
IMPLEMENT_REFCOUNTING(SimpleWindowDelegate);
DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate);
};
class SimpleBrowserViewDelegate : public CefBrowserViewDelegate {
public:
SimpleBrowserViewDelegate() {}
bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
CefRefPtr<CefBrowserView> 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<CefBrowserView> browser_view,
CefRefPtr<CefBrowserView> 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<SimpleHandler> handler) {
}
void SimpleApp::OnContextInitialized() {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefCommandLine> 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<CefBrowserView> 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<CefClient> 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();
}

View File

@@ -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<CefBrowser> browser, CefRenderHandler::Pai
onPaintCallback(buffer, w, h);
}
void SimpleHandler::PlatformTitleChange(CefRefPtr<CefBrowser> browser,
const CefString& title) {
}

View File

@@ -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 <functional>
#include <list>
class SimpleHandler : public CefClient,
public CefDisplayHandler,