HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

UniDevTools - UniApp调试工具推荐

WebView调试 nvue vue3 真机调试

<b>在线文档 - 完整版使用教程:<br>
https://dev.api0.cn


不知道大家是否和我一样已经受够了使用Uniapp开发APP时需要插USB线连着HbuilderX才能看到console打印,各项指标数据全是黑盒,开发APP时无法选择调试节点等各类头疼问题。Uniapp官方一直没有一个标准的调试工具,为什么不能像Chrome调试工具一样调试App呢?为此我们开发了一个插件,把这些痛点问题依次解决!

UniDevTools是一个UniApp工具库,包含console打印日志、request请求记录、storage缓存管理、vuex状态管理、框架报错记录、文件管理等多功能调试工具合集:

  • Tools 常用工具(重启、请求构建、跳转指定页面、注入VConsole、Eruda)、自定义工具页
  • Error 全局报错拦截:vue模板报错、uniapp框架报错
  • Console 打印日志记录
  • Network request请求记录、重发请求
  • JsRunner 执行js代码、支持App和H5端
  • Storage 缓存管理,支持localStorage、cookie、sessionStorage
  • Pages 路由页面管理、日活时间记录
  • Vuex 状态管理,支持VuexPiniaglobalData
  • Logs 框架运行日志、框架api调用日志、自定义上报的日志记录
  • Info 当前设备参数、App启动参数、运行时信息、权限列表
  • UniBus uni框架事件总线调用记录
  • FileSys 本地文件管理系统
  • Setting DevTools工具设置、清空全部缓存、导出全部日志
兼容框架: Vue2+js+vuex Vue3+ts+vuex(pinia)
兼容平台: H5 APP 微信小程序 APP-NVUE 其他小程序 UniAppX
√(大部分功能支持) 未测试 × (待办中)

<b>本工具支持在<span style="color: red;">生产环境</span>中使用</b><br>
<span style="font-size: 13px;">生产环境使用时建议隐藏调试浮窗,可设置通过特定方法进入调试页</span>

下载运行本示例项目使用说明:

注意该项目使用Cli模式搭建,请勿导入HBuilderX中运行<br>
开始前请先准备好环境:node18 + pnpm

  1. 克隆项目到本地:
    git clone https://github.com/1615958039/UniDevTools.git
  2. 进入项目
    cd ./UniDevTools
  3. 安装依赖
    pnpm i
  4. 启动预览H5
    pnpm run dev:h5

说明:示例基于UniApp+Vue3+ts+Vite,UI框架为TM-UI3.1

把调试工具引入自己项目:

  1. 下载最新源码包v3.4.5

    GitHub: releases <br>
    Gitee: releases <br>
    备用:v3.4.5_r.zip

  2. 引入项目(请移步至在线文档):https://dev.api0.cn/guide/install

示例项目

《斗图助手APP》表情包制作工具<br>
该项目基于Uniapp+Vue2,已集成DevTools工具<br>
打开APP后在搜索页输入__devtools__即可打开调试弹窗查看请求和日志数据

<div class="qrCodeList" style="display: flex;flex-direction: row; align-items: center;gap: 30px;flex-wrap: wrap;">
<div class="codeItem">
<img src="https://dev.api0.cn/qrCode/iosAppStore.png" style="width: 160px;height: 160px;">
<div class="codeTitle">苹果AppStore</div>
</div>
<br><br><br>
<div class="codeItem">
<img src="https://dev.api0.cn/qrCode/androidYYB.png" style="width: 160px;height: 160px;">
<div class="codeTitle">安卓应用宝</div>
</div>
<br><br><br>
<div class="codeItem">
<img src="https://dev.api0.cn/qrCode/wxmp.jpg" style="width: 160px;height: 160px;">
<div class="codeTitle">微信小程序</div>
</div>
<br><br><br>
<div class="codeItem">
<img src="https://dev.api0.cn/qrCode/web.png" style="width: 160px;height: 160px;">
<div class="codeTitle">H5</div>
</div>
</div>

继续阅读 »

<b>在线文档 - 完整版使用教程:<br>
https://dev.api0.cn


不知道大家是否和我一样已经受够了使用Uniapp开发APP时需要插USB线连着HbuilderX才能看到console打印,各项指标数据全是黑盒,开发APP时无法选择调试节点等各类头疼问题。Uniapp官方一直没有一个标准的调试工具,为什么不能像Chrome调试工具一样调试App呢?为此我们开发了一个插件,把这些痛点问题依次解决!

UniDevTools是一个UniApp工具库,包含console打印日志、request请求记录、storage缓存管理、vuex状态管理、框架报错记录、文件管理等多功能调试工具合集:

  • Tools 常用工具(重启、请求构建、跳转指定页面、注入VConsole、Eruda)、自定义工具页
  • Error 全局报错拦截:vue模板报错、uniapp框架报错
  • Console 打印日志记录
  • Network request请求记录、重发请求
  • JsRunner 执行js代码、支持App和H5端
  • Storage 缓存管理,支持localStorage、cookie、sessionStorage
  • Pages 路由页面管理、日活时间记录
  • Vuex 状态管理,支持VuexPiniaglobalData
  • Logs 框架运行日志、框架api调用日志、自定义上报的日志记录
  • Info 当前设备参数、App启动参数、运行时信息、权限列表
  • UniBus uni框架事件总线调用记录
  • FileSys 本地文件管理系统
  • Setting DevTools工具设置、清空全部缓存、导出全部日志
兼容框架: Vue2+js+vuex Vue3+ts+vuex(pinia)
兼容平台: H5 APP 微信小程序 APP-NVUE 其他小程序 UniAppX
√(大部分功能支持) 未测试 × (待办中)

<b>本工具支持在<span style="color: red;">生产环境</span>中使用</b><br>
<span style="font-size: 13px;">生产环境使用时建议隐藏调试浮窗,可设置通过特定方法进入调试页</span>

下载运行本示例项目使用说明:

注意该项目使用Cli模式搭建,请勿导入HBuilderX中运行<br>
开始前请先准备好环境:node18 + pnpm

  1. 克隆项目到本地:
    git clone https://github.com/1615958039/UniDevTools.git
  2. 进入项目
    cd ./UniDevTools
  3. 安装依赖
    pnpm i
  4. 启动预览H5
    pnpm run dev:h5

说明:示例基于UniApp+Vue3+ts+Vite,UI框架为TM-UI3.1

把调试工具引入自己项目:

  1. 下载最新源码包v3.4.5

    GitHub: releases <br>
    Gitee: releases <br>
    备用:v3.4.5_r.zip

  2. 引入项目(请移步至在线文档):https://dev.api0.cn/guide/install

示例项目

《斗图助手APP》表情包制作工具<br>
该项目基于Uniapp+Vue2,已集成DevTools工具<br>
打开APP后在搜索页输入__devtools__即可打开调试弹窗查看请求和日志数据

<div class="qrCodeList" style="display: flex;flex-direction: row; align-items: center;gap: 30px;flex-wrap: wrap;">
<div class="codeItem">
<img src="https://dev.api0.cn/qrCode/iosAppStore.png" style="width: 160px;height: 160px;">
<div class="codeTitle">苹果AppStore</div>
</div>
<br><br><br>
<div class="codeItem">
<img src="https://dev.api0.cn/qrCode/androidYYB.png" style="width: 160px;height: 160px;">
<div class="codeTitle">安卓应用宝</div>
</div>
<br><br><br>
<div class="codeItem">
<img src="https://dev.api0.cn/qrCode/wxmp.jpg" style="width: 160px;height: 160px;">
<div class="codeTitle">微信小程序</div>
</div>
<br><br><br>
<div class="codeItem">
<img src="https://dev.api0.cn/qrCode/web.png" style="width: 160px;height: 160px;">
<div class="codeTitle">H5</div>
</div>
</div>

收起阅读 »

离线打包 Vue2 项目,无法使用uni.createRequestPermissionListener()

离线打包 uni-app
  1. 升级到4.23后调用uni.createRequestPermissionListener() 提示[JS Framework] 当前运行的基座不包含原生插件[UTS-Proxy],请在manifest中配置该插件,重新制作包括该原生插件的自定义运行基座
  2. 引入utsplugin-release.aar后,提示打包时未添加uni-createRequestPermissionListener
  3. 引入uni-createRequestPermissionListener-release.aar后,仍然提示打包时未添加uni-createRequestPermissionListener
继续阅读 »
  1. 升级到4.23后调用uni.createRequestPermissionListener() 提示[JS Framework] 当前运行的基座不包含原生插件[UTS-Proxy],请在manifest中配置该插件,重新制作包括该原生插件的自定义运行基座
  2. 引入utsplugin-release.aar后,提示打包时未添加uni-createRequestPermissionListener
  3. 引入uni-createRequestPermissionListener-release.aar后,仍然提示打包时未添加uni-createRequestPermissionListener
收起阅读 »

uniapp微信小程序实现跨包加载js与异步组件,支持vue2和vue3,从此和主包超限说拜拜。

体积优化 微信小程序 分包

前言

最近在接到一个二开项目,发现一个普通的小项目居然主包超过了1.5MB,并且甲方还在持续加码功能,一看就是一个屎山项目。为了更好的进行开发,我打算重新规划一下整个小程序,并且进行分包,而当我打算在清理一堆屎的时候我才发现,这堆屎有毒!原项目经过多个作者反复拉屎,完美的实现了主包拉屎,分包也拉屎的操作,导致整体已经很难优化了,因此我就想到是否可以使用异步组件和跨包加载js,从而剥离一部分的文件出来,实现主包体积优化。

上姿势点

在这里,我们需要先引入来自微信小程序官方的文档:分包异步化
微信小程序在2.11.2之后就已经支持分包异步化了,因此引入了俩个特性,支持 跨分包自定义组件引用跨分包 JS 代码引用,应用这俩个特性我们可以去优化主包体积。

1. 跨分包自定义组件引用

跨分包自定义组件引用,需要搭配占位组件的配置才可以实现,根据微信小程序官方文档描述如下。


而在uniapp中,对应的我们需要在pages.json中进行如下配置


配置之后,我们就可以在页面中正常使用了,对应的slots、props、events的传递在分包加载进来之后便可以正常响应。

但是这一切看似美好,实际上还是存在部分问题的,主要如下

  • (1) 在分包未加载完成之前,该组件为占位组件,如果是view,text等基础组件,则slots的内容会直接显示出来,影响用户体验
  • (2) 该方案只支持直接在页面使用分包组件,页面内的子组件引入均无效
  • (3) 该方案在遇到分包比较大的时候容易造成过长的加载时间等待

虽然存在着部分问题,但是我们依然可以将部分业务组件分离到分包中,然后使用跨包组件,从而减少主包的体积,在我这个项目中我对接的腾讯云IM就是通过这种形式,将消息列表对接到tabbar中,否则按照以往的经验这一部分肯定占据主包大量的空间。

2. 跨分包js调用

跨分包js调用,需要到require,而对于uniapp而言,直接使用require会导致报错,无法通过编译。因此我开发了一个插件,可以简单直接的实现调用分包js。
对应的插件地址:zion-uniapp-mp-load-package
对应的github demo地址: zionLZH/zion-uniapp-mp-load-package

  • 1.首先我们需要先安装依赖

    npm install zion-uniapp-mp-load-package -D  
    或  
    yarn add zion-uniapp-mp-load-package -D
  • 2.修改配置文件,因为vue2和vue3的配置文件不一样因此需要分别处理
    这是vue2的,新增/修改vue.config.js

const { zionUniMpLoadPackagePlugin } = require('zionUniMpLoadPackagePlugin/webpack')  
module.exports = {  
  configureWebpack: {  
    plugins: [  
      new zionUniMpLoadPackagePlugin()  
    ],  
    optimization: {  
      moduleIds: 'named',  
    }  
  },  
}

这是vue3的,新增/修改vite.config.js

import { defineConfig } from 'vite';  
import uni from '@dcloudio/vite-plugin-uni';  
import { zionUniMpLoadPackagePlugin } from './script/zionUniMpLoadPackagePlugin/vite'  

export default defineConfig({  
  plugins: [  
    uni(),  
    zionUniMpLoadPackagePlugin()  
  ],  
});
  • 3.直接调用跨包js
// 这里的packageA对应的就是分包目录  
loadMpPackage("packageA", () => {  
    // ...  
    console.log('加载成功')  
    // 这里就可以直接引入分包中对应位置的js,调用其方法  
    console.log(loadMpPackageModule('/packageA/sdk/index.js'))  
    console.log(loadMpPackageModule('/packageA/sdk/index.js').a())  
}, ({mod, errMsg}) => {  
    // ...  
    console.log('加载出错', mod, errMsg)  
})

在使用我的插件之后,基本上很多第三方的js,或者比较占体积的js可以直接转移到一个独立的分包中,从而极大的减少主包的占用,我通过这个方式把高德,省市区,im,音视频等插件都进行了转移,终于把主包减少到了1M左右。

对了,如果有大佬不吝啬的话,也可以帮我点个star哦:https://github.com/zionLZH/zion-uniapp-mp-load-package

2024年7月26日:已经确定有的bug,仅存在vue2版本,引入插件之后导致主包体积反而增大,这仅在vue2/webpack版本存在,原因是因为webpack打包模块的时候moduleId被插件接管之后计算出来的moduleId有问题(因为分包里面需要进行重定向,导致分包的Id有问题,目前暂时没有一个完美的结局方案)。建议开发者自行根据项目实际跑起来的情况确定是否采用本方案(可以先引入插件,空跑一下看看前后主包体积),感谢评论区大佬提出与配合调试。

继续阅读 »

前言

最近在接到一个二开项目,发现一个普通的小项目居然主包超过了1.5MB,并且甲方还在持续加码功能,一看就是一个屎山项目。为了更好的进行开发,我打算重新规划一下整个小程序,并且进行分包,而当我打算在清理一堆屎的时候我才发现,这堆屎有毒!原项目经过多个作者反复拉屎,完美的实现了主包拉屎,分包也拉屎的操作,导致整体已经很难优化了,因此我就想到是否可以使用异步组件和跨包加载js,从而剥离一部分的文件出来,实现主包体积优化。

上姿势点

在这里,我们需要先引入来自微信小程序官方的文档:分包异步化
微信小程序在2.11.2之后就已经支持分包异步化了,因此引入了俩个特性,支持 跨分包自定义组件引用跨分包 JS 代码引用,应用这俩个特性我们可以去优化主包体积。

1. 跨分包自定义组件引用

跨分包自定义组件引用,需要搭配占位组件的配置才可以实现,根据微信小程序官方文档描述如下。


而在uniapp中,对应的我们需要在pages.json中进行如下配置


配置之后,我们就可以在页面中正常使用了,对应的slots、props、events的传递在分包加载进来之后便可以正常响应。

但是这一切看似美好,实际上还是存在部分问题的,主要如下

  • (1) 在分包未加载完成之前,该组件为占位组件,如果是view,text等基础组件,则slots的内容会直接显示出来,影响用户体验
  • (2) 该方案只支持直接在页面使用分包组件,页面内的子组件引入均无效
  • (3) 该方案在遇到分包比较大的时候容易造成过长的加载时间等待

虽然存在着部分问题,但是我们依然可以将部分业务组件分离到分包中,然后使用跨包组件,从而减少主包的体积,在我这个项目中我对接的腾讯云IM就是通过这种形式,将消息列表对接到tabbar中,否则按照以往的经验这一部分肯定占据主包大量的空间。

2. 跨分包js调用

跨分包js调用,需要到require,而对于uniapp而言,直接使用require会导致报错,无法通过编译。因此我开发了一个插件,可以简单直接的实现调用分包js。
对应的插件地址:zion-uniapp-mp-load-package
对应的github demo地址: zionLZH/zion-uniapp-mp-load-package

  • 1.首先我们需要先安装依赖

    npm install zion-uniapp-mp-load-package -D  
    或  
    yarn add zion-uniapp-mp-load-package -D
  • 2.修改配置文件,因为vue2和vue3的配置文件不一样因此需要分别处理
    这是vue2的,新增/修改vue.config.js

const { zionUniMpLoadPackagePlugin } = require('zionUniMpLoadPackagePlugin/webpack')  
module.exports = {  
  configureWebpack: {  
    plugins: [  
      new zionUniMpLoadPackagePlugin()  
    ],  
    optimization: {  
      moduleIds: 'named',  
    }  
  },  
}

这是vue3的,新增/修改vite.config.js

import { defineConfig } from 'vite';  
import uni from '@dcloudio/vite-plugin-uni';  
import { zionUniMpLoadPackagePlugin } from './script/zionUniMpLoadPackagePlugin/vite'  

export default defineConfig({  
  plugins: [  
    uni(),  
    zionUniMpLoadPackagePlugin()  
  ],  
});
  • 3.直接调用跨包js
// 这里的packageA对应的就是分包目录  
loadMpPackage("packageA", () => {  
    // ...  
    console.log('加载成功')  
    // 这里就可以直接引入分包中对应位置的js,调用其方法  
    console.log(loadMpPackageModule('/packageA/sdk/index.js'))  
    console.log(loadMpPackageModule('/packageA/sdk/index.js').a())  
}, ({mod, errMsg}) => {  
    // ...  
    console.log('加载出错', mod, errMsg)  
})

在使用我的插件之后,基本上很多第三方的js,或者比较占体积的js可以直接转移到一个独立的分包中,从而极大的减少主包的占用,我通过这个方式把高德,省市区,im,音视频等插件都进行了转移,终于把主包减少到了1M左右。

对了,如果有大佬不吝啬的话,也可以帮我点个star哦:https://github.com/zionLZH/zion-uniapp-mp-load-package

2024年7月26日:已经确定有的bug,仅存在vue2版本,引入插件之后导致主包体积反而增大,这仅在vue2/webpack版本存在,原因是因为webpack打包模块的时候moduleId被插件接管之后计算出来的moduleId有问题(因为分包里面需要进行重定向,导致分包的Id有问题,目前暂时没有一个完美的结局方案)。建议开发者自行根据项目实际跑起来的情况确定是否采用本方案(可以先引入插件,空跑一下看看前后主包体积),感谢评论区大佬提出与配合调试。

收起阅读 »

【解决】使用yz-qr生成二维码,canvas有时候会空白问题

二维码 canvas js
// 在weapp-qrcode.js里  

// 注释下面这个代码  
// _oContext.draw()  

// 添加下面这些代码  
setTimeout(() => {  
    _oContext.draw(true, (canvasResult) => {  
        console.log('二维码绘画成功', canvasResult);  
        this.success && this.success();  
    });  
})
// 在yz-qr.vue文件下添加success成功回调  
new qrCode('canvas', {  
    text: "123456",  
    width: 100,  
    height: 100,  
    ......  
    success: () => {  
        // 二维码绘画成功回调  
        uni.canvasToTempFilePath({  
            canvasId: this.canvasId,  
            success: (res) => {  
                this.canvasQrPath = res.tempFilePath  
                this.$emit('update:qrPath', this.canvasQrPath)  
                console.log('canvas转成图片成功:', res.tempFilePath);  
            },  
            fail: (err) => {  
                console.log('canvas转成图片失败:', err)  
            }  
        }, this)  
    }  
})

↓↓↓ 各位大佬点点赞

继续阅读 »
// 在weapp-qrcode.js里  

// 注释下面这个代码  
// _oContext.draw()  

// 添加下面这些代码  
setTimeout(() => {  
    _oContext.draw(true, (canvasResult) => {  
        console.log('二维码绘画成功', canvasResult);  
        this.success && this.success();  
    });  
})
// 在yz-qr.vue文件下添加success成功回调  
new qrCode('canvas', {  
    text: "123456",  
    width: 100,  
    height: 100,  
    ......  
    success: () => {  
        // 二维码绘画成功回调  
        uni.canvasToTempFilePath({  
            canvasId: this.canvasId,  
            success: (res) => {  
                this.canvasQrPath = res.tempFilePath  
                this.$emit('update:qrPath', this.canvasQrPath)  
                console.log('canvas转成图片成功:', res.tempFilePath);  
            },  
            fail: (err) => {  
                console.log('canvas转成图片失败:', err)  
            }  
        }, this)  
    }  
})

↓↓↓ 各位大佬点点赞

收起阅读 »

vue3+electron31+vite5客户端聊天应用

vue3

基于最新跨平台技术原创研发vue3+electron31.x+vite5+pinia2+element-plus仿微信电脑版聊天室Exe程序。整个聊天程序界面清爽简约,支持展示/收缩侧边栏、electron新开多窗口、换肤等功能。

electron31+vite5+vue3+elementPlus仿微信客户端聊天exe程序ElectronViteChat

img

img

vue3-electron-wechat使用vite5.x构建工具搭建项目模板,采用vue3 setup语法开发,融合electron跨平台技术。

img

实现技术

  • 编码工具:Vscode
  • 技术框架:electron31+vite5+vue3.4.29+vue-router4.4.0
  • 跨端框架:electron^31.1.0
  • 组件库:element-plus^2.7.6 (饿了么vue3组件库)
  • 状态管理:pinia^2.1.7
  • 存储服务:pinia-plugin-persistedstate^3.2.1
  • electron打包工具:electron-builder^24.13.3
  • electron整合vite插件:vite-plugin-electron^0.28.7

img

img

前段时间有分享一篇vue3+vite5网页版聊天室,感兴趣的可以去看看。
https://ask.dcloud.net.cn/article/41153

项目结构

img

vite-electronChat聊天已经同步到我的最新原创作品集,有需要的可以去看看。
https://gf.bilibili.com/item/detail/1106312011

img

入口配置main.js

import { createApp } from 'vue'  
import './style.scss'  
import App from './App.vue'  

// 引入组件库  
import ElementPlus from 'element-plus'  
import 'element-plus/dist/index.css'  

// 引入路由/状态管理  
import Router from './router'  
import Pinia from './pinia'  

import { launchApp } from '@/windows/actions'  

launchApp().then(config => {  
  if(config) {  
    console.log('窗口参数:', config)  
    console.log('窗口id:', config?.id)  

    // 全局存储窗口配置  
    window.config = config  
  }  

  // 创建app应用实例  
  createApp(App)  
  .use(ElementPlus)  
  .use(Router)  
  .use(Pinia)  
  .mount('#app')  
})

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

electron主进程

img

/**  
 * electron主进程入口配置  
 * @author andy  
 */  

import { app, BrowserWindow } from 'electron'  

import { WindowManager } from '../src/windows/index.js'  

// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)  
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true  

const createWindow = () => {  
  let win = new WindowManager()  
  win.create({isMajor: true})  
  // 系统托盘管理  
  win.trayManager()  
  // 监听ipcMain事件  
  win.ipcManager()  
}  

app.whenReady().then(() => {  
  createWindow()  

  app.on('activate', () => {  
    if(BrowserWindow.getAllWindows().length === 0) createWindow()  
  })  
})  

app.on('window-all-closed', () => {  
  if(process.platform !== 'darwin') app.quit()  
})

项目布局模板

img

<template>  
  <template v-if="!route?.meta?.isNewWin">  
    <div  
      class="vu__container flexbox flex-alignc flex-justifyc"  
      :style="{'--themeSkin': appstate.config.skin}"  
    >  
      <div class="vu__layout flexbox flex-col">  
        <div class="vu__layout-body flex1 flexbox" @contextmenu.prevent>  
          <!-- 菜单栏 -->  
          <slot v-if="!route?.meta?.hideMenuBar" name="menubar">  
            <MenuBar />  
          </slot>  

          <!-- 侧边栏 -->  
          <div v-if="route?.meta?.showSideBar" class="vu__layout-sidebar flexbox">  
            <aside class="vu__layout-sidebar__body flexbox flex-col">  
              <slot name="sidebar">  
                <SideBar />  
              </slot>  
            </aside>  
          </div>  

          <!-- 主内容区 -->  
          <div class="vu__layout-main flex1 flexbox flex-col">  
            <ToolBar v-if="!route?.meta?.hideToolBar" />  
            <router-view v-slot="{ Component, route }">  
              <keep-alive>  
                <component :is="Component" :key="route.path" />  
              </keep-alive>  
            </router-view>  
          </div>  
        </div>  
      </div>  
    </div>  
  </template>  
  <template v-else>  
    <WinLayout />  
  </template>  
</template>

electron多窗口|新开窗口

img

/**  
 * 创建新窗口  
 * @param {object} args 窗口配置参数 {url: '/chat', width: 850, height: 600, ...}  
 */  
export function winCreate(args) {  
  window.electron.send('win-create', args)  
}
// 登录窗口  
export function loginWindow() {  
  winCreate({  
    url: '/login',  
    title: '登录',  
    width: 320,  
    height: 380,  
    isMajor: true,  
    resizable: false,  
    maximizable: false,  
    alwaysOnTop: true  
  })  
}  

// 关于窗口  
export function aboutWindow() {  
  winCreate({  
    url: '/win/about',  
    title: '关于',  
    width: 375,  
    height: 300,  
    minWidth: 375,  
    minHeight: 300,  
    maximizable: false,  
    alwaysOnTop: true,  
  })  
}  

// 设置窗口  
export function settingWindow() {  
  winCreate({  
    url: '/win/setting',  
    title: '设置',  
    width: 550,  
    height: 470,  
    resizable: false,  
    maximizable: false,  
  })  
}

新建窗口支持如下参数配置:

// 自定义窗口参数  
const windowOptions = {  
  // 窗口唯一标识id  
  id: null,  
  // 窗口标题  
  title: 'Electron-ViteChat',  
  // 窗口路由地址  
  url: '',  
  // 窗口数据传参  
  data: null,  
  // 是否是主窗口(为true则会关闭所有窗口并创建一个新窗口)  
  isMajor: false,  
  // 是否支持多开窗口(为true则支持创建多个窗口)  
  isMultiple: false,  
  // 窗口是否最大化  
  maximize: false,  
}  

// 系统窗口参数(与electron的new BrowserWindow()参数一致)  
const windowBaseOptions = {  
  // 窗口图标  
  icon: join(__root, 'resources/shortcut.ico'),  
  // 是否自动隐藏菜单栏(按下Alt键显示)  
  autoHideMenuBar: true,  
  // 窗口标题栏样式  
  titleBarStyle: 'hidden',  
  // 窗口背景色  
  backgroundColor: '#fff',  
  // 宽度  
  width: 840,  
  // 高度  
  height: 610,  
  // 最小宽度  
  minWidth: '',  
  // 最小高度  
  minHeight: '',  
  // 窗口x坐标  
  x: '',  
  // 窗口y坐标  
  y: '',  
  // 是否可缩放  
  resizable: true,  
  // 是否可最小化  
  minimizable: true,  
  // 是否可最大化  
  maximizable: true,  
  // 是否可关闭  
  closable: true,  
  // 父窗口  
  parent: null,  
  // 是否模态窗口  
  modal: false,  
  // 窗口是否置顶  
  alwaysOnTop: false,  
  // 是否显示窗口边框(要创建无边框窗口,将frame参数设置为false)  
  frame: false,  
  // 是否透明窗口(仅frame: false有效)  
  transparent: false,  
  // 创建时是否显示窗口  
  show: false,  
}

electron-builder打包配置

{  
  "productName": "Electron-ViteChat",  
  "appId": "com.andy.electron-vite-wechat",  
  "copyright": "Copyright © 2024-present Andy  Q:282310962",  
  "compression": "maximum",  
  "asar": true,  
  "directories": {  
    "output": "release/${version}"  
  },  
  "nsis": {  
    "oneClick": false,  
    "allowToChangeInstallationDirectory": true,  
    "perMachine": true,  
    "deleteAppDataOnUninstall": true,  
    "createDesktopShortcut": true,  
    "createStartMenuShortcut": true,  
    "shortcutName": "ElectronViteChat"  
  },  
  "win": {  
    "icon": "./resources/shortcut.ico",  
    "artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}",  
    "target": [  
      {  
        "target": "nsis",  
        "arch": ["ia32"]  
      }  
    ]  
  },  
  "mac": {  
    "icon": "./resources/shortcut.icns",  
    "artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}"  
  },  
  "linux": {  
    "icon": "./resources",  
    "artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}"  
  }  
}

综上就是vue3+vite5+electron31实战开发仿微信客户端聊天的一些知识分享,希望对大家有些帮助~

作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045042968
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

继续阅读 »

基于最新跨平台技术原创研发vue3+electron31.x+vite5+pinia2+element-plus仿微信电脑版聊天室Exe程序。整个聊天程序界面清爽简约,支持展示/收缩侧边栏、electron新开多窗口、换肤等功能。

electron31+vite5+vue3+elementPlus仿微信客户端聊天exe程序ElectronViteChat

img

img

vue3-electron-wechat使用vite5.x构建工具搭建项目模板,采用vue3 setup语法开发,融合electron跨平台技术。

img

实现技术

  • 编码工具:Vscode
  • 技术框架:electron31+vite5+vue3.4.29+vue-router4.4.0
  • 跨端框架:electron^31.1.0
  • 组件库:element-plus^2.7.6 (饿了么vue3组件库)
  • 状态管理:pinia^2.1.7
  • 存储服务:pinia-plugin-persistedstate^3.2.1
  • electron打包工具:electron-builder^24.13.3
  • electron整合vite插件:vite-plugin-electron^0.28.7

img

img

前段时间有分享一篇vue3+vite5网页版聊天室,感兴趣的可以去看看。
https://ask.dcloud.net.cn/article/41153

项目结构

img

vite-electronChat聊天已经同步到我的最新原创作品集,有需要的可以去看看。
https://gf.bilibili.com/item/detail/1106312011

img

入口配置main.js

import { createApp } from 'vue'  
import './style.scss'  
import App from './App.vue'  

// 引入组件库  
import ElementPlus from 'element-plus'  
import 'element-plus/dist/index.css'  

// 引入路由/状态管理  
import Router from './router'  
import Pinia from './pinia'  

import { launchApp } from '@/windows/actions'  

launchApp().then(config => {  
  if(config) {  
    console.log('窗口参数:', config)  
    console.log('窗口id:', config?.id)  

    // 全局存储窗口配置  
    window.config = config  
  }  

  // 创建app应用实例  
  createApp(App)  
  .use(ElementPlus)  
  .use(Router)  
  .use(Pinia)  
  .mount('#app')  
})

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

electron主进程

img

/**  
 * electron主进程入口配置  
 * @author andy  
 */  

import { app, BrowserWindow } from 'electron'  

import { WindowManager } from '../src/windows/index.js'  

// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)  
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true  

const createWindow = () => {  
  let win = new WindowManager()  
  win.create({isMajor: true})  
  // 系统托盘管理  
  win.trayManager()  
  // 监听ipcMain事件  
  win.ipcManager()  
}  

app.whenReady().then(() => {  
  createWindow()  

  app.on('activate', () => {  
    if(BrowserWindow.getAllWindows().length === 0) createWindow()  
  })  
})  

app.on('window-all-closed', () => {  
  if(process.platform !== 'darwin') app.quit()  
})

项目布局模板

img

<template>  
  <template v-if="!route?.meta?.isNewWin">  
    <div  
      class="vu__container flexbox flex-alignc flex-justifyc"  
      :style="{'--themeSkin': appstate.config.skin}"  
    >  
      <div class="vu__layout flexbox flex-col">  
        <div class="vu__layout-body flex1 flexbox" @contextmenu.prevent>  
          <!-- 菜单栏 -->  
          <slot v-if="!route?.meta?.hideMenuBar" name="menubar">  
            <MenuBar />  
          </slot>  

          <!-- 侧边栏 -->  
          <div v-if="route?.meta?.showSideBar" class="vu__layout-sidebar flexbox">  
            <aside class="vu__layout-sidebar__body flexbox flex-col">  
              <slot name="sidebar">  
                <SideBar />  
              </slot>  
            </aside>  
          </div>  

          <!-- 主内容区 -->  
          <div class="vu__layout-main flex1 flexbox flex-col">  
            <ToolBar v-if="!route?.meta?.hideToolBar" />  
            <router-view v-slot="{ Component, route }">  
              <keep-alive>  
                <component :is="Component" :key="route.path" />  
              </keep-alive>  
            </router-view>  
          </div>  
        </div>  
      </div>  
    </div>  
  </template>  
  <template v-else>  
    <WinLayout />  
  </template>  
</template>

electron多窗口|新开窗口

img

/**  
 * 创建新窗口  
 * @param {object} args 窗口配置参数 {url: '/chat', width: 850, height: 600, ...}  
 */  
export function winCreate(args) {  
  window.electron.send('win-create', args)  
}
// 登录窗口  
export function loginWindow() {  
  winCreate({  
    url: '/login',  
    title: '登录',  
    width: 320,  
    height: 380,  
    isMajor: true,  
    resizable: false,  
    maximizable: false,  
    alwaysOnTop: true  
  })  
}  

// 关于窗口  
export function aboutWindow() {  
  winCreate({  
    url: '/win/about',  
    title: '关于',  
    width: 375,  
    height: 300,  
    minWidth: 375,  
    minHeight: 300,  
    maximizable: false,  
    alwaysOnTop: true,  
  })  
}  

// 设置窗口  
export function settingWindow() {  
  winCreate({  
    url: '/win/setting',  
    title: '设置',  
    width: 550,  
    height: 470,  
    resizable: false,  
    maximizable: false,  
  })  
}

新建窗口支持如下参数配置:

// 自定义窗口参数  
const windowOptions = {  
  // 窗口唯一标识id  
  id: null,  
  // 窗口标题  
  title: 'Electron-ViteChat',  
  // 窗口路由地址  
  url: '',  
  // 窗口数据传参  
  data: null,  
  // 是否是主窗口(为true则会关闭所有窗口并创建一个新窗口)  
  isMajor: false,  
  // 是否支持多开窗口(为true则支持创建多个窗口)  
  isMultiple: false,  
  // 窗口是否最大化  
  maximize: false,  
}  

// 系统窗口参数(与electron的new BrowserWindow()参数一致)  
const windowBaseOptions = {  
  // 窗口图标  
  icon: join(__root, 'resources/shortcut.ico'),  
  // 是否自动隐藏菜单栏(按下Alt键显示)  
  autoHideMenuBar: true,  
  // 窗口标题栏样式  
  titleBarStyle: 'hidden',  
  // 窗口背景色  
  backgroundColor: '#fff',  
  // 宽度  
  width: 840,  
  // 高度  
  height: 610,  
  // 最小宽度  
  minWidth: '',  
  // 最小高度  
  minHeight: '',  
  // 窗口x坐标  
  x: '',  
  // 窗口y坐标  
  y: '',  
  // 是否可缩放  
  resizable: true,  
  // 是否可最小化  
  minimizable: true,  
  // 是否可最大化  
  maximizable: true,  
  // 是否可关闭  
  closable: true,  
  // 父窗口  
  parent: null,  
  // 是否模态窗口  
  modal: false,  
  // 窗口是否置顶  
  alwaysOnTop: false,  
  // 是否显示窗口边框(要创建无边框窗口,将frame参数设置为false)  
  frame: false,  
  // 是否透明窗口(仅frame: false有效)  
  transparent: false,  
  // 创建时是否显示窗口  
  show: false,  
}

electron-builder打包配置

{  
  "productName": "Electron-ViteChat",  
  "appId": "com.andy.electron-vite-wechat",  
  "copyright": "Copyright © 2024-present Andy  Q:282310962",  
  "compression": "maximum",  
  "asar": true,  
  "directories": {  
    "output": "release/${version}"  
  },  
  "nsis": {  
    "oneClick": false,  
    "allowToChangeInstallationDirectory": true,  
    "perMachine": true,  
    "deleteAppDataOnUninstall": true,  
    "createDesktopShortcut": true,  
    "createStartMenuShortcut": true,  
    "shortcutName": "ElectronViteChat"  
  },  
  "win": {  
    "icon": "./resources/shortcut.ico",  
    "artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}",  
    "target": [  
      {  
        "target": "nsis",  
        "arch": ["ia32"]  
      }  
    ]  
  },  
  "mac": {  
    "icon": "./resources/shortcut.icns",  
    "artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}"  
  },  
  "linux": {  
    "icon": "./resources",  
    "artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}"  
  }  
}

综上就是vue3+vite5+electron31实战开发仿微信客户端聊天的一些知识分享,希望对大家有些帮助~

作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045042968
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

收起阅读 »

【公告】DCloud发票系统升级

发票

自2024年8月15日起,DCloud将升级开票系统,升级后系统开票规则如下:

  1. 发票抬头须与账号实名认证主体一致,实名认证主体为 A 公司的账号,不可以申请开具 B 公司的发票。

  2. 个人作为应用协作者,为应用属主代为下单“云打包、插件购买、uni安全”业务,且应用属主账号已完成企业实名认证,则个人可选择相应订单开具应用属主的实名认证企业抬头发票;否则,个人认证账号仅能开具个人发票,不可开具公司发票;如您需要开具企业发票,您可前往账号中心完成企业实名认证升级后再申请开票,详见实名认证变更流程

继续阅读 »

自2024年8月15日起,DCloud将升级开票系统,升级后系统开票规则如下:

  1. 发票抬头须与账号实名认证主体一致,实名认证主体为 A 公司的账号,不可以申请开具 B 公司的发票。

  2. 个人作为应用协作者,为应用属主代为下单“云打包、插件购买、uni安全”业务,且应用属主账号已完成企业实名认证,则个人可选择相应订单开具应用属主的实名认证企业抬头发票;否则,个人认证账号仅能开具个人发票,不可开具公司发票;如您需要开具企业发票,您可前往账号中心完成企业实名认证升级后再申请开票,详见实名认证变更流程

收起阅读 »

Windows在符号链接的文件夹下创建项目导致运行报错,关键字:keepAliveInclude,Unknown custom element,'id' of undefined

创建项目为官方提供的Demo

可能出现的bug如下

Web运行:

index.js:1127 Uncaught   
ReferenceError: uni is not defined
Property or method "keepAliveInclude" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.  

Unknown custom element: <App> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

微信小程序运行:

ERROR TypeError: Cannot read property 'id' of undefined

如遇到上述错误提示信息,请检查项目路径是否包含符号链接文件夹,如果有该情况或类似情况,可将项目移动至无符号链接的文件夹中,可正常运行

继续阅读 »

创建项目为官方提供的Demo

可能出现的bug如下

Web运行:

index.js:1127 Uncaught   
ReferenceError: uni is not defined
Property or method "keepAliveInclude" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.  

Unknown custom element: <App> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

微信小程序运行:

ERROR TypeError: Cannot read property 'id' of undefined

如遇到上述错误提示信息,请检查项目路径是否包含符号链接文件夹,如果有该情况或类似情况,可将项目移动至无符号链接的文件夹中,可正常运行

收起阅读 »

HBuilder X 编辑器体验极差的一个地方

HBuilderX

作为新手,刚用这个 IDE,经常找不到打开项目的入口。后来我找到原因了:如果我不小心收起了侧边栏,下次打开 HBuilder 后,界面如下:

然后,我会尝试重新打开项目,但编辑器会提示

让人百思不得其解(如果此时自动显示侧边框也可以啊)。

最后我在【视图--显示项目管理器等左侧视图】菜单下,找到了恢复侧边框的办法。

好家伙,原来项目是已打开的,只是我不知道还原侧边栏导致。HBuilder X 界面的设计非常不人性化,它那个侧边栏的指示「箭头」默认会自动隐藏,只有你把鼠标移到相应位置,再点击一个,才会显示出来。


熟练之后,我把快捷键记下来了,下次按 cmd+b 就能直接开关侧边栏了,好像体验也没什么问题? 但对于新手,还是要摸索一下的,给人不是很顺手的感觉。

还有很多小点,总感觉这个编辑器是个半成品。

吐槽完了,仅代表个人体验~

继续阅读 »

作为新手,刚用这个 IDE,经常找不到打开项目的入口。后来我找到原因了:如果我不小心收起了侧边栏,下次打开 HBuilder 后,界面如下:

然后,我会尝试重新打开项目,但编辑器会提示

让人百思不得其解(如果此时自动显示侧边框也可以啊)。

最后我在【视图--显示项目管理器等左侧视图】菜单下,找到了恢复侧边框的办法。

好家伙,原来项目是已打开的,只是我不知道还原侧边栏导致。HBuilder X 界面的设计非常不人性化,它那个侧边栏的指示「箭头」默认会自动隐藏,只有你把鼠标移到相应位置,再点击一个,才会显示出来。


熟练之后,我把快捷键记下来了,下次按 cmd+b 就能直接开关侧边栏了,好像体验也没什么问题? 但对于新手,还是要摸索一下的,给人不是很顺手的感觉。

还有很多小点,总感觉这个编辑器是个半成品。

吐槽完了,仅代表个人体验~

收起阅读 »

UID短信无法登录问题,短信验证无法登录问题。

uid 登录 短信验证码

相信很多朋友在建立项目是碰见了这个问题:使用uid短信登陆,一切都弄好了,但是一运行就出现;

未找到scene=login-by-sms,的短信模版templateId。\n已启动测试模式,直接使用:123456作为短信验证码即可。\n如果是正式项目,请在路径:/common/uni-config-center/uni-id/config.json中service->sms中配置密钥等信息,

最后我试了很多遍,发现问题在这里;
官方在指引文件中给的方法是在UID的设置文件config中,选择填写
"service": {
"sms": {
"name": "模板名称",
"codeExpiresIn": 180,
"scene": {

            "bind-mobile-by-sms": {  
                "templateId": "模板ID",  
                "codeExpiresIn": 240  
            }  
        }  
    }  

}
但其实scene是场景的意思,也就是说,SMS应用场景有可能不止一个,而其中的bind-mobile-by-sms意思是指通过短信绑定手机号,并不是我们要的短信登陆,所以才导致我们填写完了相关信息却在登陆环节一直没有识别,导致出现未找到登陆对应的场景。以下借用其他朋友的编码解决该问题。

"service": {
"sms": {
"name": 模板名称",
"codeExpiresIn": 180,
"scene": {
"login-by-sms": {
"templateId": "模板id",
"codeExpiresIn": 240
},

            "bind-mobile-by-sms": {  
                "templateId": "模板id",  
                "codeExpiresIn": 240  
            },  
            "reset-pwd-by-sms": {  
                "templateId": "模板id",  
                "codeExpiresIn": 240  
            }  
        }  
    },  
    "univerify": {  
        "appid": ""  
    }  
}  

}
这样我们就在一个短信模板下加了三个场景,分别是登陆,绑定,重置密码。如果需要使用不同ID的短息模板的话,去自己服务器相关页面设置就好。
亲测有效。

继续阅读 »

相信很多朋友在建立项目是碰见了这个问题:使用uid短信登陆,一切都弄好了,但是一运行就出现;

未找到scene=login-by-sms,的短信模版templateId。\n已启动测试模式,直接使用:123456作为短信验证码即可。\n如果是正式项目,请在路径:/common/uni-config-center/uni-id/config.json中service->sms中配置密钥等信息,

最后我试了很多遍,发现问题在这里;
官方在指引文件中给的方法是在UID的设置文件config中,选择填写
"service": {
"sms": {
"name": "模板名称",
"codeExpiresIn": 180,
"scene": {

            "bind-mobile-by-sms": {  
                "templateId": "模板ID",  
                "codeExpiresIn": 240  
            }  
        }  
    }  

}
但其实scene是场景的意思,也就是说,SMS应用场景有可能不止一个,而其中的bind-mobile-by-sms意思是指通过短信绑定手机号,并不是我们要的短信登陆,所以才导致我们填写完了相关信息却在登陆环节一直没有识别,导致出现未找到登陆对应的场景。以下借用其他朋友的编码解决该问题。

"service": {
"sms": {
"name": 模板名称",
"codeExpiresIn": 180,
"scene": {
"login-by-sms": {
"templateId": "模板id",
"codeExpiresIn": 240
},

            "bind-mobile-by-sms": {  
                "templateId": "模板id",  
                "codeExpiresIn": 240  
            },  
            "reset-pwd-by-sms": {  
                "templateId": "模板id",  
                "codeExpiresIn": 240  
            }  
        }  
    },  
    "univerify": {  
        "appid": ""  
    }  
}  

}
这样我们就在一个短信模板下加了三个场景,分别是登陆,绑定,重置密码。如果需要使用不同ID的短息模板的话,去自己服务器相关页面设置就好。
亲测有效。

收起阅读 »

ios应用的测试方法-testflight

测试

ios的应用开发好后,让开发人员测试有两种方法:

1、上传到app stoe,然后测试人员的手机安装testflight,通过testflight去测试
2、创建ad hoc格式的证书和证书profile文件(描述文件),然后将测试者的手机的udid添加到profile文件,通过这种证书打包的应用打好ipa包后,可以不上架,可以上传到香蕉云编或蒲公英等内测平台生成安装二维码,扫码安装。

这里我们重点讲述第一种,通过testflight的方法

1、首选,在app store创建好app,创建app的时候,选择的套装ID(bundle ID)要跟我们在uniapp里打包的appId(包名)一致, 如下图,假如已经创建好app就可以跳过这个步骤:

2、创建好app后,可以看看有一个testflight的目录

这里的testflight需要mac的xcode等上传工具上传上来,假如没有mac电脑,可以使用香蕉云编来上传:

https://www.yunedit.com/ipasend

3、然后就是需要邀请用户进来测试,进入用户和访问模块,点蓝色加号添加测试人员的appleid进来:

4、然后测试人员在测试手机安装testflight软件,使用testflight安装刚上传的构建版本,就可以测试了。

5、在testflight的测试员界面,也可以清楚的看到谁安装了

继续阅读 »

ios的应用开发好后,让开发人员测试有两种方法:

1、上传到app stoe,然后测试人员的手机安装testflight,通过testflight去测试
2、创建ad hoc格式的证书和证书profile文件(描述文件),然后将测试者的手机的udid添加到profile文件,通过这种证书打包的应用打好ipa包后,可以不上架,可以上传到香蕉云编或蒲公英等内测平台生成安装二维码,扫码安装。

这里我们重点讲述第一种,通过testflight的方法

1、首选,在app store创建好app,创建app的时候,选择的套装ID(bundle ID)要跟我们在uniapp里打包的appId(包名)一致, 如下图,假如已经创建好app就可以跳过这个步骤:

2、创建好app后,可以看看有一个testflight的目录

这里的testflight需要mac的xcode等上传工具上传上来,假如没有mac电脑,可以使用香蕉云编来上传:

https://www.yunedit.com/ipasend

3、然后就是需要邀请用户进来测试,进入用户和访问模块,点蓝色加号添加测试人员的appleid进来:

4、然后测试人员在测试手机安装testflight软件,使用testflight安装刚上传的构建版本,就可以测试了。

5、在testflight的测试员界面,也可以清楚的看到谁安装了

收起阅读 »

这玩意bug 是真的多呀

bug反馈

这玩意bug 是真的多呀

这玩意bug 是真的多呀

uniapp 拉起Google地图导航

网上搜索到的案例太少了,要么就是调起后不显示定位点,要么就是会自动搜索传入的地点名字然后瞎跳转

最后在stackoverflow上找到了一段代码,安卓原生的想着拿过来也应该也可以用,没想到还真行,直接上代码吧:

传参方式

url = `geo:0,0?q=${lat},${lng} (${address})`

调这个URL就行了

plus.runtime.openURL( url, function( e ) {    
    plus.nativeUI.alert("本机未安装指定的地图应用");    
});  

详情见原文链接
Google地图 Intent调用

继续阅读 »

网上搜索到的案例太少了,要么就是调起后不显示定位点,要么就是会自动搜索传入的地点名字然后瞎跳转

最后在stackoverflow上找到了一段代码,安卓原生的想着拿过来也应该也可以用,没想到还真行,直接上代码吧:

传参方式

url = `geo:0,0?q=${lat},${lng} (${address})`

调这个URL就行了

plus.runtime.openURL( url, function( e ) {    
    plus.nativeUI.alert("本机未安装指定的地图应用");    
});  

详情见原文链接
Google地图 Intent调用

收起阅读 »