使用(HelloWorld)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class RootView extends View { constructor() { super();
this.style = { width: '100%', height: '100%', justifyContent: 'center', alignItems: 'center', backgroundColor: '#FFFFFF', }
let textView = new Text(); textView.text = "~ Hello Hummer ~"; textView.style = { fontSize: 20, color: '#000000', }
this.appendChild(textView); } }
Hummer.render(new RootView());
|
Android目录结构
- hermes-debugger hermes引擎调试代码
- hummer 对外报漏的sdk依赖
- hummer-annotation apt 注解
- hummer-compiler apt processor,主要是根据代码生成js,js执行过程中反调用java代码
- hummer-component js 映射的 端侧组件
- hummer-core js引擎
- hummer-demo-app demo
- hummer-dev-tools 调试
- hummer-plugin-interface 调试
- hummer-sdk hummer除core之外的核心代码
JS引擎
- JavaScriptCore
- QuickJS
- hermes facebook提供的js引擎,目前没有了解过
- v8 代码中有提到,但是c代码未集成
编译
tip:COMPILE_JS_ENGINE=NAPI 替换为QuickJS之后,打包成功但无法启动
compoent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class Image$$Invoker extends BaseInvoker<Image> { @Override public String getName() { return "Image"; }
@Override protected Image createInstance(JSValue jsValue, Object[] params) { String param0 = params.length > 0 && params[0] != null ? String.valueOf(params[0]) : null; return new Image(mHummerContext, jsValue, param0); }
@Override protected Object invoke(Image instance, String methodName, Object[] params) { Object jsRet = null; switch (methodName) { case "setSrc": { String param0 = params.length > 0 && params[0] != null ? String.valueOf(params[0]) : null; instance.setSrc(param0); } break; case "setGifSrc": { String param0 = params.length > 0 && params[0] != null ? String.valueOf(params[0]) : null; instance.setGifSrc(param0); } break; case "setGifRepeatCount": { int param0 = params.length > 0 && params[0] != null ? ((Number) params[0]).intValue() : 0; instance.setGifRepeatCount(param0); } break; case "load": { Object param0 = params.length > 0 ? ((params[0] instanceof String && (HMGsonUtil.isJsonObject((String) params[0]) || HMGsonUtil.isJsonArray((String) params[0]))) ? HMGsonUtil.fromJson((String) params[0], new TypeToken<Object>(){}.getType()) : (Object) params[0]) : null; JSCallback param1 = params.length > 1 && params[1] != null ? (JSCallback) params[1] : null; instance.load(param0,param1); } break; } return jsRet; } }
|
register
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class HummerRegister$$hummer_component { public static final String JS_CODE = "var Image = class Image extends Base {\n" + " constructor(...args) {\n" + " super('Image', ...args);\n" + " }\n" + " set src(arg) {\n" + " this._src = arg;\n" + " arg = transSingleArg(arg);\n" + " invoke('Image', this.objID, 'setSrc', arg);\n" + " }\n" + " get src() {\n" + " return this._src;\n" + " }\n" + " set gifSrc(arg) {\n" + " this._gifSrc = arg;\n" + " arg = transSingleArg(arg);\n" + " invoke('Image', this.objID, 'setGifSrc', arg);\n" + " }\n" + " get gifSrc() {\n" + " return this._gifSrc;\n" + " }\n" + " set gifRepeatCount(arg) {\n" + " this._gifRepeatCount = arg;\n" + " arg = transSingleArg(arg);\n" + " invoke('Image', this.objID, 'setGifRepeatCount', arg);\n" + " }\n" + " get gifRepeatCount() {\n" + " return this._gifRepeatCount;\n" + " }\n" + " load(...args) {\n" + " let stash = args;\n" + " args = transArgs(...args);\n" + " invoke('Image', this.objID, 'load', ...args);\n" + " }\n" + "}\n" + "__GLOBAL__.Image = Image;\n"; public static void init(HummerContext hummerContext) { hummerContext.registerInvoker(new Image$$Invoker()); hummerContext.evaluateJavaScript(JS_CODE, "hummer_component.js"); } }
|
运行
流程图
- NAPIContext 和js交互
- NAPIHummerContext android上下文包装,包含了js操作,容器相关
- HummerRender 用于js的加载
javascript注入
- HummerDefinition.js
- HummerRegister$$hummer_sdk 中js注入
- HummerRegister$$hummer_component 注入
- 自定义属性和方法注入
- 业务js注入
HelloWorld分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class RootView extends View { constructor() { super();
this.style = { width: '100%', height: '100%', justifyContent: 'center', alignItems: 'center', backgroundColor: '#FFFFFF', }
let textView = new Text(); textView.text = "~ Hello Hummer ~"; textView.style = { fontSize: 20, color: '#000000', }
this.appendChild(textView); } }
Hummer.render(new RootView());
|
首先是new RootView ,RootView的继承关系为RootView -> View -> Base
View.js (此代码为自动生成)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class View extends Base { constructor(...args) { super('View', ...args); } appendChild(...args) { let stash = args; args = transArgs(...args); invoke('View', this.objID, 'appendChild', ...args); }
removeChild(...args) { let stash = args; args = transArgs(...args); invoke('View', this.objID, 'removeChild', ...args); } }
__GLOBAL__.View = View;
|
Base.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Base { constructor(className, ...args) { this.className = className; this.objID = idGenerator(); this.recycler = new Recycler(this.objID);
let params = transArgs(...args); invoke(this.className, this.objID, "constructor", this, ...params);
this.initialize(...args);
if (__IS_DEBUG__) { invoke(this.className, this.objID, "constructor_end", this); } } ... } __GLOBAL__.Base = Base;
|
RootView 会调用 Base中的构造方法,className= View,最终调用invoke方法回调端上。
1 2 3 4 5 6 7 8 9 10 11 12
| public class View$$Invoker extends BaseInvoker<View> { @Override public String getName() { return "View"; }
@Override protected View createInstance(JSValue jsValue, Object[] params) { String param0 = params.length > 0 && params[0] != null ? String.valueOf(params[0]) : null; return new View(mHummerContext, jsValue, param0); } }
|
invoke方法会回调View$$Invoker的createInstance方法创建一个View,此View为自定义View
1 2 3 4 5 6 7 8 9 10
| @Component("View") public class View extends HummerLayoutExtendView {
private static final String OVERFLOW_VISIBLE = "visible"; private static final String OVERFLOW_HIDDEN = "hidden";
public View(HummerContext context, JSValue jsValue, String viewID) { super(context, jsValue, viewID); } }
|
RootView中创建的Text原理也类似,最终会调用端上的Text,接下来我们分析Hummer的render方法
HummerDefinition.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const Hummer = { setBasicWidth: (width) => { invoke("Hummer", 0, "setBasicWidth", width); }, render: (view) => { invoke("Hummer", 0, "render", view.objID); }, loadScript: (script) => { return invoke("Hummer", 0, "loadScript", script); }, loadScriptWithUrl: (url, callback) => { invoke("Hummer", 0, "loadScriptWithUrl", url, callback); }, postException: (err) => { err = transSingleArg(err); invoke("Hummer", 0, "postException", err); }, notifyCenter: NotifyCenter, } __GLOBAL__.Hummer = Hummer;
|
hummer也是回调到了端上的render方法,这里直接给出代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class HummerInvoker extends BaseInvoker<HMBase> {
@Override public String getName() { return "Hummer"; }
@Override protected HMBase createInstance(JSValue jsValue, Object... params) { return null; }
@Override protected Object invoke(HMBase instance, String methodName, Object... params) { Object jsRet = null; switch (methodName) { case "setBasicWidth": RemUtil.BASE_WIDTH = ((Number) params[0]).floatValue(); break; case "render": long objId = ((Number) params[0]).longValue(); HMBase v = mInstanceManager.get(objId); mHummerContext.render(v); break; } return jsRet; } }
|
mHummerContext为上面提到的NAPIHummerContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class HummerContext extends ContextWrapper { public void render(HMBase base) { if (base != null) { mJSRootView = base; mJsPage = base.getJSValue(); mJsPage.protect(); create();
if (mContent != null) { mContent.removeAllViews(); mContent.addView(base); }
startIfNeed(); resumeIfNeed(); } } }
|
最终将base也就是上面提到的RootView添加到了端上容器中