目录
UI框架与操作的联系
- UI框架负责UI渲染,系统为其提供系统窗口。
- UI框架需要接收系统窗口变化,来调整自身属性,重新渲染
- 系统窗口需要接收UI框架生成的一帧数据进行送显展示
- UI框架需要接收系统VSYN信号调整发送图像数据频率
- UI框架需要接收系统键盘输入事件、字符,同时通知系统展示或隐藏键盘
- UI框架需要接收系统的触摸事件,进行相关处理
- UI框架需要接收鼠标事件,进行相关处理
- 系统根据UI框架的需求展示或隐藏键盘
渲染系统
输入系统
渲染后端
- 系统原生窗口系统
- OpenGL
Android原生窗口系统
ANativeWindow_fromSurface(env, jsurface);
//step1 创建SkSurface
SkImageInfo image_info = SkImageInfo::Make(width,height,target_corlor_type, target_alpha_type, SkColorSpace::MakeSRGB());
sk_sp<SkSurface> backing_store = SkSurface::MakeRaster(image_info);
//step2 在上层使用SkCanvas绘制完成后,提取像素点到ANativeWindow_Buffer,
SkPixmap pixmap;
cacking_store->peekPixels(&pixmap);
ANativeWindow_Buffer native_buffer;
ANativeWindow_lock(native_window->handle(), &native_buffer, nullptr);
SkImageInfo native_image_info = SkImageInfo::Make(native_buffer.width, native_buffer.height, color_type, alpha_type);
std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(native_image_info, native_buffer.bits, native_buffer.stride * SkColorTypeBytesPerPixel(color_type));
SkBitmap bitmap;
bitmap.installPixels(pixmap);
//使用canvs将bitmap数据绘制到native_buffer(native_buffer已经在上一步设置到canvas)
canvas->drawImageRect(
bitmap.asImage(),
SkRect::MakeIWH(native_buffer.width, native_buffer.height),
SkSamplingOptions());
//step3 使用ANativeWindow_unlockAndPost发送图像数据
ANativeWindow_unlockAndPost(native_window_->handle());
Android OpenGL
//
EGLSurface surface = eglCreateWindowSurface(display, config_,reinterpret_cast<EGLNativeWindowType>(window->handle()),attribs);
onscreen_surface_->MakeCurrent();
onscreen_surface_->SwapBuffers(present_info.frame_damage);
本地窗口系统
Android:SurfaceView、
TextInputChannel
- MethodChannel
- MethodChannel.MethodCallHandler
- TextInputMethodHandler
- 连接Android与Flutter
MethodChannel创建
channel = new MethodChannel(dartExecutor, "flutter/textinput", JSONMethodCodec.INSTANCE);
- 键盘事件
由InputConnectionAdapter 继承BaseInputConnection实现。 - 触摸事件
由FlutterView.onTouchEvent实现
输入框实现
在Flutter框架下,输入框由Dart实现,而输入法由系统实现,当点击输入框时,弹出系统输入法,点击系统键盘,输入的相关字符在输入框中展示,点击其他区域收起系统键盘。这样的一个交互,需要输入框告知系统将键盘展示或隐藏,而输入字符时,需要将相关字符发送给输入框,让其展示出来。同时,点击键盘方向键也可以控制光标位置,所以,也需要将键盘的相关事件传递给输入框处理。
输入法弹出会占用屏幕空间,FlutterView(继承自SurfaceView)会接收到此事件,即Android系统通知SurfaceView尺寸大小发生变化,回调SurfaceView.onSizeChanged方法。在FlutterView接收到此事件后,由JNI层传递给Flutter引擎,再通知到Flutter窗口系统进行调整。
Android系统
BaseInputConnection(Android系统输入法连接类)
InputConnectionAdapter extends BaseInputConnection
接收Fluter View相关事件
- TextInput.show
- TextInput.hide
- TextInput.setClient
- TextInput.setEditingState
将系统输入法事件传递给Flutter View处理
- TextInputClient.performAction
传递系统输入的一些事件给Flutter View,如(newline、go、search、send、done、next) - TextInputClient.updateEditingState
将系统输入法输入的文字传递给Flutter View。
整体架构
PlatformConfiguration
- PlatformConfigurationClient(RuntimeController)
PlatformConfigurationNativeApi是Dart与C++的桥,获取到PlatformConfiguration对象,再取得其PlatformConfigurationClient对象调用ScheduleFrame()方法。
void PlatformConfigurationNativeApi::ScheduleFrame() {
UIDartState::ThrowIfUIOperationsProhibited();
UIDartState::Current()->platform_configuration()->client()->ScheduleFrame();
}
RuntimeController
- RuntimeDelegate(Engine)
RuntimeController持有Engine对象(即client_),直接调用其方法与其通信。
// |PlatformConfigurationClient|
void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame();
}
Engine
- Engine::Delegate(Shell)
- RuntimeController
- Animator
- AssetManager
- FontCollection
Shell
Shell与Engine关系,Shell提供引擎的初始化参数,
void Engine::HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) {
if (message->channel() == kAssetChannel) {
HandleAssetPlatformMessage(std::move(message));
} else {
delegate_.OnEngineHandlePlatformMessage(std::move(message));
}
}
Dart 调用C++
类似Java调用C++,需要在Dart层声明,c++层注册,Java使用的是JNI,Dart使用的是FFI(Foregin Function Interfaces)。
- Dart层声明。使用@FfiNative+函数类型进行声明
- 在C++层使用DartSetFfiNativeResolver进行注册。
//dart声明后直接可调用
@FfiNative<Void Function()>('PlatformConfigurationNativeApi::ScheduleFrame')
external static void _scheduleFrame();
//dart_ui.cc
//注册的还有Canvas、PictureRecorder、SceneBuilder、Paragraph、Patht等
V(PlatformConfigurationNativeApi::ScheduleFrame, 0) \
V(PlatformConfigurationNativeApi::Render, 1) \
V(PlatformConfigurationNativeApi::SendPlatformMessage, 3) \
V(PlatformConfigurationNativeApi::RespondToPlatformMessage, 2) \
void* ResolveFfiNativeFunction(const char* name, uintptr_t args) {
auto it = g_function_dispatchers.find(name);
return (it != g_function_dispatchers.end()) ? it->second : nullptr;
}
// Set up FFI Native resolver for dart:ui. 手动调用注入
Dart_Handle result = Dart_SetFfiNativeResolver(dart_ui, ResolveFfiNativeFunction);
C++调用Dart
C++调用Dart与C++调用Java类似,需要有一个返回获取到Dart方法的步骤
- dart方法添加@pragma(‘vm:entry-point’)注解。
- 加载Dart库。使用Dart_LoopupLibrary(tonic::ToDart(“dart:ui”);
- 反射拿到Dart方法。Dart_GetField(library, tonic::ToDart(“_beginFrame”);
- 调用Dart方法。tonic::DartInvoke(xxxx,xxx);
//lib/ui/hooks.dart
@pragma('vm:entry-point')
void _beginFrame(int microseconds, int frameNumber) {
PlatformDispatcher.instance._beginFrame(microseconds);
PlatformDispatcher.instance._updateFrameData(frameNumber);
}
@pragma('vm:entry-point')
void _drawFrame() {
PlatformDispatcher.instance._drawFrame();
}
//platform_configuration.cc
tonic::DartPersistentValue begin_frame_;
tonic::DartPersistentValue draw_frame_;
//绑定
Dart_Handle library = Dart_LookupLibrary(tonic::ToDart("dart:ui"));
begin_frame_.Set(tonic::DartState::Current(), Dart_GetField(library, tonic::ToDart("_beginFrame")));
draw_frame_.Set(tonic::DartState::Current(), Dart_GetField(library, tonic::ToDart("_drawFrame")));
//调用
tonic::DartInvoke(begin_frame_.Get(), { Dart_NewInteger(microseconds), Dart_NewInteger(frame_number),}));
tonic::DartInvokeVoid(draw_frame_.Get());
通信机制
Native发送消息到Dart
Native主动发消息给Dart核心代码时调用dart:ui库的_dispatchPlatformMessage方法,将数据传递给Dart层。
MessageChannel
DartExecutor(FlutterEngine创建了DartExecutor对象)
DartMessenger
DartMessenger.send()
DispatchPlatformMessage
- FlutterJNI.java
- platform_view_android_jni_impl.cc
- PlatformViewAndroid
- PlatformView
- Shell
- Engine
- RuntimeController
- PlatformConfiguration
//注册FFi
Dart_Handle library = Dart_LookupLibrary(tonic::ToDart("dart:ui"));
tonic::DartPersistentValue dispatch_platform_message_;
dispatch_platform_message_.Set(tonic::DartState::Current(), Dart_GetField(library, tonic::ToDart("_dispatchPlatformMessage")));
//发送到Dart
std::shared_ptr<tonic::DartState> dart_state = dispatch_platform_message_.dart_state().lock();
tonic::DartState::Scope scope(dart_state);
Dart_Handle data_handle = (message->hasData()) ? ToByteData(message->data()) : Dart_Null();
auto response = message->response();
int response_id = next_response_id_++;
tonic::DartInvoke(dispatch_platform_message_.Get(), {tonic::ToDart(message->channel()), data_handle, tonic::ToDart(response_id)}));
Dart发送消息到Native
通过FFI接口,调用PlatformConfigurationNativeApi::SendPlatformMessage()向Native发送消息
PlatformConfigurationNativeApi::SendPlatformMessage
PlatformConfigurationNativeApi::HandlePlatformMessage
RuntimeController::HandlePlatformMessage
Engine::HandlePlatformMessage
Shell::OnEngineHandlePlatformMessage
PlatformMessageHandler::HandlePlatformMessage
FlutterJNI::handlePlatformMessage
Surface
Surface类只用来创建一个SurfaceFrame对象,SurfaceFrame对象中需要持有SkSurface对象。
class SurfaceFrame {
bool Submit();
sk_sp<SkSurface> SkiaSurface() const;
}
// Surface主要创建一个SurfaceFrame对象,SurfaceFrame对象持有SkSurface,可供上层绘制使用
class Surface {
virtual std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) = 0;
}
Surface类型
- 系统窗口绘制(GPUSurfaceSoftware)
系统窗口绘制时,根据具体的操作系统生成SkSurface对象。 - OpenGL绘制(GPUSurfaceGLSkia)
class GPUSurfaceSoftwareDelegate {
// Called when the GPU surface needs a new buffer to render a new frame into.
virtual sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) = 0;
// Called by the platform when a frame has been rendered into the backing store and the platform must display it on-screen.
virtual bool PresentBackingStore(sk_sp<SkSurface> backing_store) = 0;
}
系统窗口绘制
系统创建SkSurface对象类似
SkImageInfo image_info = SkImageInfo::Make(size.fWidth, size.fHeight, target_color_type_, target_alpha_type_, SkColorSpace::MakeSRGB());
sk_surface_ = SkSurface::MakeRaster(image_info);
OpenGL绘制
//创建SkSurface对象
GrGLenum format = kUnknown_SkColorType;
const SkColorType color_type = FirstSupportedColorType(context, &format);
sk_sp<SkColorSpace> colorspace = SkColorSpace::MakeSRGB();
SkSurfaceProps surface_props(0, kUnknown_SkPixelGeometry);
GrGLFramebufferInfo framebuffer_info = {};
framebuffer_info.fFBOID = static_cast<GrGLuint>(fbo);
framebuffer_info.fFormat = format;
GrBackendRenderTarget render_target(size.width(), // width
size.height(), // height
0, // sample count
0, // stencil bits
framebuffer_info // framebuffer info
);
// context为GrDirectContext
return SkSurface::MakeFromBackendRenderTarget(
context, // Gr context
render_target, // render target
GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin, // origin
color_type, // color type
colorspace, // colorspace
&surface_props // surface properties
);
OpenGL环境初始化
//OpenGL环境初始化
EGLint w, h, dummy;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
//创建与系统窗口的绑定
surface = eglCreateWindowSurface(display, config, win, NULL);
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
//设置当前绘图环境,将context和surface绑定到当前线程
eglMakeCurrent(display_, onscreen_surface_, onscreen_surface_, onscreen_context_);
EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy,
EGLSurface draw,
EGLSurface read,
EGLContext ctx);
//提交数据
eglSwapBuffers(mDisplay, mSurface);
Surface创建过程
由Native层PlatformView主动触发创建,由PlatformView根据配置信息创建Surface。
PlatformView::NotifyCreated(){
std::unique_ptr<Surface> surface = platform_view->CreateRenderingSurface();
//delegate_为Shell
delegate_.OnPlatformViewCreated(std::move(surface));
}
// |PlatformView::Delegate|
void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
rasterizer->Setup(std::move(surface));
}
todo
1、 jni是如何在动态库加载
2、消息通信实现机制