uts.js 10.0 KB
Newer Older
1 2
import { isPlainObject, hasOwn, extend, capitalize, isStr as isString } from 'uni-shared';

fxy060608's avatar
fxy060608 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
let callbackId = 1;
let proxy;
const callbacks = {};
function normalizeArg(arg) {
    if (typeof arg === 'function') {
        // 查找该函数是否已缓存
        const oldId = Object.keys(callbacks).find((id) => callbacks[id] === arg);
        const id = oldId ? parseInt(oldId) : callbackId++;
        callbacks[id] = arg;
        return id;
    }
    else if (isPlainObject(arg)) {
        Object.keys(arg).forEach((name) => {
            arg[name] = normalizeArg(arg[name]);
        });
    }
    return arg;
}
fxy060608's avatar
fxy060608 已提交
21 22
function initUTSInstanceMethod(async, opts, instanceId, proxy) {
    return initProxyFunction(async, opts, instanceId, proxy);
fxy060608's avatar
fxy060608 已提交
23 24 25 26 27 28 29
}
function getProxy() {
    if (!proxy) {
        proxy = uni.requireNativePlugin('UTS-Proxy');
    }
    return proxy;
}
fxy060608's avatar
fxy060608 已提交
30 31 32 33 34
function resolveSyncResult(res, returnOptions, instanceId, proxy) {
    // devtools 环境是字符串?
    if (isString(res)) {
        res = JSON.parse(res);
    }
fxy060608's avatar
fxy060608 已提交
35
    if ((process.env.NODE_ENV !== 'production')) {
fxy060608's avatar
fxy060608 已提交
36
        console.log('uts.invokeSync.result', res, returnOptions, instanceId, proxy);
fxy060608's avatar
fxy060608 已提交
37
    }
fxy060608's avatar
fxy060608 已提交
38 39 40
    if (res.errMsg) {
        throw new Error(res.errMsg);
    }
fxy060608's avatar
fxy060608 已提交
41 42 43 44 45 46 47 48 49 50 51
    if (returnOptions) {
        if (returnOptions.type === 'interface' && typeof res.params === 'number') {
            if (res.params === instanceId && proxy) {
                return proxy;
            }
            if (interfaceDefines[returnOptions.options]) {
                const ProxyClass = initUTSProxyClass(extend({ instanceId: res.params }, interfaceDefines[returnOptions.options]));
                return new ProxyClass();
            }
        }
    }
fxy060608's avatar
fxy060608 已提交
52 53 54 55 56 57 58
    return res.params;
}
function invokePropGetter(args) {
    if (args.errMsg) {
        throw new Error(args.errMsg);
    }
    delete args.errMsg;
fxy060608's avatar
fxy060608 已提交
59 60 61
    if ((process.env.NODE_ENV !== 'production')) {
        console.log('uts.invokePropGetter.args', args);
    }
fxy060608's avatar
fxy060608 已提交
62 63
    return resolveSyncResult(getProxy().invokeSync(args, () => { }));
}
fxy060608's avatar
fxy060608 已提交
64
function initProxyFunction(async, { moduleName, moduleType, package: pkg, class: cls, name: propOrMethod, method, companion, params: methodParams, return: returnOptions, errMsg, }, instanceId, proxy) {
fxy060608's avatar
fxy060608 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77
    const invokeCallback = ({ id, name, params, keepAlive, }) => {
        const callback = callbacks[id];
        if (callback) {
            callback(...params);
            if (!keepAlive) {
                delete callbacks[id];
            }
        }
        else {
            console.error(`${pkg}${cls}.${propOrMethod} ${name} is not found`);
        }
    };
    const baseArgs = instanceId
fxy060608's avatar
fxy060608 已提交
78 79 80 81 82 83 84
        ? {
            moduleName,
            moduleType,
            id: instanceId,
            name: propOrMethod,
            method: methodParams,
        }
fxy060608's avatar
fxy060608 已提交
85
        : {
fxy060608's avatar
fxy060608 已提交
86 87
            moduleName,
            moduleType,
fxy060608's avatar
fxy060608 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
            package: pkg,
            class: cls,
            name: method || propOrMethod,
            companion,
            method: methodParams,
        };
    return (...args) => {
        if (errMsg) {
            throw new Error(errMsg);
        }
        const invokeArgs = extend({}, baseArgs, {
            params: args.map((arg) => normalizeArg(arg)),
        });
        if (async) {
            return new Promise((resolve, reject) => {
fxy060608's avatar
fxy060608 已提交
103 104 105
                if ((process.env.NODE_ENV !== 'production')) {
                    console.log('uts.invokeAsync.args', invokeArgs);
                }
fxy060608's avatar
fxy060608 已提交
106
                getProxy().invokeAsync(invokeArgs, (res) => {
fxy060608's avatar
fxy060608 已提交
107 108 109
                    if ((process.env.NODE_ENV !== 'production')) {
                        console.log('uts.invokeAsync.result', res);
                    }
fxy060608's avatar
fxy060608 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123
                    if (res.type !== 'return') {
                        invokeCallback(res);
                    }
                    else {
                        if (res.errMsg) {
                            reject(res.errMsg);
                        }
                        else {
                            resolve(res.params);
                        }
                    }
                });
            });
        }
fxy060608's avatar
fxy060608 已提交
124 125 126
        if ((process.env.NODE_ENV !== 'production')) {
            console.log('uts.invokeSync.args', invokeArgs);
        }
fxy060608's avatar
fxy060608 已提交
127
        return resolveSyncResult(getProxy().invokeSync(invokeArgs, invokeCallback), returnOptions, instanceId, proxy);
fxy060608's avatar
fxy060608 已提交
128 129
    };
}
fxy060608's avatar
fxy060608 已提交
130
function initUTSStaticMethod(async, opts) {
fxy060608's avatar
fxy060608 已提交
131 132 133 134 135 136 137
    if (opts.main && !opts.method) {
        if (typeof plus !== 'undefined' && plus.os.name === 'iOS') {
            opts.method = 's_' + opts.name;
        }
    }
    return initProxyFunction(async, opts, 0);
}
fxy060608's avatar
fxy060608 已提交
138
const initUTSProxyFunction = initUTSStaticMethod;
fxy060608's avatar
fxy060608 已提交
139 140 141 142 143 144
function parseClassMethodName(name, methods) {
    if (hasOwn(methods, name + 'ByJs')) {
        return name + 'ByJs';
    }
    return name;
}
fxy060608's avatar
fxy060608 已提交
145 146 147 148 149 150 151 152
function isUndefined(value) {
    return typeof value === 'undefined';
}
function isProxyInterfaceOptions(options) {
    return !isUndefined(options.instanceId);
}
function initUTSProxyClass(options) {
    const { moduleName, moduleType, package: pkg, class: cls, methods, props, errMsg, } = options;
fxy060608's avatar
fxy060608 已提交
153
    const baseOptions = {
fxy060608's avatar
fxy060608 已提交
154 155
        moduleName,
        moduleType,
fxy060608's avatar
fxy060608 已提交
156 157 158 159
        package: pkg,
        class: cls,
        errMsg,
    };
fxy060608's avatar
fxy060608 已提交
160 161 162 163 164 165 166 167 168 169 170 171
    let instanceId;
    let constructorParams = [];
    let staticMethods = {};
    let staticProps = [];
    if (isProxyInterfaceOptions(options)) {
        instanceId = options.instanceId;
    }
    else {
        constructorParams = options.constructor.params;
        staticMethods = options.staticMethods;
        staticProps = options.staticProps;
    }
fxy060608's avatar
fxy060608 已提交
172 173 174 175 176 177
    // iOS 需要为 ByJs 的 class 构造函数(如果包含JSONObject或UTSCallback类型)补充最后一个参数
    if (typeof plus !== 'undefined' && plus.os.name === 'iOS') {
        if (constructorParams.find((p) => p.type === 'UTSCallback' || p.type.indexOf('JSONObject') > 0)) {
            constructorParams.push({ name: '_byJs', type: 'boolean' });
        }
    }
fxy060608's avatar
fxy060608 已提交
178
    const ProxyClass = class UTSClass {
fxy060608's avatar
fxy060608 已提交
179 180 181 182 183 184
        constructor(...params) {
            if (errMsg) {
                throw new Error(errMsg);
            }
            const target = {};
            // 初始化实例 ID
fxy060608's avatar
fxy060608 已提交
185 186 187 188
            if (isUndefined(instanceId)) {
                // 未指定instanceId
                instanceId = initProxyFunction(false, extend({ name: 'constructor', params: constructorParams }, baseOptions), 0).apply(null, params);
            }
fxy060608's avatar
fxy060608 已提交
189 190 191
            if (!instanceId) {
                throw new Error(`new ${cls} is failed`);
            }
fxy060608's avatar
fxy060608 已提交
192
            const proxy = new Proxy(this, {
fxy060608's avatar
fxy060608 已提交
193 194 195
                get(_, name) {
                    if (!target[name]) {
                        //实例方法
fxy060608's avatar
fxy060608 已提交
196
                        name = parseClassMethodName(name, methods);
fxy060608's avatar
fxy060608 已提交
197 198
                        if (hasOwn(methods, name)) {
                            const { async, params } = methods[name];
fxy060608's avatar
fxy060608 已提交
199
                            target[name] = initUTSInstanceMethod(!!async, extend({
fxy060608's avatar
fxy060608 已提交
200 201
                                name,
                                params,
fxy060608's avatar
fxy060608 已提交
202
                            }, baseOptions), instanceId, proxy);
fxy060608's avatar
fxy060608 已提交
203 204 205 206
                        }
                        else if (props.includes(name)) {
                            // 实例属性
                            return invokePropGetter({
fxy060608's avatar
fxy060608 已提交
207 208
                                moduleName,
                                moduleType,
fxy060608's avatar
fxy060608 已提交
209 210 211 212 213 214 215 216 217
                                id: instanceId,
                                name: name,
                                errMsg,
                            });
                        }
                    }
                    return target[name];
                },
            });
fxy060608's avatar
fxy060608 已提交
218
            return proxy;
fxy060608's avatar
fxy060608 已提交
219 220 221 222 223
        }
    };
    const staticMethodCache = {};
    return new Proxy(ProxyClass, {
        get(target, name, receiver) {
fxy060608's avatar
fxy060608 已提交
224
            name = parseClassMethodName(name, staticMethods);
fxy060608's avatar
fxy060608 已提交
225 226 227 228
            if (hasOwn(staticMethods, name)) {
                if (!staticMethodCache[name]) {
                    const { async, params } = staticMethods[name];
                    // 静态方法
fxy060608's avatar
fxy060608 已提交
229
                    staticMethodCache[name] = initUTSStaticMethod(!!async, extend({ name, companion: true, params }, baseOptions));
fxy060608's avatar
fxy060608 已提交
230 231 232 233 234 235 236 237 238 239 240
                }
                return staticMethodCache[name];
            }
            if (staticProps.includes(name)) {
                // 静态属性
                return invokePropGetter(extend({ name: name, companion: true }, baseOptions));
            }
            return Reflect.get(target, name, receiver);
        },
    });
}
fxy060608's avatar
fxy060608 已提交
241
function initUTSPackageName(name, is_uni_modules) {
fxy060608's avatar
fxy060608 已提交
242 243 244 245 246
    if (typeof plus !== 'undefined' && plus.os.name === 'Android') {
        return 'uts.sdk.' + (is_uni_modules ? 'modules.' : '') + name;
    }
    return '';
}
fxy060608's avatar
fxy060608 已提交
247
function initUTSIndexClassName(moduleName, is_uni_modules) {
fxy060608's avatar
fxy060608 已提交
248 249 250
    if (typeof plus === 'undefined') {
        return '';
    }
fxy060608's avatar
fxy060608 已提交
251
    return initUTSClassName(moduleName, plus.os.name === 'iOS' ? 'IndexSwift' : 'IndexKt', is_uni_modules);
fxy060608's avatar
fxy060608 已提交
252
}
fxy060608's avatar
fxy060608 已提交
253
function initUTSClassName(moduleName, className, is_uni_modules) {
fxy060608's avatar
fxy060608 已提交
254 255 256 257 258 259 260 261 262 263 264 265 266 267
    if (typeof plus === 'undefined') {
        return '';
    }
    if (plus.os.name === 'Android') {
        return className;
    }
    if (plus.os.name === 'iOS') {
        return ('UTSSDK' +
            (is_uni_modules ? 'Modules' : '') +
            capitalize(moduleName) +
            capitalize(className));
    }
    return '';
}
fxy060608's avatar
fxy060608 已提交
268 269 270 271
const interfaceDefines = {};
function registerUTSInterface(name, define) {
    interfaceDefines[name] = define;
}
fxy060608's avatar
fxy060608 已提交
272 273 274 275 276 277 278 279 280 281
const pluginDefines = {};
function registerUTSPlugin(name, define) {
    pluginDefines[name] = define;
}
function requireUTSPlugin(name) {
    const define = pluginDefines[name];
    if (!define) {
        console.error(`${name} is not found`);
    }
    return define;
282 283 284
}

export { initUTSClassName, initUTSIndexClassName, initUTSPackageName, initUTSProxyClass, initUTSProxyFunction, normalizeArg, registerUTSInterface, registerUTSPlugin, requireUTSPlugin };