提交 a43a551e 编写于 作者: 雪洛's avatar 雪洛

feat(harmony): 导出uni-runtime

上级 e212af2d
......@@ -12,9 +12,9 @@
"@dcloudio/uni-i18n": "<rootDir>/packages/uni-i18n/src",
"@dcloudio/uni-platform": "<rootDir>/packages/uni-app-harmony/src/platform",
"@dcloudio/uni-shared": "<rootDir>/packages/uni-shared/src",
"@dcloudio/uni-runtime": "./uni-app-harmony-framework-dev.js"
"@dcloudio/uni-runtime": "../../../resources/rawfile/uni-app/uni-app-harmony-framework-dev"
},
"externals": ["./uni-app-harmony-framework-dev.js"],
"externals": ["../../../resources/rawfile/uni-app/uni-app-harmony-framework-dev"],
"replacements": {
"__PLATFORM__": "'app-harmony'",
"__DEV__": "false",
......@@ -22,7 +22,7 @@
"__APP_VIEW__": "false",
"__NODE_JS__": "false"
},
"banner": "import { IUniError, UTSObject, string } from './uts'\nimport { UniError, UTSJSONObject } from './uni-app-harmony-framework-dev.js'\nimport { defineAsyncApi, ApiExcutor, ProtocolOptions, ApiOptions, ErrRes } from './uni-api-shared'\n",
"banner": "import { IUniError, UTSObject, string } from './uts'\nimport { UniError, UTSJSONObject } from '../../../resources/rawfile/uni-app/uni-app-harmony-framework-dev'\nimport { defineAsyncApi, ApiExcutor, ProtocolOptions, ApiOptions, ErrRes } from './uni-api-shared'\n",
"wrapper": {
"name": "initUniExtApi",
"args": [["APP_ID", "string"]]
......@@ -32,9 +32,9 @@
"../uni-runtime/src/helpers/api/index.ts": "uni-api-shared.ets"
},
"alias": {
"@dcloudio/uni-runtime": "./uni-app-harmony-framework-dev.js"
"@dcloudio/uni-runtime": "../../../resources/rawfile/uni-app/uni-app-harmony-framework-dev"
},
"externals": ["./uni-app-harmony-framework-dev.js"],
"externals": ["../../../resources/rawfile/uni-app/uni-app-harmony-framework-dev"],
"replacements": {
"__PLATFORM__": "'app-harmony'",
"__DEV__": "false",
......
import { defineAsyncApi as originalDefineAsyncApi } from "../../../resources/rawfile/uni-app/uni-app-harmony-framework-dev";
type Anything = Object | null | undefined;
type NullType = null | undefined;
interface ErrRes {
errMsg?: string | null;
errCode?: number | null;
}
interface ApiExcutor<K> {
resolve: (res: K | void) => void;
reject: (errMsg?: string, errRes?: ErrRes) => void;
}
interface ProtocolOptions {
name?: string | null;
type?: string | null;
required?: boolean | null;
validator?: (value: Object) => boolean | undefined | string;
}
interface ApiOptions<T> {
beforeInvoke?: (args: Object) => boolean | void | string;
beforeAll?: (res: Object) => void;
beforeSuccess?: (res: Object, args: T) => void;
formatArgs?: Map<string, Function>;
}
interface AsyncMethodOptionLike {
success?: Function | null;
}
const TYPE_MAP = new Map<string, Object>([
[
'string',
String
],
[
'number',
Number
],
[
'boolean',
Boolean
],
[
'array',
Array
],
[
'object',
Object
]
]);
function getPropType(type: string | NullType): Anything {
if (!type) {
return;
}
return TYPE_MAP[type];
}
function defineAsyncApi<T extends AsyncMethodOptionLike, K>(name: string, fn: (options: T, res: ApiExcutor<K>) => void, protocol: Map<string, ProtocolOptions>, options: ApiOptions<T>): Function {
const originalProtocol = {} as Record<string, Object>;
protocol.forEach((value, key)=>{
const protocol = originalProtocol[key] = {} as Record<string, Anything>;
protocol.name = value.name;
protocol.type = getPropType(value.type);
protocol.required = value.required;
protocol.validator = value.validator;
});
const originalFormatArgs = {} as Record<string, Function>;
if (options.formatArgs) {
options.formatArgs.forEach((value, key)=>{
originalFormatArgs[key] = value;
});
}
const originalOptions = {} as Record<string, Anything>;
originalOptions.beforeInvoke = options.beforeInvoke;
originalOptions.beforeAll = options.beforeAll;
originalOptions.beforeSuccess = options.beforeSuccess;
originalOptions.formatArgs = originalFormatArgs;
return originalDefineAsyncApi<(options: T) => Promise<K>>(name, fn, originalProtocol, originalOptions);
}
export { ErrRes as ErrRes };
export { ApiExcutor as ApiExcutor };
export { ProtocolOptions as ProtocolOptions };
export { ApiOptions as ApiOptions };
export { defineAsyncApi as defineAsyncApi };
import { IUniError, UTSObject, string } from './uts'
import { UniError, UTSJSONObject } from '../../../resources/rawfile/uni-app/uni-app-harmony-framework-dev'
import { defineAsyncApi, ApiExcutor, ProtocolOptions, ApiOptions, ErrRes } from './uni-api-shared'
import fs from '@ohos.file.fs';
import picker from '@ohos.file.picker';
import image from '@ohos.multimedia.image';
import media from '@ohos.multimedia.media';
import { ReadOptions } from '@ohos.file.fs';
import { getRealPath } from "../../../resources/rawfile/uni-app/uni-app-harmony-framework-dev";
import picker1 from '@ohos.file.picker';
import picker2 from '@ohos.file.picker';
export function initUniExtApi(APP_ID: string) {
type MediaOrientation = 'up' | 'down' | 'left' | 'right' | 'up-mirrored' | 'down-mirrored' | 'left-mirrored' | 'right-mirrored';
type MediaErrorCode = 1101001 | 1101002 | 1101003 | 1101004 | 1101005 | 1101006 | 1101007 | 1101008 | 1101009 | 1101010;
interface IMediaError extends IUniError {
errCode: MediaErrorCode;
}
class ChooseImageSuccess extends UTSObject {
errSubject!: string;
errMsg!: string;
tempFilePaths!: Array<string>;
tempFiles!: Object;
}
type ChooseImageFail = IMediaError;
type ChooseImageSuccessCallback = (callback: ChooseImageSuccess) => void;
type ChooseImageFailCallback = (callback: ChooseImageFail) => void;
type ChooseImageCompleteCallback = (callback: Object) => void;
class ChooseImageCropOptions extends UTSObject {
width!: number;
height!: number;
quality: (number) | null = null;
resize: (boolean) | null = null;
}
class ChooseImageOptions extends UTSObject {
count: (number) | null = null;
sizeType: (string[]) | null = null;
sourceType: (string[]) | null = null;
extension: (string[]) | null = null;
crop: (ChooseImageCropOptions) | null = null;
success: (ChooseImageSuccessCallback) | null = null;
fail: (ChooseImageFailCallback) | null = null;
complete: (ChooseImageCompleteCallback) | null = null;
}
type ChooseImage = (options: ChooseImageOptions) => void;
type GetImageInfo = (options: GetImageInfoOptions) => void;
class GetImageInfoSuccess extends UTSObject {
width!: number;
height!: number;
path!: string;
orientation: MediaOrientation | null = null;
type: string | null = null;
}
type GetImageInfoFail = IMediaError;
type GetImageInfoSuccessCallback = (callback: GetImageInfoSuccess) => void;
type GetImageInfoFailCallback = (callback: GetImageInfoFail) => void;
type GetImageInfoCompleteCallback = ChooseImageCompleteCallback;
class GetImageInfoOptions extends UTSObject {
src!: string.ImageURIString;
success: (GetImageInfoSuccessCallback) | null = null;
fail: (GetImageInfoFailCallback) | null = null;
complete: (GetImageInfoCompleteCallback) | null = null;
}
class ChooseVideoSuccess extends UTSObject {
tempFilePath!: string;
duration!: number;
size!: number;
height!: number;
width!: number;
}
type ChooseVideoFail = IMediaError;
type ChooseVideoSuccessCallback = (callback: ChooseVideoSuccess) => void;
type ChooseVideoFailCallback = (callback: ChooseVideoFail) => void;
type ChooseVideoCompleteCallback = ChooseImageCompleteCallback;
class ChooseVideoOptions extends UTSObject {
sourceType: (string[]) | null = null;
compressed: boolean | null = true;
maxDuration: number | null = null;
camera: string | null = null;
extension: (string[]) | null = null;
success: (ChooseVideoSuccessCallback) | null = null;
fail: (ChooseVideoFailCallback) | null = null;
complete: (ChooseVideoCompleteCallback) | null = null;
}
type ChooseVideo = (options: ChooseVideoOptions) => void;
class GetVideoInfoSuccess extends UTSObject {
orientation: MediaOrientation | null = null;
type: string | null = null;
duration!: number;
size!: number;
height!: number;
width!: number;
fps: number | null = null;
bitrate: number | null = null;
}
type GetVideoInfoFail = IMediaError;
type GetVideoInfoSuccessCallback = (callback: GetVideoInfoSuccess) => void;
type GetVideoInfoFailCallback = (callback: GetVideoInfoFail) => void;
type GetVideoInfoCompleteCallback = ChooseImageCompleteCallback;
class GetVideoInfoOptions extends UTSObject {
src!: string.VideoURIString;
success: (GetVideoInfoSuccessCallback) | null = null;
fail: (GetVideoInfoFailCallback) | null = null;
complete: (GetVideoInfoCompleteCallback) | null = null;
}
type GetVideoInfo = (options: GetVideoInfoOptions) => void;
interface MediaFile {
fileType: 'video' | 'image';
tempFilePath: string;
size: number;
width?: number;
height?: number;
duration?: number;
thumbTempFilePath?: string;
}
interface chooseMediaOptions {
mimeType: picker.PhotoViewMIMETypes.VIDEO_TYPE | picker.PhotoViewMIMETypes.IMAGE_TYPE;
count?: number;
}
interface chooseMediaSuccessCallbackResult {
tempFiles: MediaFile[];
}
const _getVideoInfo = async (uri: string): Promise<GetVideoInfoSuccess> =>{
const file = await fs.open(uri, fs.OpenMode.READ_ONLY);
const avMetadataExtractor = await media.createAVMetadataExtractor();
let metadata: media.AVMetadata | null = null;
let size: number = 0;
try {
size = (await fs.stat(file.fd)).size;
avMetadataExtractor.dataSrc = {
fileSize: size,
callback: (buffer: ArrayBuffer, length: number, pos: number | null = null)=>{
return fs.readSync(file.fd, buffer, {
offset: pos,
length
} as ReadOptions);
}
};
metadata = await avMetadataExtractor.fetchMetadata();
} catch (error) {
throw error;
} finally{
await avMetadataExtractor.release();
await fs.close(file);
}
const videoOrientationArr = [
'up',
'right',
'down',
'left'
] as MediaOrientation[];
return {
size: size,
duration: metadata.duration ? Number(metadata.duration) / 1000 : undefined,
width: metadata.videoWidth ? Number(metadata.videoWidth) : undefined,
height: metadata.videoHeight ? Number(metadata.videoHeight) : undefined,
type: metadata.mimeType,
orientation: metadata.videoOrientation ? videoOrientationArr[Number(metadata.videoOrientation) / 90] : undefined
} as GetVideoInfoSuccess;
};
const _getImageInfo = async (uri: string): Promise<GetImageInfoSuccess> =>{
const file = await fs.open(uri, fs.OpenMode.READ_ONLY);
const imageSource = image.createImageSource(file.fd);
const imageInfo = await imageSource.getImageInfo();
const orientation = await imageSource.getImageProperty(image.PropertyKey.ORIENTATION);
let orientationNum = 0;
if (typeof orientation === 'string') {
const matched = orientation.match(/^Unknown value (\d)$/);
if (matched && matched[1]) {
orientationNum = Number(matched[1]);
} else if (/^\d$/.test(orientation)) {
orientationNum = Number(orientation);
}
} else if (typeof orientation === 'number') {
orientationNum = orientation;
}
let orientationStr: MediaOrientation = 'up';
switch(orientationNum){
case 2:
orientationStr = 'up-mirrored';
break;
case 3:
orientationStr = 'down';
break;
case 4:
orientationStr = 'down-mirrored';
break;
case 5:
orientationStr = 'left-mirrored';
break;
case 6:
orientationStr = 'right';
break;
case 7:
orientationStr = 'right-mirrored';
break;
case 8:
orientationStr = 'left';
break;
case 0:
case 1:
default:
orientationStr = 'up';
break;
}
return {
path: uri,
width: imageInfo.size.width,
height: imageInfo.size.height,
orientation: orientationStr
} as GetImageInfoSuccess;
};
const _chooseMedia = async (options: chooseMediaOptions): Promise<chooseMediaSuccessCallbackResult> =>{
const photoSelectOptions = new picker.PhotoSelectOptions();
const mimeType = options.mimeType;
photoSelectOptions.MIMEType = mimeType;
photoSelectOptions.maxSelectNumber = options.count || 9;
const photoPicker = new picker.PhotoViewPicker();
const photoSelectResult = await photoPicker.select(photoSelectOptions);
const uris = photoSelectResult.photoUris;
if (mimeType !== picker.PhotoViewMIMETypes.VIDEO_TYPE) {
return {
tempFiles: uris.map((uri)=>{
const file = fs.openSync(uri, fs.OpenMode.READ_ONLY);
const stat = fs.statSync(file.fd);
fs.closeSync(file);
return {
fileType: 'image',
tempFilePath: uri,
size: stat.size
} as MediaFile;
})
};
}
const tempFiles: MediaFile[] = [];
for(let i = 0; i < uris.length; i++){
const uri = uris[i];
const videoInfo = await _getVideoInfo(uri);
tempFiles.push({
fileType: 'video',
tempFilePath: uri,
size: videoInfo.size,
duration: videoInfo.duration,
width: videoInfo.width,
height: videoInfo.height
} as MediaFile);
}
return {
tempFiles
} as chooseMediaSuccessCallbackResult;
};
const API_GET_IMAGE_INFO = 'getImageInfo';
const GetImageInfoApiProtocol = new Map<string, ProtocolOptions>([
[
'src',
{
type: 'string',
required: true
}
]
]);
const GetImageInfoApiOptions: ApiOptions<GetImageInfoOptions> = {
formatArgs: new Map<string, Function>([
[
'src',
(src: string, params: GetImageInfoOptions)=>{
params.src = getRealPath(src);
}
]
])
};
const API_CHOOSE_IMAGE = 'chooseImage';
const ChooseImageApiProtocol = new Map<string, ProtocolOptions>([
[
'count',
{
type: 'number',
required: false
}
],
[
'sizeType',
{
type: 'array',
required: false
}
],
[
'sourceType',
{
type: 'array',
required: false
}
],
[
'extension',
{
type: 'array',
required: false
}
]
]);
const ChooseImageApiOptions: ApiOptions<ChooseImageOptions> = {
formatArgs: new Map<string, Function>([
[
'count',
(count: number, params: ChooseImageOptions)=>{
if (count == null) {
params.count = 9;
}
}
],
[
'sizeType',
(sizeType: string[], params: ChooseImageOptions)=>{
if (sizeType == null) {
params.sizeType = [
'original',
'compressed'
];
}
}
],
[
'sourceType',
(sourceType: string[], params: ChooseImageOptions)=>{
if (sourceType == null) {
params.sourceType = [
'album',
'camera'
];
}
}
],
[
'extension',
(extension: string[], params: ChooseImageOptions)=>{
if (extension == null) {
params.extension = [
'*'
];
}
}
]
])
};
const API_GET_VIDEO_INFO = 'getVideoInfo';
const GetVideoInfoApiProtocol = new Map<string, ProtocolOptions>([
[
'src',
{
type: 'string',
required: true
}
]
]);
const GetVideoInfoApiOptions: ApiOptions<GetVideoInfoOptions> = {
formatArgs: new Map<string, Function>([
[
'src',
(src: string, params: GetVideoInfoOptions)=>{
params.src = getRealPath(src);
}
]
])
};
const API_CHOOSE_VIDEO = 'chooseVideo';
const ChooseVideoApiProtocol = new Map<string, ProtocolOptions>([
[
'sourceType',
{
type: 'array',
required: false
}
],
[
'compressed',
{
type: 'boolean',
required: false
}
],
[
'maxDuration',
{
type: 'number',
required: false
}
],
[
'camera',
{
type: 'string',
required: false
}
],
[
'extension',
{
type: 'array',
required: false
}
]
]);
const ChooseVideoApiOptions: ApiOptions<ChooseVideoOptions> = {
formatArgs: new Map<string, Function>([
[
'sourceType',
(sourceType: string[], params: ChooseVideoOptions)=>{
if (sourceType == null) {
params.sourceType = [
'album',
'camera'
];
}
}
],
[
'compressed',
(compressed: boolean, params: ChooseVideoOptions)=>{
if (compressed == null) {
params.compressed = true;
}
}
],
[
'maxDuration',
(maxDuration: number, params: ChooseVideoOptions)=>{
if (maxDuration == null) {
params.maxDuration = 60;
}
}
],
[
'camera',
(camera: string, params: ChooseVideoOptions)=>{
if (camera == null) {
params.camera = 'back';
}
}
],
[
'extension',
(extension: string[], params: ChooseVideoOptions)=>{
if (extension == null) {
params.extension = [
'*'
];
}
}
]
])
};
interface TempFileItem {
path: string;
size: number;
}
const chooseImage: ChooseImage = defineAsyncApi<ChooseImageOptions, ChooseImageSuccess>(API_CHOOSE_IMAGE, (options: ChooseImageOptions, res: ApiExcutor<ChooseImageSuccess>)=>{
_chooseMedia({
mimeType: picker1.PhotoViewMIMETypes.IMAGE_TYPE,
count: options.count!
} as UTSJSONObject).then((chooseMediaRes)=>{
res.resolve({
errMsg: '',
errSubject: 'uni-chooseImage',
tempFilePaths: chooseMediaRes.tempFiles.map((file)=>file.tempFilePath),
tempFiles: chooseMediaRes.tempFiles.map((file)=>{
return {
path: file.tempFilePath,
size: file.size
} as TempFileItem;
})
} as ChooseImageSuccess);
}, (err: Error)=>{
res.reject(err.message);
});
}, ChooseImageApiProtocol, ChooseImageApiOptions) as ChooseImage;
const chooseVideo: ChooseVideo = defineAsyncApi<ChooseVideoOptions, ChooseVideoSuccess>(API_CHOOSE_VIDEO, (options: ChooseVideoOptions, res: ApiExcutor<ChooseVideoSuccess>)=>{
_chooseMedia({
mimeType: picker2.PhotoViewMIMETypes.VIDEO_TYPE
} as UTSJSONObject).then((chooseMediaRes)=>{
const file = chooseMediaRes.tempFiles[0];
res.resolve({
errMsg: '',
errSubject: 'uni-chooseVideo',
tempFilePath: file.tempFilePath,
duration: file.duration,
size: file.size,
width: file.width,
height: file.height
} as ChooseVideoSuccess);
}, (err: Error)=>{
res.reject(err.message);
});
}, ChooseVideoApiProtocol, ChooseVideoApiOptions) as ChooseVideo;
const getImageInfo: GetImageInfo = defineAsyncApi<GetImageInfoOptions, GetImageInfoSuccess>(API_GET_IMAGE_INFO, (options: GetImageInfoOptions, res: ApiExcutor<GetImageInfoSuccess>)=>{
_getImageInfo(options.src).then((getImageInfoRes)=>{
res.resolve(getImageInfoRes);
}, (err: Error)=>{
res.reject(err.message);
});
}, GetImageInfoApiProtocol, GetImageInfoApiOptions) as GetImageInfo;
const getVideoInfo: GetVideoInfo = defineAsyncApi<GetVideoInfoOptions, GetVideoInfoSuccess>(API_GET_VIDEO_INFO, (options: GetVideoInfoOptions, res: ApiExcutor<GetVideoInfoSuccess>)=>{
_getVideoInfo(options.src).then((getVideInfoRes)=>{
res.resolve({
size: getVideInfoRes.size,
duration: getVideInfoRes.duration!,
width: getVideInfoRes.width!,
height: getVideInfoRes.height!,
type: getVideInfoRes.type!,
orientation: getVideInfoRes.orientation!
} as GetVideoInfoSuccess);
}, (err: Error)=>{
res.reject(err.message);
});
}, GetVideoInfoApiProtocol, GetVideoInfoApiOptions) as GetVideoInfo;
interface UniExtApi {
chooseImage: ChooseImage;
getImageInfo: GetImageInfo;
chooseVideo: ChooseVideo;
getVideoInfo: GetVideoInfo;
}
return {
chooseImage,
getImageInfo,
chooseVideo,
getVideoInfo
} as UniExtApi;
}
......@@ -3,7 +3,7 @@ import { UniServiceJSBridge } from './bridge'
import { registerApp as __registerApp, getApp } from './framework/app'
import { definePage as __definePage } from '@dcloudio/uni-app-plus/service/framework/page'
import { getCurrentPages } from '@dcloudio/uni-app-plus/service/framework/page'
export * from '@dcloudio/uni-runtime'
export default {
uni,
getApp,
......
import '@dcloudio/uni-uts-v1/lib/javascript/lib/runtime/uts.js'
export {
isFunction,
isString,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册