Flutter框架分析


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)。

  1. Dart层声明。使用@FfiNative+函数类型进行声明
  2. 在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方法的步骤

  1. dart方法添加@pragma(‘vm:entry-point’)注解。
  2. 加载Dart库。使用Dart_LoopupLibrary(tonic::ToDart(“dart:ui”);
  3. 反射拿到Dart方法。Dart_GetField(library, tonic::ToDart(“_beginFrame”);
  4. 调用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、消息通信实现机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值