提交 8e31cfa8 编写于 作者: fxy060608's avatar fxy060608

wip(uts): tests

上级 75b95110
import IUniLogin, { OnConnect, RegisterOptions } from '../interface'
export default class UniLogin implements IUniLogin {
//@UniJSMethod({ uiThread: true })
login(name: string, code: number) {
console.log(name, code)
}
// {"name":"fxy","callback1":{__type__:"fun",id:1},"callback2":{__type__:"fun",id:1}}
// => RegisterOptions
async register(opts: RegisterOptions) {
opts.callback1(true)
opts.callback2(true)
opts.abc.callback3(true)
}
onConnect(callback: OnConnect) {}
}
import Intent from "android.content.Intent";
import JSONObject from "com.alibaba.fastjson.JSONObject";
import UniModule from "io.dcloud.feature.uniapp.common.UniModule";
import UniJSMethod from "io.dcloud.feature.uniapp.annotation.UniJSMethod";
import UniJSCallback from "io.dcloud.feature.uniapp.bridge.UniJSCallback";
import log from "./log";
export default class TestModule implements UniLogin {
TAG = "TestModule";
static REQUEST_CODE = 1000;
//run ui thread
@UniJSMethod({ uiThread: true })
async testAsyncFunc(options: JSONObject, callback?: UniJSCallback) {
log(this.TAG, "testAsyncFunc--$options");
if (callback != null) {
const data = new JSONObject();
data["code"] = "success12312";
callback.invoke(data);
}
}
//run JS thread
@UniJSMethod({ uiThread: false })
testSyncFunc(options: JSONObject): JSONObject {
const data = new JSONObject();
data["code"] = "success456";
return data;
}
override onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == TestModule.REQUEST_CODE && data.hasExtra("respond")) {
log(this.TAG, "原生页面返回----" + data.getStringExtra("respond"));
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
import Log from "android.util.Log";
export default function log(tag: string, msg: string) {
Log.e(tag, msg);
}
import Log from "android.util.Log";
export default function log(tag: string, msg: string) {
Log.e(tag, msg);
}
import { login as Login, register as Register } from '../interface.fun'
export const login: Login = (name, code) => {
console.log(name, code)
}
// import { login } from '@/uni_modules/uni-login'
// => const uniLogin = require('class')
// import { UniLogin, test } from '@/uni_modules/uni-login'
// new UniLogin()
import { RegisterOptions, OnConnect } from './interface'
export interface login {
(name: string, code: number): void
}
export interface register {
(opts: RegisterOptions): Promise<void>
}
export interface onConnect {
(callback: OnConnect): void
}
export type RegisterOptions = {
name: string
callback1: (res: boolean) => void
callback2: (res: boolean) => void
abc: {
callback3: (res: boolean) => void
}
}
export type OnConnect = () => void
export default interface IUniLogin {
login: (name: string, code: number) => void
register: (opts: RegisterOptions) => Promise<void>
onConnect: (callback: OnConnect) => void
}
// import UniLogin from '@uni_modules/uni-login'
// new UniLogin()
//
// TestSwiftComponent.swift
// DCTestSwiftPlugin
//
// Created by Dcloud-XHY on 2022/6/28.
//
import 'UIKit'
import 'MapKit'
// 必须添加 @objc(类名),编译器才会生成对应的 oc 方法
@objc(TestSwiftComponent)
class TestSwiftComponent implements DCUniComponent, MKMapViewDelegate {
mapLoadedEvent = false
showTraffic = false
mapView?: MKMapView = null
// 初始化方法
override onCreateComponent(
ref: String,
type: String,
styles: [AnyHashable: Any],
attributes: [AnyHashable: Any],
events: [Any],
uniInstance: DCUniSDKInstance
) {
// NSDictionary 转换为 swift 的 [AnyHashable : Any] ,解析参数需要使用 [AnyHashable("key")]
this.showTraffic = DCUniConvert.bool(
attributes[AnyHashable('showTraffic')] ?? false
)
}
override loadView(): UIView {
this.mapView = MKMapView.init()
return this.mapView!
}
override viewDidLoad() {
this.mapView!.delegate = this
if (this.showTraffic) {
this.mapView.showsTraffic = true
}
}
// 监听属性变化方法
override updateAttributes(attributes: [AnyHashable: Any] =new Dictionary<AnyHashable, Any>()) {
if (attributes['showsTraffic'] != null) {
this.showTraffic = DCUniConvert.bool(
attributes[AnyHashable('showsTraffic')]!
)
this.mapView.showsTraffic = this.showTraffic
}
}
// 监听注册事件方法
override addEvent(eventName: String) {
if (eventName == 'mapLoaded') {
this.mapLoadedEvent = true
}
}
override removeEvent(eventName: String) {
if (eventName == 'mapLoaded') {
this.mapLoadedEvent = false
}
}
@objc public static wx_export_method_0(): String {
return 'focus:'
}
@objc focus(options: NSDictionary) {
print(options)
}
// MARK: - MKMapViewDelegate
mapViewDidFinishLoadingMap(mapView: MKMapView) {
if (this.mapLoadedEvent) {
// 回调 event 事件
this.fireEvent('mapLoaded', { mapLoaded: 'success' })
}
}
}
//
// TestSwiftModule.swift
// DCTestSwiftPlugin
//
// Created by Dcloud-XHY on 2022/6/27.
//
//import UIKit
// 必须添加 @objc(类名),编译器才会生成对应的 oc 方法
@objc(TestSwiftModule)
class TestSwiftModule extends DCUniModule {
// 暴露异步方法供js调用:
// 1.必须添加 @objc 前缀,
// 2.使用 public static 静态方法
// 3.方法名称必须是以 wx_export_method_ 开头,后面随意拼接一个字符保证唯一性即可
// 4.方法返回实例方法的名称
// 注意点:swift 方法名称转换为 oc 方法名称时系统会自动将首个参数用 with 拼接到方法名中作为方法名的一部分 如下实例
// testAsyncFunc(options:callback:) -> testAsyncFuncWithOptions:callback
// js 中调用方法 testAsyncFuncWithOptions(options,callabck)
// 可以在参数前面加上 _ 让编译器忽略拼接参数
@objc public static wx_export_method_0() : String {
return "testAsyncFunc::"
}
// 需要暴露的实例方法
// 1.必须添加 @objc 前缀
// 2.首个参数需要添加 _ 忽略外部参数 其他参数可选
@objc testAsyncFunc(options: NSDictionary,callback?: UniModuleKeepAliveCallback) {
print(options)
if (callback != null) {
callback!("success",false)
}
}
// 暴露同步方法供js调用:
// 1.必须添加 @objc 前缀,
// 2.使用 public static 静态方法
// 3.方法名称必须是以 wx_export_method_sync_ 开头,后面随意拼接一个字符保证唯一性即可
// 4.方法返回实例方法的名称
// 注意点:swift 方法名称转换为 oc 方法名称时系统会自动将首个参数名首字符大写然后用 with 拼接到方法名中作为方法名的一部分 如下实例
// testSyncFunc(options:) -> testSyncFuncWithOptions:
// js 中调用方法 var value = testSyncFuncWithOptions(options)
@objc public static wx_export_method_sync_0() : String {
return "testSyncFunc:"
}
// 需要暴露的实例方法
// 1.必须添加 @objc 前缀
// 2.首个参数需要添加 _ 忽略外部参数
@objc testSyncFunc(options: NSDictionary) : String {
print(options);
// 暴露方法内部可以调用其他 swift 方法
return getSomeString();
}
// 不需要直接暴露给js的方法不需要添加前缀
getSomeString() : String {
return "getSomeString success"
}
}
{
"name": "UTS Plugin",
"id": "DCloud-UTSPlugin",
"version": "0.0.1",
"description": "UTS示例插件",
"main":"interface",
"_dp_type":"nativeplugin",
"_dp_nativeplugin":{
"android": {
"plugins": [
{
"type": "module",
"name": "DCloud-UTSPlugin",
"class": "io.dcloud.uniplugin.TestModule"
},
{
"type": "component",
"name": "uts-richtext",
"class": "io.dcloud.uniplugin.TestComponent"
}
],
"integrateType": "uts",
"dependencies":[
{
"id": "com.zzhoujay.richtext:richtext",
"source": "implementation 'com.zzhoujay.richtext:richtext:3.0.7'"
}
],
"minSdkVersion" : 21
}
}
}
\ No newline at end of file
import IUniLogin, { OnConnect, RegisterOptions } from '../interface.uts' import IUniLogin from '../interface'
import { OnConnect, RegisterOptions } from '../interface'
export default class UniLogin implements IUniLogin { export default class UniLogin implements IUniLogin {
//@UniJSMethod({ uiThread: true }) //@UniJSMethod({ uiThread: true })
override login(name, code) { override login(name, code) {
console.log(name, code) console.log(name, code)
} }
......
...@@ -14,6 +14,3 @@ export default interface IUniLogin { ...@@ -14,6 +14,3 @@ export default interface IUniLogin {
register: (opts: RegisterOptions) => Promise<void> register: (opts: RegisterOptions) => Promise<void>
onConnect: (callback: OnConnect) => void onConnect: (callback: OnConnect) => void
} }
// import UniLogin from '@uni_modules/uni-login'
// new UniLogin()
// 接口
interface IUniLogin {
login(): void
}
// 父类/基类
class BaseUniLogin {
register() {}
}
// 子类实现
class UniLogin extends BaseUniLogin implements IUniLogin {
// 实现接口的方法,不能写 override 关键词,因为 override 关键词仅能在实现父类的属性或方法上使用
login() {}
// 实现或覆盖父类的方法,可写可不写 override
override register(): void {}
}
async function testAsync(): Promise<number> {
return 1
}
async function main() {
const res = await testAsync()
return res
}
package index;
import ...interface.interface as IUniLogin;
import ...interface.OnConnect;
import ...interface.RegisterOptions;
open class UniLogin : IUniLogin {
override fun login(name, code) {
console.log(name, code);
}
open fun async register(opts: RegisterOptions) {
opts.callback1(true);
opts.callback2(true);
opts.abc.callback3(true);
}
override fun onConnect(callback: OnConnect) {}
}
package io.dcloud.uniplugin.TestModule;
import android.content.Intent;
import com.alibaba.fastjson.JSONObject;
import io.dcloud.feature.uniapp.common.UniModule;
import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.uniplugin.log.log;
open class TestModule : UniLogin {
open var TAG = "TestModule";
@UniJSMethod( uiThread = true )
open fun async testAsyncFunc(options: JSONObject, callback: UniJSCallback?) {
log(this.TAG, "testAsyncFunc--$options");
if (callback != null) {
val data = JSONObject();
data["code"] = "success12312";
callback.invoke(data);
}
}
@UniJSMethod( uiThread = false )
open fun testSyncFunc(options: JSONObject): JSONObject {
val data = JSONObject();
data["code"] = "success456";
return data;
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == TestModule.REQUEST_CODE && data.hasExtra("respond")) {
log(this.TAG, "原生页面返回----" + data.getStringExtra("respond"));
}
else {
super.onActivityResult(requestCode, resultCode, data);
}
}
companion object {
var REQUEST_CODE = 1000;
}
}
package io.dcloud.uniplugin.log;
import android.util.Log;
fun log(tag: String, msg: String) {
Log.e(tag, msg);
}
package test;
import android.util.Log;
fun log(tag: String, msg: String) {
Log.e(tag, msg);
}
import UIKit;
import MapKit;
@objc(TestSwiftComponent)
class TestSwiftComponent : DCUniComponent, MKMapViewDelegate {
var mapLoadedEvent = false;
var showTraffic = false;
var mapView: MKMapView? = nil;
override func onCreateComponent(_ ref: String, _ type: String, _ styles: [AnyHashable: Any], _ attributes: [AnyHashable: Any], _ events: [Any], _ uniInstance: DCUniSDKInstance) {
self.showTraffic = DCUniConvert.bool(attributes[AnyHashable("showTraffic")] ?? false);
}
override func loadView() -> UIView {
self.mapView = MKMapView.init();
return self.mapView!;
}
override func viewDidLoad() {
self.mapView!.delegate = self;
if (self.showTraffic) {
self.mapView.showsTraffic = true;
}
}
override func updateAttributes(_ attributes: [AnyHashable: Any] = Dictionary<AnyHashable, Any>()) {
if (attributes["showsTraffic"] != nil) {
self.showTraffic = DCUniConvert.bool(attributes[AnyHashable("showsTraffic")]!);
self.mapView.showsTraffic = self.showTraffic;
}
}
override func addEvent(_ eventName: String) {
if (eventName == "mapLoaded") {
self.mapLoadedEvent = true;
}
}
override func removeEvent(_ eventName: String) {
if (eventName == "mapLoaded") {
self.mapLoadedEvent = false;
}
}
@objc
public static func wx_export_method_0() -> String {
return "focus:";
}
@objc
func focus(_ options: NSDictionary) {
print(options);
}
func mapViewDidFinishLoadingMap(_ mapView: MKMapView) {
if (self.mapLoadedEvent) {
self.fireEvent("mapLoaded", [
"mapLoaded": "success"
]);
}
}
}
@objc(TestSwiftModule)
class TestSwiftModule : DCUniModule {
@objc
public static func wx_export_method_0() -> String {
return "testAsyncFunc::";
}
@objc
func testAsyncFunc(_ options: NSDictionary, _ callback: UniModuleKeepAliveCallback?) {
print(options);
if (callback != nil) {
callback!("success", false);
}
}
@objc
public static func wx_export_method_sync_0() -> String {
return "testSyncFunc:";
}
@objc
func testSyncFunc(_ options: NSDictionary) -> String {
print(options);
return getSomeString();
}
func getSomeString() -> String {
return "getSomeString success";
}
}
...@@ -11,7 +11,6 @@ import { ...@@ -11,7 +11,6 @@ import {
} from '../../types/types' } from '../../types/types'
// 需要区分 android,iOS // 需要区分 android,iOS
export function uniUtsV1Plugin(): Plugin { export function uniUtsV1Plugin(): Plugin {
// TODO 1.0 版本,解析到 uts module 时,动态编译 uts ?
let moduleCode: string let moduleCode: string
return { return {
name: 'uni:uts-v1', name: 'uni:uts-v1',
...@@ -29,7 +28,7 @@ export function uniUtsV1Plugin(): Plugin { ...@@ -29,7 +28,7 @@ export function uniUtsV1Plugin(): Plugin {
if (!moduleName) { if (!moduleName) {
return return
} }
// 懒加载 uts // 懒加载 uts 编译器
// eslint-disable-next-line no-restricted-globals // eslint-disable-next-line no-restricted-globals
const { parse } = require('@dcloudio/uts') const { parse } = require('@dcloudio/uts')
const ast = await parse(code) const ast = await parse(code)
...@@ -39,9 +38,12 @@ export function uniUtsV1Plugin(): Plugin { ...@@ -39,9 +38,12 @@ export function uniUtsV1Plugin(): Plugin {
'utf8' 'utf8'
) )
} }
return moduleCode code = moduleCode
.replace(`__MODULE_NAME__`, moduleName) .replace(`__MODULE_NAME__`, moduleName)
.replace(`'__MODULE_DEFINE__'`, JSON.stringify(parseModuleDefines(ast))) .replace(`'__MODULE_DEFINE__'`, JSON.stringify(parseModuleDefines(ast)))
// TODO compile uts
return code
}, },
} }
} }
......
import { parse, runBuild, UtsTarget } from '@dcloudio/uts'
import path from 'path'
export function getUtsCompiler(): {
parse: typeof parse
runBuild: typeof runBuild
UtsTarget: typeof UtsTarget
} {
// eslint-disable-next-line no-restricted-globals
return require('@dcloudio/uts')
}
export function compile(pluginDir: string) {
const { runBuild, UtsTarget } = getUtsCompiler()
runBuild(UtsTarget.KOTLIN, {
input: {
dir: path.join(process.env.UNI_INPUT_DIR, pluginDir),
},
output: {
dir: path.join(process.env.UNI_OUTPUT_DIR, pluginDir),
sourceMap: true,
extname: '',
},
})
}
...@@ -20,7 +20,10 @@ function resolveOptions(options: UtsOptions) { ...@@ -20,7 +20,10 @@ function resolveOptions(options: UtsOptions) {
} }
if (output.sourceMap === true) { if (output.sourceMap === true) {
output.sourceMap = output.outDir output.sourceMap = output.outDir
} else if (output.sourceMap === false) { } else if (
output.sourceMap === false ||
typeof output.sourceMap === 'undefined'
) {
output.sourceMap = '' output.sourceMap = ''
} }
if (!output.imports) { if (!output.imports) {
......
...@@ -27,8 +27,8 @@ export enum UtsTarget { ...@@ -27,8 +27,8 @@ export enum UtsTarget {
export type UtsMode = 'dev' | 'build' export type UtsMode = 'dev' | 'build'
const UtsTargetDirs = { const UtsTargetDirs = {
[UtsTarget.KOTLIN]: 'android', [UtsTarget.KOTLIN]: 'app-android',
[UtsTarget.SWIFT]: 'ios', [UtsTarget.SWIFT]: 'app-ios',
} as const } as const
export const UtsTargetExtNames = { export const UtsTargetExtNames = {
...@@ -58,12 +58,12 @@ export interface ToOptions { ...@@ -58,12 +58,12 @@ export interface ToOptions {
/** /**
* 是否生成 sourceMap,为 string 时,表示生成的 sourceMap 目标目录 * 是否生成 sourceMap,为 string 时,表示生成的 sourceMap 目标目录
*/ */
sourceMap: boolean | string sourceMap?: boolean | string
/** /**
* sourceMap 中是否包含源码 * sourceMap 中是否包含源码
*/ */
inlineSourcesContent?: boolean inlineSourcesContent?: boolean
extname: string extname?: string
} }
} }
...@@ -99,6 +99,9 @@ function parseOptions( ...@@ -99,6 +99,9 @@ function parseOptions(
if (!opts.output.dir) { if (!opts.output.dir) {
opts.output.dir = resolveDefaultOutputDir(mode, input.dir) opts.output.dir = resolveDefaultOutputDir(mode, input.dir)
} }
if (!opts.output.extname) {
opts.output.extname = UtsTargetExtNames[target]
}
opts.silent = opts.silent === true opts.silent = opts.silent === true
return opts as ToOptions return opts as ToOptions
} }
...@@ -106,7 +109,7 @@ function parseOptions( ...@@ -106,7 +109,7 @@ function parseOptions(
const EXTNAME = '.uts' const EXTNAME = '.uts'
function resolveSrcDir(target: UtsTarget, dir: string) { function resolveSrcDir(target: UtsTarget, dir: string) {
return path.join(dir, UtsTargetDirs[target] + '/src') return path.join(dir, UtsTargetDirs[target])
} }
function initInputOptions(_: UtsTarget, root: string): UtsInputOptions { function initInputOptions(_: UtsTarget, root: string): UtsInputOptions {
...@@ -119,12 +122,12 @@ function initInputOptions(_: UtsTarget, root: string): UtsInputOptions { ...@@ -119,12 +122,12 @@ function initInputOptions(_: UtsTarget, root: string): UtsInputOptions {
function initOutputOptions( function initOutputOptions(
target: UtsTarget, target: UtsTarget,
outDir: string, outDir: string,
sourceMap: string | boolean, sourceMap: string | boolean | undefined,
inlineSourcesContent: boolean inlineSourcesContent: boolean
): UtsOutputOptions { ): UtsOutputOptions {
return { return {
outDir, outDir,
sourceMap, sourceMap: sourceMap ? sourceMap : false,
inlineSourcesContent, inlineSourcesContent,
extname: UtsTargetExtNames[target], extname: UtsTargetExtNames[target],
} }
...@@ -227,16 +230,7 @@ interface DoBuildOptions { ...@@ -227,16 +230,7 @@ interface DoBuildOptions {
function doBuild( function doBuild(
target: UtsTarget, target: UtsTarget,
{ { watch, silent, extname, inputSrcDir, input, output }: DoBuildOptions
watch,
silent,
extname,
inputDir,
inputSrcDir,
outputDir,
input,
output,
}: DoBuildOptions
) { ) {
const files = glob.sync('**/*' + extname, { const files = glob.sync('**/*' + extname, {
absolute: true, absolute: true,
...@@ -252,16 +246,10 @@ function doBuild( ...@@ -252,16 +246,10 @@ function doBuild(
} as UtsResult } as UtsResult
}) })
) )
) ).then((res) => {
.then((res) => { !silent && printUtsResults(res, watch)
return copyAssets(UtsTarget.KOTLIN, inputDir, outputDir, extname!).then( return res
() => res })
)
})
.then((res) => {
!silent && printUtsResults(res, watch)
return res
})
} }
function build(target: UtsTarget, toOptions: ToOptions) { function build(target: UtsTarget, toOptions: ToOptions) {
...@@ -286,38 +274,6 @@ function build(target: UtsTarget, toOptions: ToOptions) { ...@@ -286,38 +274,6 @@ function build(target: UtsTarget, toOptions: ToOptions) {
}) })
} }
function copyAssets(
target: UtsTarget,
inputDir: string,
outputDir: string,
extname: string
) {
inputDir = path.resolve(inputDir)
outputDir = path.resolve(outputDir)
const kotlinRootDir = path.join(inputDir, UtsTargetDirs[UtsTarget.KOTLIN])
const swiftRootDir = path.join(inputDir, UtsTargetDirs[UtsTarget.SWIFT])
return fs.copy(inputDir, outputDir, {
filter(src) {
if (target === UtsTarget.KOTLIN) {
if (src === swiftRootDir) {
return false
}
} else if (target === UtsTarget.SWIFT) {
if (src === kotlinRootDir) {
return false
}
}
if (path.basename(src).startsWith('.')) {
return false
}
if (fs.lstatSync(src).isDirectory()) {
return false
}
return ![extname, '.ts'].includes(path.extname(src))
},
})
}
function buildFile( function buildFile(
target: UtsTarget, target: UtsTarget,
filename: string, filename: string,
......
...@@ -19,7 +19,7 @@ export type UtsInputOptions = UtsParseOptions & { ...@@ -19,7 +19,7 @@ export type UtsInputOptions = UtsParseOptions & {
export type UtsOutputOptions = { export type UtsOutputOptions = {
outDir: string outDir: string
imports?: string[] imports?: string[]
sourceMap: boolean | string sourceMap?: boolean | string
inlineSourcesContent?: boolean inlineSourcesContent?: boolean
extname: string extname: string
} }
......
...@@ -18,13 +18,13 @@ parse( ...@@ -18,13 +18,13 @@ parse(
runBuild(UtsTarget.KOTLIN, { runBuild(UtsTarget.KOTLIN, {
silent: false, silent: false,
input: { input: {
dir: path.resolve(projectDir, 'nativeplugins/test-uniplugin'), dir: path.resolve(projectDir, 'uni_modules/test-uniplugin'),
extname: '.uts', extname: '.uts',
}, },
output: { output: {
dir: path.resolve( dir: path.resolve(
projectDir, projectDir,
'unpackage/nativeplugins/test-uniplugin-android' 'unpackage/dist/app-plus/uni_modules/test-uniplugin/android'
), ),
sourceMap: false, sourceMap: false,
inlineSourcesContent: false, inlineSourcesContent: false,
...@@ -33,11 +33,14 @@ runBuild(UtsTarget.KOTLIN, { ...@@ -33,11 +33,14 @@ runBuild(UtsTarget.KOTLIN, {
runBuild(UtsTarget.SWIFT, { runBuild(UtsTarget.SWIFT, {
silent: false, silent: false,
input: { input: {
dir: path.resolve(projectDir, 'nativeplugins/test-uniplugin'), dir: path.resolve(projectDir, 'uni_modules/test-uniplugin'),
extname: '.uts', extname: '.uts',
}, },
output: { output: {
dir: path.resolve(projectDir, 'unpackage/nativeplugins/test-uniplugin-ios'), dir: path.resolve(
projectDir,
'unpackage/dist/app-plus/uni_modules/test-uniplugin/ios'
),
sourceMap: false, sourceMap: false,
inlineSourcesContent: false, inlineSourcesContent: false,
}, },
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册