├── .gitignore
├── README.md
├── app
├── .DS_Store
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── .DS_Store
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── hybriddemo
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── hybriddemo
│ │ │ ├── MainActivity.java
│ │ │ ├── core
│ │ │ ├── JSBridge.java
│ │ │ ├── JsApplication.java
│ │ │ ├── JsBundle.java
│ │ │ ├── JsContext.java
│ │ │ ├── module
│ │ │ │ ├── JsModule.java
│ │ │ │ └── ModuleManager.java
│ │ │ └── ui
│ │ │ │ ├── JsView.java
│ │ │ │ ├── JsViewFactory.java
│ │ │ │ ├── JsViewGroup.java
│ │ │ │ ├── RenderManager.java
│ │ │ │ └── dom
│ │ │ │ ├── DomButton.java
│ │ │ │ ├── DomElement.java
│ │ │ │ ├── DomFactory.java
│ │ │ │ ├── DomGroup.java
│ │ │ │ ├── DomImage.java
│ │ │ │ ├── DomText.java
│ │ │ │ └── DomVerticalLayout.java
│ │ │ ├── module
│ │ │ ├── ConsoleModule.java
│ │ │ └── UiModule.java
│ │ │ └── view
│ │ │ ├── ButtonJsView.java
│ │ │ ├── ImageJsView.java
│ │ │ ├── TextJsView.java
│ │ │ └── VerticalLayoutJsView.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── demo.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── js.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── hybriddemo
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | # Android Studio 3 in .gitignore file.
48 | .idea/caches
49 | .idea/modules.xml
50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
51 | .idea/navEditor.xml
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 | .cxx/
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HybridDemo
2 | 快手电商无线技术团队的掘金文章:打造你自己的动态化引擎 https://juejin.cn/post/7046299455397560350
3 |
4 | 一个基础的动态化引擎,文章主要介绍了动态化引擎有哪些核心模块,并将每个模块的实现方法分步骤展开,希望大家能从手动实现的过程中,理解动态化引擎的原理,也了解前端技术栈和客户端的不同之处。
5 | 大家感兴趣的话,可以再继续完善这个动态化引擎,添加自己想要的能力,写出更多有趣的JS应用~
6 |
--------------------------------------------------------------------------------
/app/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kwai-ec/HybridDemo/652e4259dba3b1f63774de6d97fa3606e528e350/app/.DS_Store
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | id 'kotlin-kapt'
5 | }
6 |
7 | kapt {
8 | arguments {
9 | arg("AROUTER_MODULE_NAME", project.getName())
10 | }
11 | }
12 |
13 | android {
14 | compileSdkVersion 30
15 | buildToolsVersion "30.0.3"
16 |
17 | defaultConfig {
18 | applicationId "com.example.hybriddemo"
19 | minSdkVersion 21
20 | targetSdkVersion 30
21 | versionCode 1
22 | versionName "1.0"
23 |
24 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
25 | }
26 |
27 | buildTypes {
28 | release {
29 | minifyEnabled false
30 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
31 | }
32 | }
33 | compileOptions {
34 | sourceCompatibility JavaVersion.VERSION_1_8
35 | targetCompatibility JavaVersion.VERSION_1_8
36 | }
37 | kotlinOptions {
38 | jvmTarget = '1.8'
39 | }
40 | }
41 |
42 | dependencies {
43 | implementation 'com.eclipsesource.j2v8:j2v8:6.2.1@aar'
44 |
45 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
46 | implementation 'androidx.core:core-ktx:1.3.2'
47 | implementation 'androidx.appcompat:appcompat:1.2.0'
48 | implementation 'com.google.android.material:material:1.2.1'
49 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
50 | testImplementation 'junit:junit:4.+'
51 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
52 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
53 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kwai-ec/HybridDemo/652e4259dba3b1f63774de6d97fa3606e528e350/app/src/.DS_Store
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/hybriddemo/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.example.hybriddemo", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo;
2 |
3 | import android.os.Bundle;
4 | import android.widget.FrameLayout;
5 |
6 | import androidx.annotation.Nullable;
7 | import androidx.appcompat.app.AppCompatActivity;
8 |
9 | import com.example.hybriddemo.core.JsApplication;
10 | import com.example.hybriddemo.core.JsBundle;
11 |
12 | public class MainActivity extends AppCompatActivity {
13 |
14 | private static final String JS_CODE = "const hello = \"Hello \";\n" +
15 | "const title = hello + \"Hybrid World\"\n" +
16 | "$view.render({\n" +
17 | " rootView: {\n" +
18 | " type: \"verticalLayout\",\n" +
19 | " children: [\n" +
20 | " {\n" +
21 | " \"type\": \"text\",\n" +
22 | " \"text\": title,\n" +
23 | " \"textSize\": 24,\n" +
24 | " \"marginTop\": 32\n" +
25 | " },\n" +
26 | " {\n" +
27 | " \"type\": \"image\",\n" +
28 | " \"width\": 172,\n" +
29 | " \"height\": 172,\n" +
30 | " \"marginTop\": 120,\n" +
31 | " \"url\": \"\"\n" +
32 | " },\n" +
33 | " {\n" +
34 | " \"type\": \"button\",\n" +
35 | " \"text\": \"点击打印日志\",\n" +
36 | " \"marginTop\": 80,\n" +
37 | " \"marginLeft\": 40,\n" +
38 | " \"marginRight\": 40,\n" +
39 | " \"onClick\": function () {\n" +
40 | " console.info(\"success!\")\n" +
41 | " }\n" +
42 | " }\n" +
43 | " ]\n" +
44 | " }\n" +
45 | "})";
46 |
47 | @Override
48 | protected void onCreate(@Nullable Bundle savedInstanceState) {
49 | super.onCreate(savedInstanceState);
50 | setContentView(R.layout.activity_main);
51 |
52 | FrameLayout containerView = findViewById(R.id.js_container_view);
53 |
54 | JsBundle jsBundle = new JsBundle();
55 | jsBundle.setAppJavaScript(JS_CODE);
56 |
57 | JsApplication jsApplication = JsApplication.init(this, containerView);
58 | jsApplication.run(jsBundle);
59 |
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/JSBridge.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core;
2 |
3 | import com.example.hybriddemo.core.module.JsModule;
4 |
5 | public class JSBridge {
6 | private JsContext mJsContext;
7 |
8 | public JSBridge(JsContext jsContext) {
9 | mJsContext = jsContext;
10 | }
11 |
12 | public void registerJavaMethod(JsModule jsModule) {
13 |
14 | }
15 |
16 | public Object executeJs(String js) {
17 | return null;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/JsApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core;
2 |
3 | import android.content.Context;
4 | import android.view.ViewGroup;
5 |
6 | import com.example.hybriddemo.core.module.ModuleManager;
7 | import com.example.hybriddemo.core.ui.RenderManager;
8 |
9 | public class JsApplication {
10 | private JsContext mJsContext;
11 |
12 | public static JsApplication init(Context context, ViewGroup containerView) {
13 | JsApplication jsApplication = new JsApplication();
14 | JsContext jsContext = new JsContext();
15 | jsApplication.mJsContext = jsContext;
16 | RenderManager.getInstance().init(context, containerView);
17 | ModuleManager.getInstance().init(jsContext);
18 | return jsApplication;
19 | }
20 |
21 | public void run(JsBundle jsBundle) {
22 | mJsContext.runApplication(jsBundle);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/JsBundle.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core;
2 |
3 | public class JsBundle {
4 |
5 | private String mAppJavaScript;
6 |
7 | public String getAppJavaScript() {
8 | return mAppJavaScript;
9 | }
10 |
11 | public void setAppJavaScript(String appJavaScript) {
12 | this.mAppJavaScript = appJavaScript;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/JsContext.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core;
2 |
3 | import com.eclipsesource.v8.V8;
4 |
5 | public class JsContext {
6 |
7 | private V8 mEngine;
8 |
9 | public JsContext() {
10 | init();
11 | }
12 |
13 | private void init() {
14 | mEngine = V8.createV8Runtime();
15 | }
16 |
17 | public V8 getEngine() {
18 | return mEngine;
19 | }
20 |
21 | public void runApplication(JsBundle jsBundle) {
22 | mEngine.executeStringScript(jsBundle.getAppJavaScript());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/module/JsModule.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.module;
2 |
3 | import com.eclipsesource.v8.V8Array;
4 |
5 | import java.util.List;
6 |
7 | public abstract class JsModule {
8 |
9 | public abstract String getName();
10 |
11 | public abstract List getFunctionNames();
12 |
13 | public abstract Object execute(String functionName, V8Array params);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/module/ModuleManager.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.module;
2 |
3 | import com.eclipsesource.v8.V8Object;
4 | import com.example.hybriddemo.core.JsContext;
5 | import com.example.hybriddemo.module.ConsoleModule;
6 | import com.example.hybriddemo.module.UiModule;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | public class ModuleManager {
12 |
13 | private ModuleManager() {
14 | }
15 |
16 | private static class Holder {
17 | private static final ModuleManager INSTANCE = new ModuleManager();
18 | }
19 |
20 | public static ModuleManager getInstance() {
21 | return Holder.INSTANCE;
22 | }
23 |
24 | private final List mModuleList = new ArrayList<>();
25 | private JsContext mJsContext;
26 |
27 | public void init(JsContext jsContext) {
28 | mJsContext = jsContext;
29 | mModuleList.add(new UiModule());
30 | mModuleList.add(new ConsoleModule());
31 | registerModules();
32 | }
33 |
34 | private void registerModules() {
35 | for (JsModule module : mModuleList) {
36 | V8Object moduleObj = new V8Object(mJsContext.getEngine());
37 | for (String functionName : module.getFunctionNames()) {
38 | moduleObj.registerJavaMethod((v8Object, params) -> {
39 | return module.execute(functionName, params);
40 | }, functionName);
41 | }
42 | mJsContext.getEngine().add(module.getName(), moduleObj);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/JsView.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 |
7 | import com.example.hybriddemo.core.ui.dom.DomElement;
8 |
9 | public abstract class JsView {
10 |
11 | protected D mDomElement;
12 | protected V mNativeView;
13 |
14 | public void setDomElement(DomElement domElement) {
15 | mDomElement = (D) domElement;
16 | }
17 |
18 | public abstract String getType();
19 |
20 | public abstract V createViewInternal(Context context);
21 |
22 | public V createView(Context context) {
23 | V view = createViewInternal(context);
24 | mNativeView = view;
25 | ViewGroup.MarginLayoutParams layoutParams =
26 | new ViewGroup.MarginLayoutParams(getWidth(context), getHeight(context));
27 | layoutParams.setMargins(dp2px(mDomElement.marginLeft, context), dp2px(mDomElement.marginTop, context),
28 | dp2px(mDomElement.marginRight, context), dp2px(mDomElement.marginBottom, context));
29 | view.setLayoutParams(layoutParams);
30 | return view;
31 | }
32 |
33 | protected int getWidth(Context context) {
34 | return ViewGroup.LayoutParams.MATCH_PARENT;
35 | }
36 |
37 | protected int getHeight(Context context) {
38 | return ViewGroup.LayoutParams.WRAP_CONTENT;
39 | }
40 |
41 | protected int dp2px(float dp, Context context) {
42 | final float scale = context.getResources().getDisplayMetrics().density;
43 | return (int) (dp * scale + 0.5f);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/JsViewFactory.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui;
2 |
3 | import com.example.hybriddemo.core.ui.dom.DomElement;
4 | import com.example.hybriddemo.core.ui.dom.DomGroup;
5 | import com.example.hybriddemo.view.ButtonJsView;
6 | import com.example.hybriddemo.view.ImageJsView;
7 | import com.example.hybriddemo.view.TextJsView;
8 | import com.example.hybriddemo.view.VerticalLayoutJsView;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | public class JsViewFactory {
14 |
15 | public static JsView create(DomElement domElement) {
16 | String type = domElement.type;
17 | switch (type) {
18 | case "text":
19 | TextJsView textJsView = new TextJsView();
20 | textJsView.setDomElement(domElement);
21 | return textJsView;
22 | case "image":
23 | ImageJsView imageJsView = new ImageJsView();
24 | imageJsView.setDomElement(domElement);
25 | return imageJsView;
26 | case "button":
27 | ButtonJsView buttonJsView = new ButtonJsView();
28 | buttonJsView.setDomElement(domElement);
29 | return buttonJsView;
30 | case "verticalLayout":
31 | VerticalLayoutJsView verticalLayoutJsView = new VerticalLayoutJsView();
32 | verticalLayoutJsView.setDomElement(domElement);
33 | if (domElement instanceof DomGroup) {
34 | List childrenJsView = new ArrayList<>();
35 | for (DomElement childModel : ((DomGroup) domElement).children) {
36 | childrenJsView.add(create(childModel));
37 | }
38 | verticalLayoutJsView.setChildren(childrenJsView);
39 | }
40 | return verticalLayoutJsView;
41 | default:
42 | return null;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/JsViewGroup.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 | import com.example.hybriddemo.core.ui.dom.DomGroup;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | public abstract class JsViewGroup extends JsView {
12 | protected List mChildren = new ArrayList<>();
13 |
14 | public void setChildren(List children) {
15 | mChildren = children;
16 | }
17 |
18 | @Override
19 | public T createView(Context context) {
20 | return super.createView(context);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/RenderManager.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.eclipsesource.v8.V8Object;
9 | import com.example.hybriddemo.core.ui.dom.DomElement;
10 | import com.example.hybriddemo.core.ui.dom.DomFactory;
11 |
12 | public class RenderManager {
13 |
14 | private RenderManager() {
15 | }
16 |
17 | private static class Holder {
18 | private static final RenderManager INSTANCE = new RenderManager();
19 | }
20 |
21 | public static RenderManager getInstance() {
22 | return Holder.INSTANCE;
23 | }
24 |
25 | private Context mContext;
26 | private ViewGroup mContainerView;
27 |
28 | public void init(Context context, ViewGroup containerView) {
29 | mContext = context;
30 | mContainerView = containerView;
31 | }
32 |
33 | public void render(V8Object rootViewObj) {
34 | DomElement rootDomElement = DomFactory.create(rootViewObj);
35 | JsView rootJsView = JsViewFactory.create(rootDomElement);
36 | if (rootJsView != null) {
37 | View rootView = rootJsView.createView(mContext);
38 | mContainerView.addView(rootView);
39 | }
40 | }
41 |
42 | public View findViewById(String id) {
43 | return findViewById(mContainerView, id);
44 | }
45 |
46 | public View findViewById(ViewGroup parent, String id) {
47 | for (int i = 0; i < parent.getChildCount(); i++) {
48 | View child = parent.getChildAt(i);
49 | Object idTag = child.getTag();
50 | if (idTag instanceof String && TextUtils.equals(id, (String) idTag)) {
51 | return child;
52 | }
53 | if (child instanceof ViewGroup) {
54 | return findViewById((ViewGroup) child, id);
55 | }
56 | }
57 | return null;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/dom/DomButton.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui.dom;
2 |
3 | import com.eclipsesource.v8.V8Object;
4 |
5 | public class DomButton extends DomElement {
6 |
7 | public String text;
8 |
9 | @Override
10 | public void parse(V8Object v8Object) {
11 | super.parse(v8Object);
12 | for (String key : v8Object.getKeys()) {
13 | switch (key) {
14 | case "text":
15 | this.text = v8Object.getString("text");
16 | break;
17 | }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/dom/DomElement.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui.dom;
2 |
3 | import com.eclipsesource.v8.V8Function;
4 | import com.eclipsesource.v8.V8Object;
5 |
6 | public class DomElement {
7 |
8 | public String type;
9 | public int marginTop;
10 | public int marginBottom;
11 | public int marginLeft;
12 | public int marginRight;
13 | public V8Function onClick;
14 |
15 | public void parse(V8Object v8Object) {
16 | for (String key : v8Object.getKeys()) {
17 | switch (key) {
18 | case "type":
19 | this.type = v8Object.getString("type");
20 | break;
21 | case "marginTop":
22 | this.marginTop = v8Object.getInteger("marginTop");
23 | break;
24 | case "marginBottom":
25 | this.marginBottom = v8Object.getInteger("marginBottom");
26 | break;
27 | case "marginLeft":
28 | this.marginLeft = v8Object.getInteger("marginLeft");
29 | break;
30 | case "marginRight":
31 | this.marginRight = v8Object.getInteger("marginRight");
32 | break;
33 | case "onClick":
34 | this.onClick = (V8Function) v8Object.get("onClick");
35 | break;
36 | default:
37 | break;
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/dom/DomFactory.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui.dom;
2 |
3 | import com.eclipsesource.v8.V8Object;
4 |
5 | public class DomFactory {
6 |
7 | public static DomElement create(V8Object rootV8Obj) {
8 | String type = rootV8Obj.getString("type");
9 | switch (type) {
10 | case "text":
11 | DomText domText = new DomText();
12 | domText.parse(rootV8Obj);
13 | return domText;
14 | case "image":
15 | DomImage domImage = new DomImage();
16 | domImage.parse(rootV8Obj);
17 | return domImage;
18 | case "button":
19 | DomButton domButton = new DomButton();
20 | domButton.parse(rootV8Obj);
21 | return domButton;
22 | case "verticalLayout":
23 | DomVerticalLayout domVerticalLayout = new DomVerticalLayout();
24 | domVerticalLayout.parse(rootV8Obj);
25 | return domVerticalLayout;
26 | }
27 | return null;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/dom/DomGroup.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui.dom;
2 |
3 | import com.eclipsesource.v8.V8Array;
4 | import com.eclipsesource.v8.V8Object;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class DomGroup extends DomElement {
10 | public List children;
11 |
12 | @Override
13 | public void parse(V8Object v8Object) {
14 | super.parse(v8Object);
15 | List childElements = new ArrayList<>();
16 | V8Array childrenObj = v8Object.getArray("children");
17 | for (int i = 0; i < childrenObj.length(); i++) {
18 | childElements.add(DomFactory.create(childrenObj.getObject(i)));
19 | }
20 | this.children = childElements;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/dom/DomImage.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui.dom;
2 |
3 | import com.eclipsesource.v8.V8Object;
4 |
5 | public class DomImage extends DomElement {
6 |
7 | public int width;
8 | public int height;
9 | public String url;
10 |
11 | @Override
12 | public void parse(V8Object v8Object) {
13 | super.parse(v8Object);
14 | for (String key : v8Object.getKeys()) {
15 | switch (key) {
16 | case "width":
17 | this.width = v8Object.getInteger("width");
18 | break;
19 | case "height":
20 | this.height = v8Object.getInteger("height");
21 | break;
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/dom/DomText.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui.dom;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.eclipsesource.v8.V8Object;
6 |
7 | public class DomText extends DomElement {
8 | public String text;
9 | public int textSize = 16;
10 | public String textColor = "#000000";
11 |
12 | @Override
13 | public void parse(V8Object v8Object) {
14 | super.parse(v8Object);
15 | for (String key : v8Object.getKeys()) {
16 | switch (key) {
17 | case "text":
18 | this.text = v8Object.getString("text");
19 | break;
20 | case "textSize":
21 | int textSize = v8Object.getInteger("textSize");
22 | if (textSize == 0) {
23 | textSize = 16;
24 | }
25 | this.textSize = textSize;
26 | break;
27 | case "textColor":
28 | String textColor = v8Object.getString("textColor");
29 | if (TextUtils.isEmpty(textColor)) {
30 | textColor = "#000000";
31 | }
32 | this.textColor = textColor;
33 | break;
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/core/ui/dom/DomVerticalLayout.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.core.ui.dom;
2 |
3 | public class DomVerticalLayout extends DomGroup {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/module/ConsoleModule.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.module;
2 |
3 | import android.util.Log;
4 |
5 | import com.eclipsesource.v8.V8Array;
6 | import com.example.hybriddemo.core.module.JsModule;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | public class ConsoleModule extends JsModule {
12 |
13 | @Override
14 | public String getName() {
15 | return "console";
16 | }
17 |
18 | @Override
19 | public List getFunctionNames() {
20 | List functions = new ArrayList<>();
21 | functions.add("info");
22 | return functions;
23 | }
24 |
25 | @Override
26 | public Object execute(String functionName, V8Array params) {
27 | switch (functionName) {
28 | case "info":
29 | Log.i("Javascript Console", params.getString(0));
30 | break;
31 | }
32 | return null;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/module/UiModule.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.module;
2 |
3 | import com.eclipsesource.v8.V8Array;
4 | import com.eclipsesource.v8.V8Object;
5 | import com.example.hybriddemo.core.module.JsModule;
6 | import com.example.hybriddemo.core.ui.RenderManager;
7 | import com.example.hybriddemo.core.ui.dom.DomFactory;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class UiModule extends JsModule {
13 | @Override
14 | public String getName() {
15 | return "$view";
16 | }
17 |
18 | @Override
19 | public List getFunctionNames() {
20 | List functionNames = new ArrayList<>();
21 | functionNames.add("render");
22 | return functionNames;
23 | }
24 |
25 | @Override
26 | public Object execute(String functionName, V8Array params) {
27 | switch (functionName) {
28 | case "render":
29 | V8Object param1 = params.getObject(0);
30 | V8Object rootViewObj = param1.getObject("rootView");
31 | RenderManager.getInstance().render(rootViewObj);
32 | break;
33 | }
34 | return null;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/hybriddemo/view/ButtonJsView.java:
--------------------------------------------------------------------------------
1 | package com.example.hybriddemo.view;
2 |
3 | import android.content.Context;
4 | import android.widget.Button;
5 |
6 | import com.example.hybriddemo.core.ui.JsView;
7 | import com.example.hybriddemo.core.ui.dom.DomButton;
8 |
9 | public class ButtonJsView extends JsView