-
Notifications
You must be signed in to change notification settings - Fork 304
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
插件化方案 #5
Comments
Kraken 插件化设计有关 Kraken 能力边界划分: 核心能力
Kraken 插件化拆分的设计的目标:
kraken 插件的加载方式Kraken 的插件就是一个 Flutter plugin,采用和其他 flutter plugin 一样的加载方式。可以通过 pub 进行安装 Kraken 扩展能力在设计上, Kraken 将支持 2 种能力的扩展:
渲染能力扩展设计Kraken 的渲染能力所承载的实现为 Element 对象。Element 对象在 JS 环境 (C++ 实现)和 Dart 环境中各有一份对象的实现。它们之间会通过一个 NativeEventTarget 的结构体来保持相互的引用。通过这样的一个结构体,JS 环境可以直接调用 Dart 环境中的函数,同时 Dart 环境也可以直接调用 JS 环境(C++实现)中实现的函数。 Dart 环境中的 Element 扩展import 'package:kraken/dom.dart';
import 'package:kraken/rendering.dart';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class NativeCustomElement extends Struct {
Pointer<NativeElement> nativeElement;
}
const String CUSTOM = 'CUSTOM';
class CustomElement extends Element {
CustomElement(int targetId, Pointer<CustomElement> nativePtr, ElementManager elementManager)
: super(
targetId,
nativePtr.ref.nativeElement,
elementManager,
CUSTOM
);
// Fired before this element's renderObject attach to renderObject tree.
@override
void willAttachRenderer() {
super.willAttachRenderer();
}
// Fired when this element's renderObject attach to renderObject tree.
@override
void attachTo(Element parent, {RenderObject after}) {
super.attachTo(parent, after: after);
}
// Fired after this element's renderObject attach to renderObject
@override
void didDetachRenderer() {
super.didDetachRenderer();
}
// Fired when this element is disposed.
@override
void dispose() {
super.dispose();
}
// Fired when this element's renderObject detached from parent
@override
void detach() {
super.detach();
}
// Fired when setting string property of the element in JS environment.
@override
void setProperty(String key, value) {
super.setProperty(key, value);
}
// Fired when reading string property of the element in JS environment.
@override
dynamic getProperty(String key) {
return super.getProperty(key);
}
// Fired when remove string property of the element in JS environment.
@override
void removeProperty(String key) {
super.removeProperty(key);
}
// Fired when add child node of this element.
@override
Node appendChild(Node child) {
super.appendChild(child);
}
// Fired when remove child node of this element.
Node removeChild(Node child) {
super.removeChild(child);
}
// Fired when insert child node before a referenceNode.
Node insertBefore(Node child, Node referenceNode) {
super.insertBefore(child, referenceNode);
}
// Fired when element.addEventListener() js api called.
void addEvent(String eventType) {
super.addEvent(eventType);
}
}
defineElement(CUSTOM, (id, nativePtr, elementManager) => CustomElement(id, nativePtr.cast<NativeCustomElement>(), elementManager)); JS 环境中的 Element 扩展Kraken 中的 JS Element 采用 C++ 进行实现,因此 JS 环境中的 Element 扩展也需要采用 C++ 进行开发。通过 Kraken 所提供的 Headers 就可以编写 Kraken Element 扩展。 using GetContext = NativeCanvasRenderingContext2D *(*)(NativeCanvasElement *nativeCanvasElement,
NativeString *contextId);
struct NativeCanvasElement {
NativeCanvasElement() = delete;
NativeCanvasElement(NativeElement *nativeElement) : nativeElement(nativeElement){};
NativeElement *nativeElement;
GetContext getContext{nullptr};
};
class JSCanvasElement : public JSElement {
public:
static std::unordered_map<JSContext *, JSCanvasElement *> instanceMap;
OBJECT_INSTANCE(JSCanvasElement)
JSObjectRef instanceConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount,
const JSValueRef *arguments, JSValueRef *exception) override;
private:
JSCanvasElement() = delete;
~JSCanvasElement();
explicit JSCanvasElement(JSContext *context);
};
class CanvasElementInstance : public ElementInstance {
public:
static JSValueRef getContext(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount,
const JSValueRef arguments[], JSValueRef *exception);
CanvasElementInstance() = delete;
explicit CanvasElementInstance(JSCanvasElement *jsCanvasElement);
~CanvasElementInstance();
// called when reading properties on canvas element
JSValueRef getProperty(std::string &name, JSValueRef *exception) override;
// called when setting properties on canvas element
void setProperty(std::string &name, JSValueRef value, JSValueRef *exception) override;
// called when read property names (Object.keys) on canvas element.
void getPropertyNames(JSPropertyNameAccumulatorRef accumulator) override;
NativeCanvasElement *nativeCanvasElement;
private:
JSFunctionHolder m_getContext{context, this, "getContext", getContext};
};
JSElement::defineElement("canvas", [](JSContext *context) -> ElementInstance* {
return new CanvasElementInstance(JSCanvasElement::instance(context));
}); API 能力扩展设计API 能力的扩展分为两个部分:Module 的扩展和 JS API 扩展 Module 扩展
class CustomModule extends BaseModule {
CustomModule(ModuleManager moduleManager) : super(moduleManager);
// Invoke when Kraken page disposed.
@override
void dispose() {
// TODO: implement dispose
}
// Invoke when JS api kraken.invokeModule calls.
@override
String invoke(List<dynamic> params, InvokeModuleCallback callback) {
}
} 然后再通过下面的方法将 Module 注册到 Kraken 中。 ModuleManager.defineNewModule('DemoModule', CustomModule(controller.module.moduleManager)); JS API 扩展Module 的 JS API 扩展推荐使用 JS 进行实现。Kraken 提供了以下几个 API 用于调用 Dart 层实现的 Module。
触发自定义 Module 事件Kraken 提供了 CloseEvent event = CloseEvent(0, '', true);
moduleManager.emitModuleEvent('WebSocket', event);
kraken.addKrakenModuleListener((method, event) => {
if (method == "WebSocket") {
// dispatch websocket event.
}
}); Q & A如何实现 Element 上方法的调用
class CanvasElement extends Element {
static SplayTreeMap<int, Element> _nativeMap = SplayTreeMap();
static CanvasElement getCanvasElementOfNativePtr(Pointer<NativeCanvasElement> nativeCanvasElement) {
CanvasElement canvasElement = _nativeMap[nativeCanvasElement.address];
assert(canvasElement != null, 'Can not get canvasElement from nativeElement: $nativeCanvasElement');
return canvasElement;
}
static Pointer<NativeCanvasRenderingContext2D> _getContext(
Pointer<NativeCanvasElement> nativeCanvasElement, Pointer<NativeString> contextId) {
CanvasElement canvasElement = getCanvasElementOfNativePtr(nativeCanvasElement);
canvasElement.getContext(nativeStringToString(contextId));
}
final Pointer<NativeCanvasElement> nativeCanvasElement;
CanvasElement(int targetId, this.nativeCanvasElement, ElementManager elementManager)
: super(
targetId,
nativeCanvasElement.ref.nativeElement,
elementManager,
defaultStyle: _defaultStyle,
isIntrinsicBox: true,
repaintSelf: true,
tagName: CANVAS,
) {
nativeCanvasElement.ref.getContext = nativeGetContext;
// Keep reference so that we can search back with nativePtr from bridge.
_nativeMap[nativeCanvasElement.address] = this;
}
// RenderingContext? getContext(DOMString contextId, optional any options = null);
CanvasRenderingContext getContext(String contextId, {dynamic options}) {
// ...
}
}
NativeCanvasRenderingContext2D *nativeCanvasRenderingContext2D =
elementInstance->nativeCanvasElement->getContext(elementInstance->nativeCanvasElement, &contextId); NativeElement的介绍如何自定义事件在 W3C 标准中,定义了各种不同类型的事件。每个事件之间的差异在于不同的事件提供不一样的参数和数据。 class CloseEvent extends Event {
/// An unsigned short containing the close code sent by the server
final int code;
/// Indicating the reason the server closed the connection.
final String reason;
/// Indicates whether or not the connection was cleanly closed
final bool wasClean;
CloseEvent(this.code, this.reason, this.wasClean) :
assert(reason != null),
super(EVENT_CLOSE);
Pointer<NativeCloseEvent> toNative() {
Pointer<NativeCloseEvent> closeEvent = allocate<NativeCloseEvent>();
Pointer<NativeEvent> nativeEvent = super.toNative().cast<NativeEvent>();
closeEvent.ref.nativeEvent = nativeEvent;
closeEvent.ref.code = code;
closeEvent.ref.reason = stringToNativeString(reason);
closeEvent.ref.wasClean = wasClean ? 1 : 0;
return closeEvent;
}
} 在 JS 环境中扩展事件 class JSCloseEvent : public JSEvent {
public:
DEFINE_OBJECT_PROPERTY(CloseEvent, 3, code, reason, wasClean)
static std::unordered_map<JSContext *, JSCloseEvent *> instanceMap;
OBJECT_INSTANCE(JSCloseEvent)
JSObjectRef instanceConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount,
const JSValueRef *arguments, JSValueRef *exception) override;
JSValueRef getProperty(std::string &name, JSValueRef *exception) override;
protected:
JSCloseEvent() = delete;
~JSCloseEvent();
explicit JSCloseEvent(JSContext *context);
};
class CloseEventInstance : public EventInstance {
public:
CloseEventInstance() = delete;
explicit CloseEventInstance(JSCloseEvent *jsCloseEvent, NativeCloseEvent *nativeCloseEvent);
explicit CloseEventInstance(JSCloseEvent *jsCloseEvent, JSStringRef data, JSValueRef closeEventInit, JSValueRef *exception);
JSValueRef getProperty(std::string &name, JSValueRef *exception) override;
void setProperty(std::string &name, JSValueRef value, JSValueRef *exception) override;
void getPropertyNames(JSPropertyNameAccumulatorRef accumulator) override;
~CloseEventInstance() override;
NativeCloseEvent *nativeCloseEvent;
private:
double code;
bool wasClean;
JSStringHolder m_reason{context, ""};
};
struct NativeCloseEvent {
NativeCloseEvent() = delete;
explicit NativeCloseEvent(NativeEvent *nativeEvent) : nativeEvent(nativeEvent){};
NativeEvent *nativeEvent;
int64_t code;
NativeString *reason;
int64_t wasClean;
};
|
@andycall 写这么好,不放文档里可惜了 |
No description provided.
The text was updated successfully, but these errors were encountered: