Android support internal class

This commit is contained in:
pengfei.zhou 2020-09-04 18:22:45 +08:00 committed by osborn
parent a211ac8acb
commit 4df7df1327
16 changed files with 343 additions and 48 deletions

View File

@ -16,6 +16,7 @@
package pub.doric.loader; package pub.doric.loader;
import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import java.util.Collection; import java.util.Collection;
@ -56,6 +57,13 @@ public class DoricJSLoaderManager {
public AsyncResult<String> loadJSBundle(String source) { public AsyncResult<String> loadJSBundle(String source) {
if (!TextUtils.isEmpty(source)) { if (!TextUtils.isEmpty(source)) {
if (source.startsWith("_internal_")) {
Uri uri = Uri.parse(source);
String srcContextId = uri.getQueryParameter("context");
String className = uri.getQueryParameter("class");
source = String.format("Entry('%s','%s')", srcContextId, className);
return new AsyncResult<>(source);
}
Collection<IDoricJSLoader> jsLoaders = getJSLoaders(); Collection<IDoricJSLoader> jsLoaders = getJSLoaders();
for (IDoricJSLoader jsLoader : jsLoaders) { for (IDoricJSLoader jsLoader : jsLoaders) {
if (jsLoader.filter(source)) { if (jsLoader.filter(source)) {

View File

@ -2,7 +2,7 @@ import { Group, Panel, text, Color, LayoutSpec, vlayout, Gravity, scroller, layo
import { colors, label } from "./utils"; import { colors, label } from "./utils";
@Entry @Entry
class ModalDemo extends Panel { export class ModalDemo extends Panel {
build(rootView: Group): void { build(rootView: Group): void {
scroller( scroller(
vlayout( vlayout(

View File

@ -0,0 +1,97 @@
import { Group, Panel, navbar, text, gravity, Color, LayoutSpec, vlayout, Gravity, hlayout, scroller, layoutConfig, image, modal, navigator, ViewHolder, Text, ViewModel, VMPanel } from "doric";
import { title, label, colors } from "./utils";
import { ModalDemo } from "./ModalDemo";
interface CountModel {
count: number
}
class CounterView extends ViewHolder {
number!: Text
counter!: Text
build(root: Group) {
vlayout(
[
text({
textSize: 40,
tag: "tvNumber"
}),
text({
text: "Click To Count 1",
textSize: 20,
tag: "tvCounter"
}),
],
{
layoutConfig: layoutConfig().most(),
gravity: Gravity.Center,
space: 20,
}
).in(root)
this.number = root.findViewByTag("tvNumber")!
this.counter = root.findViewByTag("tvCounter")!
}
}
class CounterVM extends ViewModel<CountModel, CounterView> {
onAttached(s: CountModel, vh: CounterView) {
vh.counter.onClick = () => {
this.updateState(state => {
state.count++
})
}
}
onBind(s: CountModel, vh: CounterView) {
vh.number.text = `${s.count}`
}
}
class MyPage extends VMPanel<CountModel, CounterView>{
getViewHolderClass() {
return CounterView
}
getViewModelClass() {
return CounterVM
}
getState(): CountModel {
return {
count: 0
}
}
}
@Entry(exports = [ModalDemo, MyPage])
class MultiPanelDemo extends Panel {
build(rootView: Group): void {
scroller(
vlayout(
[
title("Multi Panel"),
label('isHidden').apply({
width: 200,
height: 50,
backgroundColor: colors[0],
textSize: 30,
textColor: Color.WHITE,
layoutConfig: layoutConfig().just(),
onClick: () => {
navigator(context).push(ModalDemo)
}
}),
],
{
layoutConfig: layoutConfig().most().configHeight(LayoutSpec.FIT),
gravity: gravity().center(),
space: 10,
}),
{
layoutConfig: layoutConfig().most(),
backgroundColor: Color.BLUE,
}
).in(rootView)
}
}

View File

@ -2963,6 +2963,9 @@ function navigator(context) {
var moduleName = "navigator"; var moduleName = "navigator";
return { return {
push: function (source, config) { push: function (source, config) {
if (typeof source === 'function') {
source = "_internal_://export?class=" + encodeURIComponent(source.name) + "&context=" + context.id;
}
if (config && config.extra) { if (config && config.extra) {
config.extra = JSON.stringify(config.extra); config.extra = JSON.stringify(config.extra);
} }

View File

@ -2295,6 +2295,9 @@ function navigator(context) {
const moduleName = "navigator"; const moduleName = "navigator";
return { return {
push: (source, config) => { push: (source, config) => {
if (typeof source === 'function') {
source = `_internal_://export?class=${encodeURIComponent(source.name)}&context=${context.id}`;
}
if (config && config.extra) { if (config && config.extra) {
config.extra = JSON.stringify(config.extra); config.extra = JSON.stringify(config.extra);
} }

View File

@ -1280,6 +1280,7 @@ var doric = (function (exports) {
var Context = /** @class */ (function () { var Context = /** @class */ (function () {
function Context(id) { function Context(id) {
this.callbacks = new Map; this.callbacks = new Map;
this.classes = new Map;
this.id = id; this.id = id;
} }
Context.prototype.hookBeforeNativeCall = function () { Context.prototype.hookBeforeNativeCall = function () {
@ -1395,6 +1396,8 @@ var doric = (function (exports) {
function jsObtainEntry(contextId) { function jsObtainEntry(contextId) {
var context = jsObtainContext(contextId); var context = jsObtainContext(contextId);
var exportFunc = function (constructor) { var exportFunc = function (constructor) {
var _a;
(_a = context === null || context === void 0 ? void 0 : context.classes) === null || _a === void 0 ? void 0 : _a.set(constructor.name, constructor);
var ret = /** @class */ (function (_super) { var ret = /** @class */ (function (_super) {
__extends(class_1, _super); __extends(class_1, _super);
function class_1() { function class_1() {
@ -1404,18 +1407,43 @@ var doric = (function (exports) {
} }
return class_1; return class_1;
}(constructor)); }(constructor));
if (context) { context === null || context === void 0 ? void 0 : context.register(new ret);
context.register(new ret);
}
return ret; return ret;
}; };
return function (args) { return function () {
if (arguments.length === 1) {
var args = arguments[0];
if (args instanceof Array) { if (args instanceof Array) {
args.forEach(function (clz) {
var _a;
(_a = context === null || context === void 0 ? void 0 : context.classes) === null || _a === void 0 ? void 0 : _a.set(clz.name, clz);
});
return exportFunc; return exportFunc;
} }
else { else {
return exportFunc(args); return exportFunc(args);
} }
}
else if (arguments.length === 2) {
var srcContextId = arguments[0];
var className = arguments[1];
var srcContext = gContexts.get(srcContextId);
if (srcContext) {
var clz = srcContext.classes.get(className);
if (clz) {
return exportFunc(clz);
}
else {
throw new Error("Cannot find class:" + className + " in context:" + srcContextId);
}
}
else {
throw new Error("Cannot find context for " + srcContextId);
}
}
else {
throw new Error("Entry arguments error:" + arguments);
}
}; };
} }
var global$1 = Function('return this')(); var global$1 = Function('return this')();

View File

@ -1256,6 +1256,7 @@ var doric = (function (exports) {
class Context { class Context {
constructor(id) { constructor(id) {
this.callbacks = new Map; this.callbacks = new Map;
this.classes = new Map;
this.id = id; this.id = id;
return new Proxy(this, { return new Proxy(this, {
get: (target, p) => { get: (target, p) => {
@ -1396,24 +1397,51 @@ var doric = (function (exports) {
function jsObtainEntry(contextId) { function jsObtainEntry(contextId) {
const context = jsObtainContext(contextId); const context = jsObtainContext(contextId);
const exportFunc = (constructor) => { const exportFunc = (constructor) => {
var _a;
(_a = context === null || context === void 0 ? void 0 : context.classes) === null || _a === void 0 ? void 0 : _a.set(constructor.name, constructor);
const ret = class extends constructor { const ret = class extends constructor {
constructor() { constructor() {
super(...arguments); super(...arguments);
this.context = context; this.context = context;
} }
}; };
if (context) { context === null || context === void 0 ? void 0 : context.register(new ret);
context.register(new ret);
}
return ret; return ret;
}; };
return (args) => { return function () {
if (arguments.length === 1) {
const args = arguments[0];
if (args instanceof Array) { if (args instanceof Array) {
args.forEach(clz => {
var _a;
(_a = context === null || context === void 0 ? void 0 : context.classes) === null || _a === void 0 ? void 0 : _a.set(clz.name, clz);
});
return exportFunc; return exportFunc;
} }
else { else {
return exportFunc(args); return exportFunc(args);
} }
}
else if (arguments.length === 2) {
const srcContextId = arguments[0];
const className = arguments[1];
const srcContext = gContexts.get(srcContextId);
if (srcContext) {
const clz = srcContext.classes.get(className);
if (clz) {
return exportFunc(clz);
}
else {
throw new Error(`Cannot find class:${className} in context:${srcContextId}`);
}
}
else {
throw new Error(`Cannot find context for ${srcContextId}`);
}
}
else {
throw new Error(`Entry arguments error:${arguments}`);
}
}; };
} }
const global$1 = Function('return this')(); const global$1 = Function('return this')();

View File

@ -1279,6 +1279,7 @@ function jsCallReject(contextId, callbackId, args) {
class Context { class Context {
constructor(id) { constructor(id) {
this.callbacks = new Map; this.callbacks = new Map;
this.classes = new Map;
this.id = id; this.id = id;
return new Proxy(this, { return new Proxy(this, {
get: (target, p) => { get: (target, p) => {
@ -1419,24 +1420,51 @@ function jsCallEntityMethod(contextId, methodName, args) {
function jsObtainEntry(contextId) { function jsObtainEntry(contextId) {
const context = jsObtainContext(contextId); const context = jsObtainContext(contextId);
const exportFunc = (constructor) => { const exportFunc = (constructor) => {
var _a;
(_a = context === null || context === void 0 ? void 0 : context.classes) === null || _a === void 0 ? void 0 : _a.set(constructor.name, constructor);
const ret = class extends constructor { const ret = class extends constructor {
constructor() { constructor() {
super(...arguments); super(...arguments);
this.context = context; this.context = context;
} }
}; };
if (context) { context === null || context === void 0 ? void 0 : context.register(new ret);
context.register(new ret);
}
return ret; return ret;
}; };
return (args) => { return function () {
if (arguments.length === 1) {
const args = arguments[0];
if (args instanceof Array) { if (args instanceof Array) {
args.forEach(clz => {
var _a;
(_a = context === null || context === void 0 ? void 0 : context.classes) === null || _a === void 0 ? void 0 : _a.set(clz.name, clz);
});
return exportFunc; return exportFunc;
} }
else { else {
return exportFunc(args); return exportFunc(args);
} }
}
else if (arguments.length === 2) {
const srcContextId = arguments[0];
const className = arguments[1];
const srcContext = gContexts.get(srcContextId);
if (srcContext) {
const clz = srcContext.classes.get(className);
if (clz) {
return exportFunc(clz);
}
else {
throw new Error(`Cannot find class:${className} in context:${srcContextId}`);
}
}
else {
throw new Error(`Cannot find context for ${srcContextId}`);
}
}
else {
throw new Error(`Entry arguments error:${arguments}`);
}
}; };
} }
const global$1 = Function('return this')(); const global$1 = Function('return this')();
@ -3762,6 +3790,9 @@ function navigator(context) {
const moduleName = "navigator"; const moduleName = "navigator";
return { return {
push: (source, config) => { push: (source, config) => {
if (typeof source === 'function') {
source = `_internal_://export?class=${encodeURIComponent(source.name)}&context=${context.id}`;
}
if (config && config.extra) { if (config && config.extra) {
config.extra = JSON.stringify(config.extra); config.extra = JSON.stringify(config.extra);
} }

4
doric-js/index.d.ts vendored
View File

@ -840,8 +840,10 @@ declare module 'doric/lib/src/native/navbar' {
declare module 'doric/lib/src/native/navigator' { declare module 'doric/lib/src/native/navigator' {
import { BridgeContext } from "doric/lib/src/runtime/global"; import { BridgeContext } from "doric/lib/src/runtime/global";
import { ClassType } from "doric/lib/src/pattern/mvvm";
import { Panel } from "doric/lib/src/ui/panel";
export function navigator(context: BridgeContext): { export function navigator(context: BridgeContext): {
push: (source: string, config?: { push: (source: string | ClassType<Panel>, config?: {
alias?: string | undefined; alias?: string | undefined;
animated?: boolean | undefined; animated?: boolean | undefined;
extra?: object | undefined; extra?: object | undefined;

View File

@ -1,6 +1,8 @@
import { BridgeContext } from "../runtime/global"; import { BridgeContext } from "../runtime/global";
import { ClassType } from "../pattern/mvvm";
import { Panel } from "../ui/panel";
export declare function navigator(context: BridgeContext): { export declare function navigator(context: BridgeContext): {
push: (source: string, config?: { push: (source: string | ClassType<Panel>, config?: {
alias?: string | undefined; alias?: string | undefined;
animated?: boolean | undefined; animated?: boolean | undefined;
extra?: object | undefined; extra?: object | undefined;

View File

@ -2,6 +2,9 @@ export function navigator(context) {
const moduleName = "navigator"; const moduleName = "navigator";
return { return {
push: (source, config) => { push: (source, config) => {
if (typeof source === 'function') {
source = `_internal_://export?class=${encodeURIComponent(source.name)}&context=${context.id}`;
}
if (config && config.extra) { if (config && config.extra) {
config.extra = JSON.stringify(config.extra); config.extra = JSON.stringify(config.extra);
} }

View File

@ -8,6 +8,7 @@ export declare class Context {
resolve: Function; resolve: Function;
reject: Function; reject: Function;
}>; }>;
classes: Map<string, ClassType<object>>;
hookBeforeNativeCall(): void; hookBeforeNativeCall(): void;
hookAfterNativeCall(): void; hookAfterNativeCall(): void;
constructor(id: string); constructor(id: string);
@ -22,7 +23,7 @@ export declare function __require__(name: string): any;
export declare function jsRegisterModule(name: string, moduleObject: any): void; export declare function jsRegisterModule(name: string, moduleObject: any): void;
export declare function jsCallEntityMethod(contextId: string, methodName: string, args?: any): any; export declare function jsCallEntityMethod(contextId: string, methodName: string, args?: any): any;
declare type ClassType<T> = new (...args: any) => T; declare type ClassType<T> = new (...args: any) => T;
export declare function jsObtainEntry(contextId: string): (args: ClassType<object> | ClassType<object>[]) => ((constructor: ClassType<object>) => { export declare function jsObtainEntry(contextId: string): () => ((constructor: ClassType<object>) => {
new (...args: any): { new (...args: any): {
context: Context | undefined; context: Context | undefined;
}; };

View File

@ -74,6 +74,7 @@ export function jsCallReject(contextId, callbackId, args) {
export class Context { export class Context {
constructor(id) { constructor(id) {
this.callbacks = new Map; this.callbacks = new Map;
this.classes = new Map;
this.id = id; this.id = id;
return new Proxy(this, { return new Proxy(this, {
get: (target, p) => { get: (target, p) => {
@ -214,24 +215,51 @@ export function jsCallEntityMethod(contextId, methodName, args) {
export function jsObtainEntry(contextId) { export function jsObtainEntry(contextId) {
const context = jsObtainContext(contextId); const context = jsObtainContext(contextId);
const exportFunc = (constructor) => { const exportFunc = (constructor) => {
var _a;
(_a = context === null || context === void 0 ? void 0 : context.classes) === null || _a === void 0 ? void 0 : _a.set(constructor.name, constructor);
const ret = class extends constructor { const ret = class extends constructor {
constructor() { constructor() {
super(...arguments); super(...arguments);
this.context = context; this.context = context;
} }
}; };
if (context) { context === null || context === void 0 ? void 0 : context.register(new ret);
context.register(new ret);
}
return ret; return ret;
}; };
return (args) => { return function () {
if (arguments.length === 1) {
const args = arguments[0];
if (args instanceof Array) { if (args instanceof Array) {
args.forEach(clz => {
var _a;
(_a = context === null || context === void 0 ? void 0 : context.classes) === null || _a === void 0 ? void 0 : _a.set(clz.name, clz);
});
return exportFunc; return exportFunc;
} }
else { else {
return exportFunc(args); return exportFunc(args);
} }
}
else if (arguments.length === 2) {
const srcContextId = arguments[0];
const className = arguments[1];
const srcContext = gContexts.get(srcContextId);
if (srcContext) {
const clz = srcContext.classes.get(className);
if (clz) {
return exportFunc(clz);
}
else {
throw new Error(`Cannot find class:${className} in context:${srcContextId}`);
}
}
else {
throw new Error(`Cannot find context for ${srcContextId}`);
}
}
else {
throw new Error(`Entry arguments error:${arguments}`);
}
}; };
} }
const global = Function('return this')(); const global = Function('return this')();

View File

@ -14,16 +14,21 @@
* limitations under the License. * limitations under the License.
*/ */
import { BridgeContext } from "../runtime/global" import { BridgeContext } from "../runtime/global"
import { ClassType } from "../pattern/mvvm"
import { Panel } from "../ui/panel"
export function navigator(context: BridgeContext) { export function navigator(context: BridgeContext) {
const moduleName = "navigator" const moduleName = "navigator"
return { return {
push: (source: string, config?: { push: (source: string | ClassType<Panel>, config?: {
alias?: string, alias?: string,
animated?: boolean, animated?: boolean,
extra?: object, extra?: object,
singlePage?: boolean, singlePage?: boolean,
}) => { }) => {
if (typeof source === 'function') {
source = `_internal_://export?class=${encodeURIComponent(source.name)}&context=${context.id}`
}
if (config && config.extra) { if (config && config.extra) {
(config as any).extra = JSON.stringify(config.extra) (config as any).extra = JSON.stringify(config.extra)
} }

View File

@ -117,6 +117,7 @@ export class Context {
entity: any entity: any
id: string id: string
callbacks: Map<string, { resolve: Function, reject: Function }> = new Map callbacks: Map<string, { resolve: Function, reject: Function }> = new Map
classes: Map<string, ClassType<object>> = new Map
hookBeforeNativeCall() { hookBeforeNativeCall() {
if (this.entity && Reflect.has(this.entity, 'hookBeforeNativeCall')) { if (this.entity && Reflect.has(this.entity, 'hookBeforeNativeCall')) {
@ -233,29 +234,50 @@ export function jsCallEntityMethod(contextId: string, methodName: string, args?:
loge(`Cannot find method for context id:${contextId},method name is:${methodName}`) loge(`Cannot find method for context id:${contextId},method name is:${methodName}`)
} }
} }
type ClassType<T> = new (...args: any) => T type ClassType<T> = new (...args: any) => T
export function jsObtainEntry(contextId: string) { export function jsObtainEntry(contextId: string) {
const context = jsObtainContext(contextId) const context = jsObtainContext(contextId)
const exportFunc = (constructor: ClassType<object>) => { const exportFunc = (constructor: ClassType<object>) => {
context?.classes?.set(constructor.name, constructor)
const ret = class extends constructor { const ret = class extends constructor {
context = context context = context
} }
if (context) { context?.register(new ret)
context.register(new ret)
}
return ret return ret
} }
return (args: ClassType<object> | ClassType<object>[]) => { return function () {
if (arguments.length === 1) {
const args = arguments[0]
if (args instanceof Array) { if (args instanceof Array) {
args.forEach(clz => {
context?.classes?.set(clz.name, clz)
})
return exportFunc return exportFunc
} else { } else {
return exportFunc(args) return exportFunc(args)
} }
} else if (arguments.length === 2) {
const srcContextId = arguments[0] as string
const className = arguments[1] as string
const srcContext = gContexts.get(srcContextId)
if (srcContext) {
const clz = srcContext.classes.get(className)
if (clz) {
return exportFunc(clz)
} else {
throw new Error(`Cannot find class:${className} in context:${srcContextId}`)
}
} else {
throw new Error(`Cannot find context for ${srcContextId}`)
}
} else {
throw new Error(`Entry arguments error:${arguments}`)
}
} }
} }
const global = Function('return this')() const global = Function('return this')()
let __timerId__ = 0 let __timerId__ = 0

View File

@ -30,6 +30,17 @@ import "reflect-metadata"
* doric.jsObtainEntry(id), * doric.jsObtainEntry(id),
* doric.__require__, * doric.__require__,
* ]) * ])
* // Direct load class
* Reflect.apply(
* function(doric,context,Entry,require){
* //Script content
* Entry('lastContextId','className')
* },doric.jsObtainContext(id),[
* undefined,
* doric.jsObtainContext(id),
* doric.jsObtainEntry(id),
* doric.__require__,
* ])
* // load module in global scope * // load module in global scope
* Reflect.apply(doric.jsRegisterModule,this,[ * Reflect.apply(doric.jsRegisterModule,this,[
* moduleName, * moduleName,
@ -117,6 +128,7 @@ export class Context {
entity: any entity: any
id: string id: string
callbacks: Map<string, { resolve: Function, reject: Function }> = new Map callbacks: Map<string, { resolve: Function, reject: Function }> = new Map
classes: Map<string, ClassType<object>> = new Map
hookBeforeNativeCall() { hookBeforeNativeCall() {
if (this.entity && Reflect.has(this.entity, 'hookBeforeNativeCall')) { if (this.entity && Reflect.has(this.entity, 'hookBeforeNativeCall')) {
@ -260,25 +272,47 @@ export function jsCallEntityMethod(contextId: string, methodName: string, args?:
loge(`Cannot find method for context id:${contextId},method name is:${methodName}`) loge(`Cannot find method for context id:${contextId},method name is:${methodName}`)
} }
} }
type ClassType<T> = new (...args: any) => T type ClassType<T> = new (...args: any) => T
export function jsObtainEntry(contextId: string) { export function jsObtainEntry(contextId: string) {
const context = jsObtainContext(contextId) const context = jsObtainContext(contextId)
const exportFunc = (constructor: ClassType<object>) => { const exportFunc = (constructor: ClassType<object>) => {
context?.classes?.set(constructor.name, constructor)
const ret = class extends constructor { const ret = class extends constructor {
context = context context = context
} }
if (context) { context?.register(new ret)
context.register(new ret)
}
return ret return ret
} }
return (args: ClassType<object> | ClassType<object>[]) => { return function () {
if (arguments.length === 1) {
const args = arguments[0]
if (args instanceof Array) { if (args instanceof Array) {
args.forEach(clz => {
context?.classes?.set(clz.name, clz)
})
return exportFunc return exportFunc
} else { } else {
return exportFunc(args) return exportFunc(args)
} }
} else if (arguments.length === 2) {
const srcContextId = arguments[0] as string
const className = arguments[1] as string
const srcContext = gContexts.get(srcContextId)
if (srcContext) {
const clz = srcContext.classes.get(className)
if (clz) {
return exportFunc(clz)
} else {
throw new Error(`Cannot find class:${className} in context:${srcContextId}`)
}
} else {
throw new Error(`Cannot find context for ${srcContextId}`)
}
} else {
throw new Error(`Entry arguments error:${arguments}`)
}
} }
} }