HBuilder X打包运行鸿蒙应用(vue2 -> vue3)

1. manifest.json配置为vueVersion: 3

2. main.js调整(下方已补充)

3. store调整

import { createStore } from 'vuex'
const state = {}
const getters = {}
const mutations = {}
const actions = {}
// 创建 Vuex Store
const store = createStore({
  state,
  getters,
  mutations,
  actions,
});

export default store

4. 增加入口文件index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <script>
      var coverSupport = "CSS" in window && typeof CSS.supports === "function" && (CSS.supports("top: env(a)") || CSS.supports("top: constant(a)"));
      document.write(
        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
          (coverSupport ? ", viewport-fit=cover" : "") +
          '" />'
      );
    </script>
    <title></title>
    <!--preload-links-->
    <!--app-context-->
  </head>
  <body>
    <div id="app"><!--app-html--></div>
    <script type="module" src="/main.js"></script>
  </body>
</html>

5. require方式调整为import导入方式

6. main导入uni.promisify.adaptor3-2.js uniapp Vue 3转Vue 2 API Promise 化调用结果的方式

API Promise 化 调用结果的方式

// uni.promisify.adaptor3-2.js
uni.addInterceptor({
    returnValue(res) {
        if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
            return res;
        }
        const returnValue = [undefined, undefined];
        return res
            .then((res) => {
                returnValue[1] = res;
            })
            .catch((err) => {
                returnValue[0] = err;
            })
            .then(() => returnValue);
    },
});

7. 项目运行,组件调整,样式调整,vue2组件升级为vue3组件;vue3不建议使用标签样式,比如p, img

8. jweixin-module等部分使用动态导入方式

// loadJweixin.js
xport async function loadJweixin() {
    try {
        // 动态导入 jweixin-module
        return await import('jweixin-module');
    } catch (error) {
        console.error('Failed to load jweixin-module:', error);
        throw error;
    }
}

// main.js
import App from "./App";
// 全局状态管理
import store from "./store";

// #ifdef VUE3
import { createSSRApp } from "vue";
import "./uni.promisify.adaptor3-2";
import uViewPlus from "@/uni_modules/uview-plus";
// #ifdef H5
import { loadJweixin } from "./utils/loadJweixin.js";
// #endif

// 不能修改导出的 createApp 方法名,不能修改从 Vue 中导入的 createSSRApp。
export function createApp() {
    // 创建应用实例
    const app = createSSRApp(App);
    // 使用 uViewPlus
    app.use(uViewPlus);

    // 设置全局配置
    app.config.globalProperties.$store = store;

    // #ifdef H5
    loadJweixin().then((res) => {
        app.config.globalProperties.$jweixin = res;
    });
    // #endif

    // 忽略某些元素
    // app.config.ignoredElements.push('wx-open-launch-weapp');

    return {
        app,
    };
}
// #endif

9. H5各个界面运行,出现异常进行代码调整

10. 适配小程序

11. 适配APP

12. 适配鸿蒙模拟器,以及处理tabbar界面不显示问题

  • a). 白屏不展示问题按照官网方式,注释pages.json,二分法测试各个界面
  • b). tabbar界面第一次不显示数据:第一次打开onShow不会执行,执行函数需要在onLoad里面
  • c). axios拦截器不支持,接口会没有响应

13. 华为安卓权限监听显示顶部蒙层,导入permissionListener.js文件,使用的uni.createRequestPermissionListener

/**
 * @Author:liyuqi
 * @Date:2024-09-06 10:38:45
 * @LastEditors:liyuqi
 * @Description:uni.createRequestPermissionListener()
 * @Description:安卓权限说明顶部蒙层
 * @Description:文档地址:https://uniapp.dcloud.net.cn/api/system/create-request-permission-listener.html
 * @Description:注意:HBuilderX (4.0+) android 平台支持;HBuilderX 4.01 Vue2项目需要使用自定义基座测试监听权限申请的功能,标准基座暂不支持测试。
 */
// #ifndef APP
export default null;
// #endif

// #ifdef APP
let permissionListener = null;
// 是安卓平台,同时有uni.createRequestPermissionListener这个api
if (getApp().globalData.isAndroid && uni.createRequestPermissionListener) {
    permissionListener = uni.createRequestPermissionListener();
}
let canRunListener = true;  // 是否可以执行所有监听方法
let canStopListener = true; // 是否可以执行取消所有监听方法,避免唤起权限会触发App.vue的onHide生命周期
const permissionEnums = {
    "ACCESS_COARSE_LOCATION": {
        name: "定位",
        explain: "展示附近店铺、填写收货地址等相关功能"
    },
    "ACCESS_FINE_LOCATION": {
        name: "定位",
        explain: "展示附近店铺、填写收货地址等相关功能"
    },
    "READ_EXTERNAL_STORAGE": {
        name: "存储",
        explain: "上传图片、上传视频等相关功能"
    },
    "CAMERA": {
        name: "相机",
        explain: "扫二维码、拍摄图片等相关功能"
    },
    "WRITE_EXTERNAL_STORAGE": {
        name: "存储",
        explain: "把图片保存到相册等相关功能"
    }
}

/**
 * 权限说明文字
 * @param {String} permissionName  例如:ACCESS_COARSE_LOCATION
 */
const texts = (permissionName) => {
    let title = "";
    let content = "";
    let permissionInfo = permissionEnums[permissionName] || null;
    if (permissionInfo) {
        const { name, explain } = permissionInfo;
        title = `${name}权限使用说明`;
        content = `将获取${name}权限,用于${explain}`;
    } else {
        title = "";
        content = "";
    }
    return {
        title,
        content
    }
};

/**
 * 绘画顶部权限说明
 * 文档地址:https://www.html5plus.org/doc/zh_cn/nativeobj.html
 * @function drawView title标题,content描述使用说明
 * @function hideView 隐藏顶部权限说明
 */
let view = null;
const drawView = ({ title, content }) => {
    console.log("drawView方法的参数值:", title, content);
    if (view || !title || !content) return;     // 没有标题和内容则return出去
    const { windowTop, windowWidth, statusBarHeight } = uni.getSystemInfoSync();
    const topHeight = windowTop + statusBarHeight;
    const distance = {
        box: 10,    // 盒子距离视图两边的距离
        text: 20    // 文字距离视图两边的距离
    }
    // 标题的相关样式
    const titleStyle = {
        size: 16,
        height: 16,
        top: `${topHeight + 22}`,
        color: "#000",
    }
    // 内容的相关样式
    const contentStyle = {
        size: 14,
        height: 0,
        top: `${parseInt(titleStyle.top) + titleStyle.height + 6}`,
        color: "#656563",
    }
    const contentLength = content.length;   // 权限说明内容文字长度
    const contentWidth = windowWidth - distance.text * 2;   // 内容的宽度
    const contentRowCount = Math.floor(contentWidth / contentStyle.size);   // 一行占几个文字
    const contentRows = Math.ceil(contentLength / contentRowCount);     // 当前内容占几行
    contentStyle.height = contentRows * (contentStyle.size + 4);    // 内容的高度
    /**
     * @description 计算盒子的高度
     * 获取content到盒子顶部距离:parseInt(contentStyle.top) - topHeight - distance.box
     * content的高度:contentStyle.height
     * 获取content到盒子底部的距离:(distance.text - distance.box)
     */
    const boxHeight = (parseInt(contentStyle.top) - topHeight - distance.box) + contentStyle.height + (distance.text - distance.box);
    view = new plus.nativeObj.View('per-modal', {
        top: '0',
        left: '0',
        width: '100%',
        backgroundColor: 'rgba(0,0,0,0.2)'
    })
    view.drawRect({
        color: '#fff',
        radius: '5px',
    }, {
        top: `${topHeight + distance.box}px`,
        left: `${distance.box}px`,
        right: `${distance.box}px`,
        height: `${boxHeight}px`
    })
    view.drawText(title, {
        top: `${titleStyle.top}px`,
        left: `${distance.text}px`,
        height: `${titleStyle.height}px`
    }, {
        size: `${titleStyle.size}px`,
        align: "left",
        color: titleStyle.color,
        weight: "bold"
    })
    view.drawText(content, {
        top: `${contentStyle.top}px`,
        left: `${distance.text}px`,
        right: `${distance.text}px`,
        height: `${contentStyle.height}px`,
    }, {
        size: `${contentStyle.size}px`,
        lineSpacing: "2px",
        align: "left",
        color: contentStyle.color,
        verticalAlign: "top",
        whiteSpace: "normal"
    })
    let timer = setTimeout(() => {
        view && view.show();
        clearTimeout(timer);
        timer = null;
    }, 200)
}

// 关闭顶部权限说明
const hideView = () => {
    if (view) {
        view.hide();
        view = null;
    }
}

// 监听权限方法
const listenerFunc = () => {
    stopFunc();     // 取消所有监听方法
    if (canRunListener && permissionListener) {
        let permissionName = "";    // 权限名称
        let hasConfirm = false;     // 是否有权限弹窗(触发permissionListener.onConfirm这个回调)
        canRunListener = false;
        canStopListener = false;
        // 监听申请系统权限
        permissionListener.onRequest((e) => {
            console.log("permissionListener.onRequest回调:", e);
            if (Array.isArray(e) && e.length > 0) {
                const stringToArray = e[0].split(".");
                permissionName = stringToArray[stringToArray.length - 1];
                console.log("权限名称:", permissionName);
            }
        });
        // 监听弹出系统权限授权框
        permissionListener.onConfirm((e) => {
            console.log("permissionListener.onConfirm回调:", e);
            hasConfirm = true;
            if (permissionName) {
                drawView(texts(permissionName));
            }
        });
        // 监听权限申请完成
        permissionListener.onComplete((e) => {
            console.log("permissionListener.onComplete回调:", e);
            // e.length === 0:权限列表无值,则不继续做相对逻辑
            if (e.length === 0) return;
            let name = "";      // 权限名称
            let explain = "";   // 权限说明
            if (permissionName && permissionEnums[permissionName]) {
                name = permissionEnums[permissionName].name;
                explain = permissionEnums[permissionName].explain;
            }
            const Manifest = plus.android.importClass("android.Manifest");
            const MainActivity = plus.android.runtimeMainActivity();
            const permissionStatus = MainActivity.checkSelfPermission(Manifest.permission[permissionName]);
            console.log("当前权限状态:", permissionStatus);
            /**
             * @description 永久拒绝该权限,则引导用户前往设置页
             * permissionStatus != 0:权限状态是拒绝
             * !hasConfirm:没有permissionListener.onConfirm这个回调
             */
            if (permissionStatus != 0 && !hasConfirm && name && explain) {
                uni.showModal({
                    title: "温馨提示",
                    content: `开启${name}权限后,才能${explain}`,
                    showCancel: true,
                    confirmText: "去设置",
                    success: (res) => {
                        if (res.confirm) {
                            uni.openAppAuthorizeSetting();
                        }
                    }
                })
                return;
            }
            canStopListener = true;
            hideView();
        });
    }
}

// 取消所有监听方法
const stopFunc = () => {
    if (canStopListener && permissionListener) {
        console.log("执行permissionListener.stop()方法");
        canRunListener = true;
        hideView();
        permissionListener.stop();
    }
}

let exportObj = null;
if (permissionListener) {
    exportObj = {
        listenerFunc,
        stopFunc
    };
} else {
    exportObj = null;
}

export default exportObj;
// #endif

导入方式

// App.vue
// #ifdef APP
import permissionListener from  "./utils/permissionListener.js";
// #endif

export default {
	onLaunch: function(options) {
	},
	onShow() {
      // #ifdef APP
      permissionListener && permissionListener.listenerFunc();
      // #endif
	},
	onHide() {
      // #ifdef APP
      permissionListener && permissionListener.stopFunc();
      // #endif
    },
}
<think>好的,我需要帮助用户了解如何使用UniAppVue2打包鸿蒙应用。根据用户提供的引用资料,首先,引用[1]提到用户公司的项目是UniApp Vue2,需要兼容鸿蒙App,但引用[2]指出官方文档上线的是Vue3支持。这可能意味着Vue2的支持可能有限或者需要特定配置。 接下来,引用[3]和[4]提到了Vue3的转换过程和开发环境配置,比如JDK17和DevEco Studio的使用。这说明即使官方文档主要针对Vue3,Vue2项目仍然可能需要类似的环境设置。需要注意JDK版本兼容问题,因为引用[4]提到本地JDK版本不一致会导致问题,必须使用JDK17。 然后,用户的问题是如何在Vue2下打包鸿蒙应用。虽然官方文档可能没有明确说明Vue2的支持,但根据引用[1]和[3],用户可能需要手动调整配置或遵循一些步骤。可能需要检查UniApp的配置,生成签名,并确保HBuilder正确设置。 此外,可能需要处理代码兼容性问题,比如某些API在鸿蒙上的差异,这需要参考官方文档和社区解决方案。例如,引用[3]提到了一些问题及解决方案,可能需要类似的处理步骤。 最后,生成相关问题时要考虑用户可能遇到的后续问题,比如性能优化、兼容性处理等,确保覆盖潜在的需求。</think>### 使用 UniAppVue 2 打包鸿蒙应用的教程 #### 1. 环境准备 - **开发工具**:安装 HBuilderX(用于 UniApp 开发)和 DevEco Studio(鸿蒙开发工具)[^4]。 - **JDK 版本**:**必须使用 JDK 17**(鸿蒙开发工具内置 JDK 17,版本不一致会导致报错)。 - **Node.js**:建议使用稳定版本(如 v16.x 或 v18.x)。 --- #### 2. 项目配置 **步骤 1:生成鸿蒙签名** - 在 DevEco Studio 中创建空白鸿蒙项目,通过 `File > Project Structure > Project > Signing Configs` 生成签名文件(`.p12` 和 `.cer`)。 - 将签名文件的路径、别名、密码等信息保存备用。 **步骤 2:HBuilderX 配置** 1. 在 UniApp 项目的 `manifest.json` 中,选择“鸿蒙”为发行平台。 2. 将 DevEco Studio 生成的签名信息填入 `manifest.json` 的“鸿蒙应用配置”模块。 - 示例配置: ```json "harmony" : { "package": "com.example.app", "signature": "path/to/your.p12", "alias": "test", "password": "123456" } ``` --- #### 3. 代码兼容性处理 - **API 差异**:部分 UniApp API 在鸿蒙平台可能不兼容,需替换为鸿蒙原生 API(如文件操作、网络请求)[^1]。 - **组件调整**:鸿蒙的 `<swiper>` 等组件可能与 UniApp 的语法不同,需参考[鸿蒙官方文档](https://developer.harmonyos.com/cn/docs/documentation/doc-references)调整[^3]。 --- #### 4. 打包运行 1. **生成鸿蒙工程**:在 HBuilderX 中点击“发行 > 原生 App-鸿蒙”,生成鸿蒙平台代码。 2. **导入 DevEco Studio**:将生成的代码导入 DevEco Studio,检查依赖和配置。 3. **编译运行**:连接鸿蒙模拟器或真机,点击运行按钮调试。 --- #### 5. 注意事项 - **Vue 2 的局限性**:UniApp 官方对鸿蒙的支持主要面向 Vue3,Vue2 项目可能需手动解决兼容性问题(如生命周期差异)[^2]。 - **调试工具**:鸿蒙的日志系统与安卓不同,需使用 `hilog` 接口输出日志[^3]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值