dev android,and complete load context
This commit is contained in:
parent
f2fc57bbc7
commit
2a34d7b638
@ -14,7 +14,7 @@
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -16,6 +16,11 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
assets.srcDirs = [project.rootDir.getParent() + "/js-framework/bundle"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -3,6 +3,7 @@
|
||||
package="com.github.pengfeizhou.hegodemo">
|
||||
|
||||
<application
|
||||
android:name=".MyApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
@ -3,7 +3,8 @@ package com.github.pengfeizhou.hegodemo;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.github.pengfeizhou.hegodemo.R;
|
||||
import com.github.pengfeizhou.hego.HegoContext;
|
||||
import com.github.pengfeizhou.hego.HegoUtils;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@ -11,5 +12,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
HegoContext hegoContext = HegoContext.createContext(HegoUtils.readAssetFile("test.js"), "demo");
|
||||
hegoContext.callJS("");
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,17 @@ package com.github.pengfeizhou.hegodemo;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.github.pengfeizhou.hego.Hego;
|
||||
|
||||
/**
|
||||
* @Description: Android
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class MyApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Hego.init(this);
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,11 @@ android {
|
||||
consumerProguardFiles 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
assets.srcDirs = [project.rootDir.getParent() + "/js-framework/bundle"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -1,9 +1,20 @@
|
||||
package com.github.pengfeizhou.hego;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
/**
|
||||
* @Description: Android
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class Hego {
|
||||
private static Application sApplication;
|
||||
|
||||
public static void init(Application application) {
|
||||
sApplication = application;
|
||||
}
|
||||
|
||||
public static Application application() {
|
||||
return sApplication;
|
||||
}
|
||||
}
|
||||
|
@ -6,4 +6,21 @@ package com.github.pengfeizhou.hego;
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class HegoConstant {
|
||||
public static final String INJECT_LOG = "nativeLog";
|
||||
public static final String INJECT_REQUIRE = "nativeRequire";
|
||||
public static final String INJECT_BRIDGE = "nativeBridge";
|
||||
|
||||
public static final String TEMPLATE_CONTEXT_CREATE = "Reflect.apply(" +
|
||||
"function(hego,context,require,exports){" + "\n" +
|
||||
"%s" + "\n" +
|
||||
"},hego.jsObtainContext(%s),[" +
|
||||
"undefined," +
|
||||
"hego.jsObtainContext(%s)," +
|
||||
"hego.__require__" +
|
||||
",{}" +
|
||||
"])";
|
||||
public static final String TEMPLATE_CONTEXT_DESTORY = "hego.jsRelease(%s)";
|
||||
public static final String GLOBAL_HEGO = "hego";
|
||||
public static final String HEGO_CONTEXT_RELEASE = "jsReleaseContext";
|
||||
public static final String HEGO_CONTEXT_INVOKE = "jsCallEntityMethod";
|
||||
}
|
||||
|
@ -1,9 +1,31 @@
|
||||
package com.github.pengfeizhou.hego;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @Description: Android
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class HegoHolder {
|
||||
public class HegoContext {
|
||||
private static AtomicInteger sCounter = new AtomicInteger();
|
||||
private final String mContextId;
|
||||
|
||||
private HegoContext(String contextId) {
|
||||
this.mContextId = contextId;
|
||||
}
|
||||
|
||||
public static HegoContext createContext(String script, String alias) {
|
||||
String contextId = String.valueOf(sCounter.incrementAndGet());
|
||||
HegoDriver.getInstance().createPage(contextId, script, alias);
|
||||
return new HegoContext(contextId);
|
||||
}
|
||||
|
||||
public void callJS(String methodName, Object... args) {
|
||||
HegoDriver.getInstance().invokeContextMethod(mContextId, methodName, args);
|
||||
}
|
||||
|
||||
public void teardown() {
|
||||
HegoDriver.getInstance().destoryContext(mContextId);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,38 @@
|
||||
package com.github.pengfeizhou.hego;
|
||||
|
||||
import com.github.pengfeizhou.jscore.JSDecoder;
|
||||
|
||||
/**
|
||||
* @Description: Android
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public interface HegoDriver {
|
||||
public class HegoDriver {
|
||||
private final HegoJSEngine hegoJSEngine;
|
||||
|
||||
public HegoSettableFuture<JSDecoder> invokeContextMethod(final String contextId, final String method, final Object... args) {
|
||||
return hegoJSEngine.invokeContextEntityMethod(contextId, method, args);
|
||||
}
|
||||
|
||||
private static class Inner {
|
||||
private static final HegoDriver sInstance = new HegoDriver();
|
||||
}
|
||||
|
||||
private HegoDriver() {
|
||||
hegoJSEngine = new HegoJSEngine();
|
||||
}
|
||||
|
||||
public static HegoDriver getInstance() {
|
||||
return Inner.sInstance;
|
||||
}
|
||||
|
||||
public void createPage(final String contextId, final String script, final String source) {
|
||||
hegoJSEngine.prepareContext(contextId, script, source);
|
||||
}
|
||||
|
||||
public void destoryContext(String contextId) {
|
||||
hegoJSEngine.destroyContext(contextId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,167 @@
|
||||
package com.github.pengfeizhou.hego;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import com.github.pengfeizhou.hego.jse.HegoJSExecutor;
|
||||
import com.github.pengfeizhou.hego.jse.IHegoJSE;
|
||||
import com.github.pengfeizhou.jscore.JSDecoder;
|
||||
import com.github.pengfeizhou.jscore.JavaFunction;
|
||||
import com.github.pengfeizhou.jscore.JavaValue;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* @Description: Android
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class HegoJSEngine {
|
||||
public class HegoJSEngine implements Handler.Callback {
|
||||
private final Handler mJSHandler;
|
||||
private IHegoJSE mHegoJSE;
|
||||
|
||||
public HegoJSEngine() {
|
||||
HandlerThread handlerThread = new HandlerThread(this.getClass().getSimpleName());
|
||||
handlerThread.start();
|
||||
Looper looper = handlerThread.getLooper();
|
||||
mJSHandler = new Handler(looper, this);
|
||||
mJSHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
initJSExecutor();
|
||||
initHugoRuntime();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void initJSExecutor() {
|
||||
mHegoJSE = new HegoJSExecutor();
|
||||
mHegoJSE.injectGlobalJSFunction(HegoConstant.INJECT_LOG, new JavaFunction() {
|
||||
@Override
|
||||
public JavaValue exec(JSDecoder[] args) {
|
||||
try {
|
||||
String type = args[0].string();
|
||||
String message = args[1].string();
|
||||
switch (type) {
|
||||
case "w":
|
||||
HegoLog.w("js", message);
|
||||
break;
|
||||
case "e":
|
||||
HegoLog.e("js", message);
|
||||
break;
|
||||
default:
|
||||
HegoLog.d("js", message);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new JavaValue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initHugoRuntime() {
|
||||
loadBuiltinJS("sandbox.js");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void teardown() {
|
||||
mHegoJSE.teardown();
|
||||
}
|
||||
|
||||
private void loadBuiltinJS(String assetName) {
|
||||
String script = HegoUtils.readAssetFile(assetName);
|
||||
mHegoJSE.loadJS(script, "Assets://" + assetName);
|
||||
}
|
||||
|
||||
public void prepareContext(final String contextId, final String script, final String source) {
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mHegoJSE.loadJS(packageContextScript(script, contextId), "Context://" + source);
|
||||
}
|
||||
};
|
||||
doOnJSThread(runnable);
|
||||
}
|
||||
|
||||
public void doOnJSThread(Runnable runnable) {
|
||||
if (isJSThread()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
mJSHandler.post(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroyContext(final String contextId) {
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mHegoJSE.loadJS(String.format(HegoConstant.TEMPLATE_CONTEXT_DESTORY, contextId), "_Context://" + contextId);
|
||||
}
|
||||
};
|
||||
doOnJSThread(runnable);
|
||||
}
|
||||
|
||||
private String packageContextScript(String content, String contextId) {
|
||||
return String.format(HegoConstant.TEMPLATE_CONTEXT_CREATE, content, contextId, contextId);
|
||||
}
|
||||
|
||||
public boolean isJSThread() {
|
||||
return Looper.myLooper() == mJSHandler.getLooper();
|
||||
}
|
||||
|
||||
public HegoSettableFuture<JSDecoder> invokeContextEntityMethod(final String contextId, final String method, final Object... args) {
|
||||
final Object[] nArgs = new Object[args.length + 2];
|
||||
nArgs[0] = contextId;
|
||||
nArgs[1] = method;
|
||||
if (args.length > 0) {
|
||||
System.arraycopy(args, 0, nArgs, 2, args.length);
|
||||
}
|
||||
return invokeHegoMethod(HegoConstant.HEGO_CONTEXT_INVOKE, args);
|
||||
}
|
||||
|
||||
|
||||
public HegoSettableFuture<JSDecoder> invokeHegoMethod(final String method, final Object... args) {
|
||||
final HegoSettableFuture<JSDecoder> settableFuture = new HegoSettableFuture<>();
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ArrayList<JavaValue> values = new ArrayList<>();
|
||||
for (Object arg : args) {
|
||||
if (arg == null) {
|
||||
values.add(new JavaValue());
|
||||
} else if (arg instanceof JSONObject) {
|
||||
values.add(new JavaValue((JSONObject) arg));
|
||||
} else if (arg instanceof String) {
|
||||
values.add(new JavaValue((String) arg));
|
||||
} else if (arg instanceof Integer) {
|
||||
values.add(new JavaValue((Integer) arg));
|
||||
} else if (arg instanceof Double) {
|
||||
values.add(new JavaValue((Double) arg));
|
||||
} else if (arg instanceof Boolean) {
|
||||
values.add(new JavaValue((Boolean) arg));
|
||||
} else if (arg instanceof JavaValue) {
|
||||
values.add((JavaValue) arg);
|
||||
} else {
|
||||
values.add(new JavaValue(String.valueOf(arg)));
|
||||
}
|
||||
}
|
||||
settableFuture.set(mHegoJSE.invokeMethod(HegoConstant.GLOBAL_HEGO, method,
|
||||
values.toArray(new JavaValue[values.size()]), true));
|
||||
}
|
||||
};
|
||||
doOnJSThread(runnable);
|
||||
return settableFuture;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,24 @@
|
||||
package com.github.pengfeizhou.hego;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* @Description: Android
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class HegoLog {
|
||||
private static String TAG = Hego.class.getSimpleName();
|
||||
|
||||
public static void d(String suffix, String message) {
|
||||
Log.d(TAG + suffix, message);
|
||||
}
|
||||
|
||||
public static void w(String suffix, String message) {
|
||||
Log.w(TAG + suffix, message);
|
||||
}
|
||||
|
||||
public static void e(String suffix, String message) {
|
||||
Log.e(TAG + suffix, message);
|
||||
}
|
||||
}
|
||||
|
@ -5,5 +5,54 @@ package com.github.pengfeizhou.hego;
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class HegoSettableFuture {
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A super simple Future-like class that can safely notify another Thread when a value is ready.
|
||||
* Does not support setting errors or canceling.
|
||||
*/
|
||||
public class HegoSettableFuture<T> {
|
||||
|
||||
private final CountDownLatch mReadyLatch = new CountDownLatch(1);
|
||||
private volatile
|
||||
T mResult;
|
||||
|
||||
/**
|
||||
* Sets the result. If another thread has called {@link #get}, they will immediately receive the
|
||||
* value. Must only be called once.
|
||||
*/
|
||||
public void set(T result) {
|
||||
if (mReadyLatch.getCount() == 0) {
|
||||
throw new RuntimeException("Result has already been set!");
|
||||
}
|
||||
mResult = result;
|
||||
mReadyLatch.countDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait up to the timeout time for another Thread to set a value on this future. If a value has
|
||||
* already been set, this method will return immediately.
|
||||
* <p>
|
||||
* NB: For simplicity, we catch and wrap InterruptedException. Do NOT use this class if you
|
||||
* are in the 1% of cases where you actually want to handle that.
|
||||
*/
|
||||
public T get(long timeoutMS) {
|
||||
try {
|
||||
if (!mReadyLatch.await(timeoutMS, TimeUnit.MILLISECONDS)) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return mResult;
|
||||
}
|
||||
|
||||
public static class TimeoutException extends RuntimeException {
|
||||
|
||||
public TimeoutException() {
|
||||
super("Timed out waiting for future");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,36 @@
|
||||
package com.github.pengfeizhou.hego;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @Description: Android
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class HegoUtils {
|
||||
public static String readAssetFile(String assetFile) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
AssetManager assetManager = Hego.application().getAssets();
|
||||
inputStream = assetManager.open(assetFile);
|
||||
int length = inputStream.available();
|
||||
byte[] buffer = new byte[length];
|
||||
inputStream.read(buffer);
|
||||
return new String(buffer);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -11,11 +11,11 @@ import com.github.pengfeizhou.jscore.JavaValue;
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public class HugoJSExecutor implements IHugoJSE {
|
||||
public class HegoJSExecutor implements IHegoJSE {
|
||||
|
||||
private final JSExecutor mJSExecutor;
|
||||
|
||||
public HugoJSExecutor() {
|
||||
public HegoJSExecutor() {
|
||||
this.mJSExecutor = JSExecutor.create();
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import com.github.pengfeizhou.jscore.JavaValue;
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-07-18
|
||||
*/
|
||||
public interface IHugoJSE {
|
||||
public interface IHegoJSE {
|
||||
/**
|
||||
* 执行JS语句
|
||||
*
|
||||
|
29
js-framework/index.test.ts
Normal file
29
js-framework/index.test.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Text, Alignment, Color, VLayout, Registor, Panel, log, logw, loge } from "./index"
|
||||
|
||||
const v = new Text
|
||||
v.width = 20
|
||||
v.height = 30
|
||||
v.left = 5
|
||||
v.top = 5
|
||||
v.bgColor = Color.parse('#00ff00')
|
||||
v.config = {
|
||||
alignment: Alignment.start
|
||||
}
|
||||
console.log(v.toModel())
|
||||
|
||||
const layout = new VLayout
|
||||
layout.space = 10
|
||||
console.log(layout.viewId)
|
||||
console.log(layout.toModel())
|
||||
|
||||
@Registor
|
||||
export class MyPage extends Panel {
|
||||
build() {
|
||||
return layout
|
||||
}
|
||||
log() {
|
||||
log("Hello.HEGO")
|
||||
logw("Hello.HEGO")
|
||||
loge("Hello.HEGO")
|
||||
}
|
||||
}
|
@ -1,31 +1,4 @@
|
||||
import { Text, Alignment, VLayout, Gravity } from "./src/ui/view";
|
||||
import { Color } from "./src/util/color";
|
||||
import { Panel, Registor } from "./src/ui/panel";
|
||||
|
||||
export * from "./src/ui/view"
|
||||
export * from "./src/ui/panel"
|
||||
export * from "./src/util/color"
|
||||
|
||||
const v = new Text
|
||||
v.width = 20
|
||||
v.height = 30
|
||||
v.left = 5
|
||||
v.top = 5
|
||||
v.bgColor = Color.parse('#00ff00')
|
||||
v.config = {
|
||||
alignment: Alignment.start
|
||||
}
|
||||
console.log(v.toModel())
|
||||
|
||||
const layout = new VLayout
|
||||
layout.space = 10
|
||||
console.log(layout.viewId)
|
||||
console.log(layout.toModel())
|
||||
|
||||
// @Registor
|
||||
class MyPage extends Panel {
|
||||
build(): import("./src/ui/view").View {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
console.log('end')
|
||||
export * from './src/util/log'
|
@ -29,4 +29,17 @@ export default [
|
||||
commonjs()
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "build/index.test.js",
|
||||
output: {
|
||||
format: "cjs",
|
||||
file: "bundle/test.js",
|
||||
},
|
||||
sourceMap: true,
|
||||
plugins: [
|
||||
resolve({ jsnext: true, main: true }),
|
||||
commonjs()
|
||||
],
|
||||
external: ['./index'],
|
||||
},
|
||||
]
|
@ -8,9 +8,9 @@ import { loge } from "../util/log";
|
||||
* function(hego,context,require){
|
||||
* //Script content
|
||||
* REG()
|
||||
* },hego.obtainContext(id),[
|
||||
* },hego.jsObtainContext(id),[
|
||||
* undefined,
|
||||
* hego.obtainContext(id),
|
||||
* hego.jsObtainContext(id),
|
||||
* hego.__require__,
|
||||
* ])
|
||||
* // load module in global scope
|
||||
@ -24,6 +24,7 @@ import { loge } from "../util/log";
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
|
||||
declare function nativeRequire(moduleName: string): boolean
|
||||
|
||||
declare function nativeBridge(contextId: string, namespace: string, method: string, args?: any, callbackId?: string): boolean
|
||||
|
@ -1,11 +1,29 @@
|
||||
declare function nativeLog(type: 'd' | 'w' | 'e', message: string): void
|
||||
|
||||
function toString(message: any) {
|
||||
if (message instanceof Function) {
|
||||
return message.toString()
|
||||
} else if (message instanceof Object) {
|
||||
try {
|
||||
return JSON.stringify(message)
|
||||
} catch (e) {
|
||||
return message.toString()
|
||||
}
|
||||
} else if (message === undefined) {
|
||||
return "undefined"
|
||||
} else {
|
||||
return message.toString()
|
||||
}
|
||||
}
|
||||
|
||||
export function log(message: any) {
|
||||
console.log(message)
|
||||
nativeLog('d', toString(message))
|
||||
}
|
||||
|
||||
export function loge(message: any) {
|
||||
console.error(message)
|
||||
nativeLog('e', toString(message))
|
||||
}
|
||||
|
||||
export function logw(message: any) {
|
||||
console.warn(message)
|
||||
nativeLog('w', toString(message))
|
||||
}
|
||||
|
Reference in New Issue
Block a user