鸿蒙uiapp支持读取当地和在线拉取运行
前言:鸿蒙运行uiapp小程序来源于uiapp的SDK包提供的能力,如有更多定制化业务,请自行查看SDK内容导入相应的API,比方以下import {
openUniMP,
releaseWgtToRunPath,
getUniMPRunPath,
isExistsUniMP,
getAppVersionInfo,
registerModule
} from '@dcloudio/uni-app-runtime' 告示:只支持Vue3版本运行
uniMP小程序
#初始化 sdk 全局环境
interface IInitConfig {
debug?: boolean
}
function init(ability: UIAbility, stage: window.WindowStage, config?: IInitConfig)
复制代码
#获取uni小程序应用资源部署路径
function getUniMPRunPath(appID: string): string
复制代码
#判断应用资源是否已经部署
function isExistsUniMP(appId: string): boolean
复制代码
#将wgt应用资源包部署到运行路径中
type ReleaseWgtToRunPathCallback = (code: 1 | -1, error?: Error) => void
function releaseWgtToRunPath(appID: string, wgtPath: string, callback: ReleaseWgtToRunPathCallback)
复制代码
#获取已经部署的小程序应用资源版本信息
interface IAppVersionInfo {
name: string
code: string
}
function getAppVersionInfo(appId: string): IAppVersionInfo | null
复制代码
#启动小程序应用并获得IUniMP实例
interface ICapsuleStyle {
backgroundColor?: string
textColor?: string
highlightColor?: string
borderColor?: string
}
interface ICapsuleMenuActionSheetItem {
id: string
title: string
}
interface IOpenUniMPConfig {
showCapsuleButton?: boolean
capsuleMenuActionSheetItems?: ICapsuleMenuActionSheetItem[]
capsuleButtonStyle?: ICapsuleStyle
redirectPath?: string
extraData?: Object // 传递给小程序的额外数据,小程序中onLaunch,uni.getLaunchOptionsSync可以获取
}
export interface IUniMP {
hide(): void
show(): void
close(): void
sendUniMPEvent: (event: string, data: ESObject) => void
on(event: 'uniMPEvent', callback: (event: string, data: ESObject, notify: (...args: ESObject[]) => void) => void): void
on(event: 'menuItemClick', callback: (id: string) => void): void
on(event: 'close' | 'show' | 'hide', callback: () => void): void
off(name: string, callback: Function): void
}
function openUniMP(appID: string, config?: IOpenUniMPConfig): IUniMP
复制代码
#IUniMP实例下的API
#隐藏当前小程序应用
hide(): void
复制代码
#表现当前小程序应用
show(): void
复制代码
#关闭当前小程序应用
close(): void
复制代码
#向小程序发送变乱
sendUniMPEvent: (event: string, data: ESObject) => void
复制代码
#监听小程序发送过来的变乱
on(event: 'uniMPEvent', callback: (event: string, data: ESObject, notify: (...args: ESObject[]) => void) => void): void
复制代码
#监听右上角菜单的点击变乱
on(event: 'menuItemClick', callback: (id: string) => void): void
复制代码
#监听小程序隐藏、表现、关闭变乱
on(event: 'close' | 'show' | 'hide', callback: () => void): void
复制代码
#移除对应的监听变乱
off(name: string, callback: Function): void
[*]修改鸿蒙项目根目次文件 oh-package.json5 的依赖 "@dcloudio/uni-app-runtime": "版本号",如下图所示 查看最新版本号https://i-blog.csdnimg.cn/direct/f785ca361e97485e869e6ef45463daf1.png
[*]点击右上角 Sync Now,并等候 Sync 结束
[*]首先需要初始化uiapp SDK包 ,初始化如下 在EntryAbility文件入口如下
import { init } from '@dcloudio/uni-app-runtime' init(this, windowStage, {
debug: true
}) <img alt=""src="https://i-blog.csdnimg.cn/direct/1eb1fece6be84fdf85cbfa2791a61251.png"/>
[*] 将生成的wgt包拷贝到 entry/src/main/resources/resfile 目次下,如下图所示
https://i-blog.csdnimg.cn/img_convert/fdffc7f3c035a8dc21b4b460d419d909.png
4.再通过 releaseWgtToRunPath 函数释放 wgt 包到运行目次,最后通过 openUniMP 函数打开小程序,代码如下https://i-blog.csdnimg.cn/direct/01bf32f87c9f42448a4beb6f7081328e.png
在线拉取运行:
/**
*下载 uiapp 包
*/
function downloadUiApp(fileName: string, downUrl: string, md5Code: string): Promise<string> {
return new Promise((resolve) => {
DownloadUiApp.downloadUiApp(
downUrl,
fileName,
md5Code,
{
onError: (code: string = '') => {
// 下载错误
if (code === 'MD5_error') {
promptAction.showToast({
message: '文件损坏,请重新点击应用'
})
}
resolve(code)
},
onSuccess: (srcFilePath: string) => {
// 下载并保存成功
Logger.info('下载文件完成地址为', srcFilePath)
resolve(srcFilePath)
}
})
})
} 下载文件Class
import { common } from '@kit.AbilityKit';
import fs, { ReadOptions, WriteOptions } from '@ohos.file.fs';
import { BusinessError, request } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
import Logger from './Logger'
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
Logger.prefix = 'uiapp'
export class DownloadUiApp {
/**
* 获取应用沙箱存储目录 统一一下,方便APP设置页面删除
* @returns
*/
static getLocalCacheDir(): string {
let cache_dir_name = "uiapps";
let cache_dir = getContext().filesDir + "/" + cache_dir_name;
console.info(`createCacheDir cache_dir: ${cache_dir}`);
let existAppCacheDir = fileIo.accessSync(cache_dir, fileIo.AccessModeType.EXIST)
if (!existAppCacheDir) {
fileIo.mkdirSync(cache_dir, true);
}
return cache_dir
}
static async checkAndRemoveFile(path: string) {
const exist = await fs.access(path);
if (exist) {
await fs.unlink(path);
}
}
//计算文件的MD5码
public static computeMD5(file: string | number): Uint8Array {
let md5Stream: fs.Stream
if (typeof file === 'string') {
md5Stream = fs.createStreamSync(file, "r");
} else {
md5Stream = fs.fdopenStreamSync(file, "r")
}
let dataBuff: ArrayBuffer = new ArrayBuffer(4096)
let mdAlgName = "MD5";
let md = cryptoFramework.createMd(mdAlgName);
let readCount = md5Stream.readSync(dataBuff)
while (readCount > 0) {
let messageData = new Uint8Array(dataBuff.slice(0, readCount));
let updateMessageBlob: cryptoFramework.DataBlob = { data: messageData };
md.updateSync(updateMessageBlob);
readCount = md5Stream.readSync(dataBuff)
}
let mdResult = md.digestSync();
md5Stream.closeSync()
return mdResult.data
}
public static uint8ArrayToHexStr(data: Uint8Array): string {
let hexString = '';
let i: number;
for (i = 0; i < data.length; i++) {
let char = ('00' + data.toString(16)).slice(-2);
hexString += char;
}
return hexString;
}
public static checkFileMD5(srcFilePath: string, fileMd5Code: string) {
let file = fs.openSync(srcFilePath, fs.OpenMode.READ_ONLY)
// 校验文件完整性
let md5Code = DownloadUiApp.uint8ArrayToHexStr(DownloadUiApp.computeMD5(file.fd)).toUpperCase()
Logger.info('md5Code:' + md5Code)
return md5Code === fileMd5Code
}
public static async downloadUiApp(
downUrl: string,
fileName: string,
fileMd5Code: string,
callback: DownloadCallback
) {
if (!downUrl.startsWith("http://") && !downUrl.startsWith("https://")) {
callback.onError()
Logger.info('uiapp请传入正确的请求URL!')
return
}
try {
// 获取应用文件路径
const localCacheDir = DownloadUiApp.getLocalCacheDir();
let srcFilePath = `${localCacheDir}/${fileName}`
await DownloadUiApp.checkAndRemoveFile(srcFilePath);
let context = getContext() as common.UIAbilityContext;
request.downloadFile(context, {
url: downUrl,
filePath: srcFilePath,
background: false,
enableMetered: true,
enableRoaming: true
})
.then((downloadTask: request.DownloadTask) => {
downloadTask.on('complete', () => {
let isComplete = DownloadUiApp.checkFileMD5(srcFilePath, fileMd5Code)
if (isComplete) {
Logger.info('uiapp下载uiapp 成功!')
callback.onSuccess(srcFilePath)
} else {
fs.unlinkSync(srcFilePath)
callback.onError('MD5_error')
}
})
downloadTask.on('fail', () => {
Logger.info('uiapp下载uiapp失败')
callback.onError('down_fail')
});
}).catch((err: BusinessError) => {
Logger.info('uiapp下载uiapp异常')
callback.onError('down_error')
});
} catch (error) {
let err: BusinessError = error as BusinessError;
Logger.info('uiapp打开下载过程失败')
callback.onError('down_open_error')
}
}
}
/**
* 下载文件的返回结果
*/
interface DownloadCallback {
// MD5_error MD5校验失败
onError: (code?: string) => void;
onStart?: () => void;
inProgress?: (progress: number, total: number) => void;
onSuccess: (srcFilePath: string) => void;
}
运行在线拉取的uiapp包
/**
*更新 uiapp 版本信息
*/
function updateUiAppFile(appId: string, newSrcFilePath: string) {
let oldSrcFilePath = preferenceUtil.getPreference(appId, '') as string
if (oldSrcFilePath && fs.accessSync(oldSrcFilePath)) {
fs.unlinkSync(oldSrcFilePath)
Logger.info('删除 uiapp 老版本地址' + oldSrcFilePath)
}
if (oldSrcFilePath !== newSrcFilePath) {
preferenceUtil.putPreference(appId, newSrcFilePath)
Logger.info('更新 uiapp 新版本地址' + newSrcFilePath)
}
}
function readLocalUiAppToSandbox(appId: string): Promise<string> {
return new Promise(async (resolve) => {
try {
Logger.info(`读取本地文件 ${appId}.wgt`)
let context = getContext() as common.UIAbilityContext;
let val: Uint8Array = context.resourceManager.getRawFileContentSync(`${appId}.wgt`);
let localCacheDir: string = DownloadUiApp.getLocalCacheDir()
//目录不存在,则先创建存放小程序目录
if (!fs.accessSync(localCacheDir, fs.AccessModeType.EXIST)) {
await fs.mkdir(localCacheDir, true)
}
Logger.info("小程序 pathDir: " + localCacheDir);
// 待拷贝文件沙箱路径
let filePath: string = `${localCacheDir}/${appId}.wgt`;
// 若文件不存在,则创建文件。
let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let writeLen = fs.writeSync(file.fd, val.buffer as ArrayBuffer);
fs.closeSync(file);
Logger.info('复制到沙箱路径', filePath)
resolve(filePath)
} catch (error) {
Logger.info('读取本地文件错误')
resolve('')
}
})
}
// 小程序运行实例集合
let uniMPInstanceCollections: Record<string, ESObject> = {}
function uniMenuItemsClick(code: string, uniMPInstance: ESObject) {
Logger.info('menuItemClick::' + code)
switch (code) {
case CommonConstants.UNI_BACKEND_CODE:
uniMPInstance.hide()
break;
case CommonConstants.UNI_CLOSE_CODE:
//关闭小程序
uniMPInstance.close()
uniMPInstance = null
break;
}
}
/**
*调起 uiapp
*/
async function loadUiApp(appId: string, redirectPath?: string) {
//进度加载类弹出框
const dialogId = DialogHelper.showLoadingDialog({
loadType: SpinType.spinP,
loadColor: Color.White,
loadSize: 30,
backgroundColor: '#BB000000',
content: "加载中…",
fontSize: 15,
autoCancel: true
})
try {
let uiappInfo = await checkUiAppStatus(appId)
let uiAppDirPath = uiappInfo.uiAppDirPath
if (uiappInfo.code === 'version_error' || true) {
let localCacheDir: string = DownloadUiApp.getLocalCacheDir()
let srcFilePath = `${localCacheDir}/${appId}`
if (!fs.accessSync(srcFilePath)) {
let sandboxFilePath = await readLocalUiAppToSandbox(appId)
if (sandboxFilePath) {
uiAppDirPath = sandboxFilePath
} else {
promptAction.showToast({
message: '获取版本信息异常'
})
Logger.info('version_error return')
return
}
}
}
Logger.info(`完成检查动作获得地址 :: ${JSON.stringify(uiappInfo)}`)
DialogHelper.closeDialog(dialogId)
// 已经存在,并且运行中直接打开小程序
if (uniMPInstanceCollections && uniMPInstanceCollections.isRunning()) {
Logger.info('小程序 uniMPInstance: show')
uniMPInstanceCollections.show()
} else {
// 小程序没执行或者已经被关闭掉了的重新运行
releaseWgtToRunPath(appId, uiAppDirPath, (code) => {
Logger.info('小程序::getAppVersionInfo' + JSON.stringify(getAppVersionInfo(appId)))
if (code === CommonConstants.UIAPP_RUN_SUCCESS) {
updateUiAppFile(appId, uiAppDirPath)
uniMPInstanceCollections = openUniMP(appId, {
redirectPath: redirectPath || '',
capsuleMenuActionSheetItems: [
{
id: CommonConstants.UNI_BACKEND_CODE,
title: '将小程序隐藏到后台'
},
{
id: CommonConstants.UNI_CLOSE_CODE,
title: '关闭小程序'
}
]
});
uniMPInstanceCollections.capsuleCloseButtonClick = () => {
uniMenuItemsClick(CommonConstants.UNI_CLOSE_CODE, uniMPInstanceCollections)
}
uniMPInstanceCollections.on('menuItemClick', (id: string) => {
uniMenuItemsClick(id, uniMPInstanceCollections)
})
}
})
}
} catch (error) {
DialogHelper.closeDialog(dialogId)
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
Logger.info(`执行打开小程序失败 code: ${code}message: ${message}`)
}
} 注册模块提供给uiapp小程序使用
/**
*注册 BGYUniCommonNativeModule 模块,供uiapp小程序调用
*/
registerModule('BGYUniCommonNativeModule', {
getUserInfo(data: object, callback: Function) {
let userInfoData = preferenceUtil.getPreference('userInfoData', '') as string
Logger.info('小程序 getUserInfo' + userInfoData)
callback && callback({
code: 200,
data: JSONUtil.isJSONStr(userInfoData) && JSONUtil.jsonToBean(userInfoData) || null
})
}
})
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]