
【解决】使用yz-qr生成二维码,canvas有时候会空白问题
// 在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+electron31.x+vite5+pinia2+element-plus仿微信电脑版聊天室Exe程序。整个聊天程序界面清爽简约,支持展示/收缩侧边栏、electron新开多窗口、换肤等功能。
electron31+vite5+vue3+elementPlus仿微信客户端聊天exe程序ElectronViteChat
vue3-electron-wechat使用vite5.x构建工具搭建项目模板,采用vue3 setup语法开发,融合electron跨平台技术。
实现技术
- 编码工具: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
前段时间有分享一篇vue3+vite5网页版聊天室,感兴趣的可以去看看。
https://ask.dcloud.net.cn/article/41153
项目结构
vite-electronChat聊天已经同步到我的最新原创作品集,有需要的可以去看看。
https://gf.bilibili.com/item/detail/1106312011
入口配置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')
})
electron主进程
/**
* 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()
})
项目布局模板
<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多窗口|新开窗口
/**
* 创建新窗口
* @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
vue3-electron-wechat使用vite5.x构建工具搭建项目模板,采用vue3 setup语法开发,融合electron跨平台技术。
实现技术
- 编码工具: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
前段时间有分享一篇vue3+vite5网页版聊天室,感兴趣的可以去看看。
https://ask.dcloud.net.cn/article/41153
项目结构
vite-electronChat聊天已经同步到我的最新原创作品集,有需要的可以去看看。
https://gf.bilibili.com/item/detail/1106312011
入口配置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')
})
electron主进程
/**
* 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()
})
项目布局模板
<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多窗口|新开窗口
/**
* 创建新窗口
* @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发票系统升级

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 编辑器体验极差的一个地方
作为新手,刚用这个 IDE,经常找不到打开项目的入口。后来我找到原因了:如果我不小心收起了侧边栏,下次打开 HBuilder 后,界面如下:

然后,我会尝试重新打开项目,但编辑器会提示
让人百思不得其解(如果此时自动显示侧边框也可以啊)。
最后我在【视图--显示项目管理器等左侧视图】菜单下,找到了恢复侧边框的办法。
好家伙,原来项目是已打开的,只是我不知道还原侧边栏导致。HBuilder X 界面的设计非常不人性化,它那个侧边栏的指示「箭头」默认会自动隐藏,只有你把鼠标移到相应位置,再点击一个,才会显示出来。
熟练之后,我把快捷键记下来了,下次按 cmd+b 就能直接开关侧边栏了,好像体验也没什么问题? 但对于新手,还是要摸索一下的,给人不是很顺手的感觉。
还有很多小点,总感觉这个编辑器是个半成品。
吐槽完了,仅代表个人体验~
作为新手,刚用这个 IDE,经常找不到打开项目的入口。后来我找到原因了:如果我不小心收起了侧边栏,下次打开 HBuilder 后,界面如下:
然后,我会尝试重新打开项目,但编辑器会提示
让人百思不得其解(如果此时自动显示侧边框也可以啊)。
最后我在【视图--显示项目管理器等左侧视图】菜单下,找到了恢复侧边框的办法。
好家伙,原来项目是已打开的,只是我不知道还原侧边栏导致。HBuilder X 界面的设计非常不人性化,它那个侧边栏的指示「箭头」默认会自动隐藏,只有你把鼠标移到相应位置,再点击一个,才会显示出来。
熟练之后,我把快捷键记下来了,下次按 cmd+b 就能直接开关侧边栏了,好像体验也没什么问题? 但对于新手,还是要摸索一下的,给人不是很顺手的感觉。
还有很多小点,总感觉这个编辑器是个半成品。
吐槽完了,仅代表个人体验~
收起阅读 »
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的测试员界面,也可以清楚的看到谁安装了
收起阅读 »
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调用

全栈定制开发
全栈定制开发
1,各平台小程序开发
2,app(android,ios) 技术栈 uni-app x 获原生开发
3,工厂数字化升级, mes方向;集成各厂商PLC,及数字孪生;
4,企业级门户网站
5,ai 行业助手定制;
有意站内私信 或:
电话:15210908900
邮箱:279955152@qq.com
全栈定制开发
1,各平台小程序开发
2,app(android,ios) 技术栈 uni-app x 获原生开发
3,工厂数字化升级, mes方向;集成各厂商PLC,及数字孪生;
4,企业级门户网站
5,ai 行业助手定制;
有意站内私信 或:
电话:15210908900
邮箱:279955152@qq.com

安卓app蓝牙打印票据(二维码)完整代码(vue2)
蓝牙搜索用的uni-app的低功耗蓝牙的方法,连接和打印用的安卓原生的方法,连接蓝牙会出现连接不成功的问题(或者连接成功但是连接状态是false)需要额外处理
<!-- 蓝牙打印页面 -->
<template>
<view style="height: 100vh; display: flex; flex-direction: column">
<view style="flex: 1; overflow-y: auto; padding-bottom: 20rpx">
<button
class="button"
hover-class="hover"
@click="startSearch"
:loading="isScanning"
>
搜索蓝牙设备
</button>
<text class="td">(Android8.0+系统需开启定位)</text>
<view v-if="list.length > 0" style="text-align: center">
<view style="font-size: 18px">蓝牙设备列表</view>
<view style="color: #666; font-size: 10px">点击连接蓝牙设备</view>
</view>
<view v-if="deviceinfo.deviceId" class="linkcss"
>蓝牙设备已连接:{{ deviceinfo.name }}</view
>
<scroll-view class="device_list" scroll-y scroll-with-animation>
<view
:class="item.deviceId === deviceinfo.deviceId ? 'sign_step' : ''"
v-for="item in list"
:data-title="item.deviceId"
:data-name="item.name"
:data-advertisData="item.advertisServiceUUIDs"
:key="item.deviceId"
@click="bindViewTap(item)"
class="item"
hover-class="item_hover"
>
<view>
<view style="font-size: 16px">{{ item.name }}</view>
<view style="font-size: 12px">{{ item.deviceId }}</view>
<view style="font-size: 10px; color: #666"
>信号强度: {{ item.RSSI }}dBm
</view>
</view>
</view>
</scroll-view>
</view>
<view class="btncss">
<u-button
:disabled="!deviceinfo.deviceId"
:custom-style="{ width: '200rpx' }"
type="primary"
@click="submitPrinte"
>打 印</u-button
>
</view>
</view>
</template>
<script>
function printAlignment(writer, align) {
// 对齐方式,0:左,1:中,2:右
writer.write(0x1b);
writer.write(0x61);
writer.write(align);
writer.write(0x1b);
writer.write(0x45);
writer.write(0x00);
}
function printFontsize(writer, size) {
// 字体大小
writer.write(0x1b);
writer.write(0x21);
writer.write(size);
writer.write(0x1b);
writer.write(0x45);
writer.write(0x00);
}
export default {
data() {
return {
list: [],
isScanning: false,
BLEInformation: {},
};
},
computed: {
deviceinfo() {
return this.BLEInformation;
},
},
methods: {
submitPrinte() {
console.log("进入打印方法中");
const that = this;
var main = plus.android.runtimeMainActivity();
var BluetoothAdapter = plus.android.importClass(
"android.bluetooth.BluetoothAdapter"
);
var UUID = plus.android.importClass("java.util.UUID");
var uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
var BAdapter = BluetoothAdapter.getDefaultAdapter();
var device = BAdapter.getRemoteDevice(that.BLEInformation.deviceId);
plus.android.importClass(device);
var bluetoothSocket =
device.createInsecureRfcommSocketToServiceRecord(uuid);
plus.android.importClass(bluetoothSocket);
if (!bluetoothSocket.isConnected()) {
console.log("检测到设备未连接,尝试连接....");
bluetoothSocket.connect();
}
console.log(bluetoothSocket.isConnected());
var outputStream = bluetoothSocket.getOutputStream();
plus.android.importClass(outputStream);
const OutputStreamWriter = plus.android.importClass(
"java.io.OutputStreamWriter"
);
const writer = new OutputStreamWriter(outputStream, "GBK");
plus.android.importClass(writer);
writer.write("\r\n"); //打印空行并换行
writer.write("\r\n"); //打印空行并换行
//标题
writer.write("标题:打印测试\r\n");
printFontsize(writer, 14); // 设置字体14
printAlignment(writer, 1); // 设置居中
writer.write("打印居中14号字体\r\n");
printFontsize(writer, 16); // 设置字体14
printAlignment(writer, 0); // 设置居中
writer.write("打印居左16号字体\r\n");
printAlignment(writer, 2); // 设置居中
writer.write("打印居右16号字体\r\n");
writer.write("\r\n"); //打印空行并换行
// 二维码打印——start
const qrcode = "二维码内容放在这里了";
var moduleSize = 8;
var qrcodebytes = plus.android.invoke(qrcode, "getBytes", "gbk");
var length = qrcodebytes.length;
writer.write(0x1b);
writer.write(0x40);
writer.flush();
printAlignment(writer, 1);
// 缓存二维码数据
writer.write(0x1d); // init
writer.write("(k"); // adjust height of barcode
writer.write(length + 3); // pl
writer.write(0); // ph
writer.write(49); // cn
writer.write(80); // fn
writer.write(48); //
writer.write(qrcode);
// 二维码纠错等级
writer.write(0x1d);
writer.write("(k");
writer.write(3);
writer.write(0);
writer.write(49);
writer.write(69);
writer.write(48);
// 设置二维码块大小
writer.write(0x1d);
writer.write("(k");
writer.write(3);
writer.write(0);
writer.write(49);
writer.write(67);
writer.write(moduleSize);
// 打印已缓存的数据二维码
writer.write(0x1d);
writer.write("(k");
writer.write(3); // pl
writer.write(0); // ph
writer.write(49); // cn
writer.write(81); // fn
writer.write(48); // m
writer.flush();
writer.write(0x1b);
writer.write(0x64);
writer.write(2); // 行数
writer.flush();
// 二维码打印——end
writer.flush();
// device = null; //这里关键
// bluetoothSocket.close(); //必须关闭蓝牙连接否则意外断开的话打印错误
},
startSearch() {
var that = this;
uni.openBluetoothAdapter({
success: function (res) {
uni.getBluetoothAdapterState({
success: function (res) {
console.log("openBluetoothAdapter success", res);
if (res.available) {
if (res.discovering) {
} else {
that.getBluetoothDevices();
}
} else {
uni.showModal({
title: "提示",
content: "本机蓝牙不可用",
showCancel: false,
});
}
},
});
},
fail: function (res) {
console.log(res);
uni.showModal({
title: "提示",
content: "蓝牙初始化失败,请到设置打开蓝牙",
showCancel: false,
});
},
});
},
getBluetoothDevices() {
var that = this;
uni.showLoading({
title: "正在搜索",
icon: "loading",
});
that.isScanning = true;
uni.startBluetoothDevicesDiscovery({
success: function (res) {
console.log(res);
setTimeout(function () {
// 不设置延迟获取的servers为空数组
uni.getBluetoothDevices({
success: function (res) {
var devices = [];
var num = 0;
for (var i = 0; i < res.devices.length; ++i) {
if (
res.devices[i].name != "未知设备"
) {
devices[num] = res.devices[i];
num++;
}
}
that.list = devices;
that.isScanning = false;
uni.hideLoading();
uni.stopPullDownRefresh();
uni.stopBluetoothDevicesDiscovery({
success: function (res) {
console.log("停止搜索蓝牙");
that.isScanning = false;
uni.hideLoading();
},
});
},
});
}, 5000);
},
});
},
bindViewTap(item) {
var that = this;
uni.showLoading({
title: "正在连接",
});
var main = plus.android.runtimeMainActivity();
var BluetoothAdapter = plus.android.importClass(
"android.bluetooth.BluetoothAdapter"
);
var UUID = plus.android.importClass("java.util.UUID");
var uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
var BAdapter = BluetoothAdapter.getDefaultAdapter();
var device = BAdapter.getRemoteDevice(item.deviceId);
plus.android.importClass(device);
var bluetoothSocket =
device.createInsecureRfcommSocketToServiceRecord(uuid);
plus.android.importClass(bluetoothSocket);
bluetoothSocket.connect();
console.log("连接:", bluetoothSocket.isConnected());
if (bluetoothSocket.isConnected()) {
that.openControl();
that.BLEInformation.deviceId = item.deviceId;
that.BLEInformation.name = item.name;
that.$forceUpdate();
console.log("that.BLEInformation:", that.BLEInformation);
}
},
openControl() {
// 连接成功后打印
uni.hideLoading();
const that = this;
uni.showModal({
title: "提示",
content: "蓝牙设备连接成功,是否确认打印",
success(res) {
if (res.confirm) {
that.submitPrinte();
}
},
});
},
},
};
</script>
<style scoped lang="scss">
.btncss {
background-color: white;
padding-inline: 20rpx;
width: 100%;
padding-top: 30rpx;
padding-bottom: 50rpx;
box-shadow: 2px 2px 4px 4px rgba(223, 223, 223, 0.5);
z-index: 9999;
}
.linkcss {
border: 2px solid #54bec2;
padding: 10px;
margin: 10px;
}
.button {
margin-top: 20px;
margin-bottom: 20px;
width: 70%;
background-color: #54bec2;
color: white;
border-radius: 98rpx;
background: bg_red;
}
/* 按下变颜色 */
.hover {
background: #dcdcdc;
}
.device_list {
height: auto;
margin-left: 20rpx;
margin-right: 20rpx;
margin-top: 10px;
margin-bottom: 20px;
/* border: 1px solid #EEE; */
width: auto;
}
.td {
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.item {
display: block;
background-color: white;
border-radius: 18rpx;
margin-bottom: 16rpx;
padding: 8px;
}
.item_hover {
background-color: rgba(0, 0, 0, 0.1);
}
.block {
display: block;
color: #ffffff;
padding: 5px;
}
.button::after {
border-width: 0px;
}
.sign_step > view::after {
// 对钩的三角行底色
position: absolute;
right: 0;
top: 0;
width: 0;
height: 0;
content: "";
border: 16px solid;
border-color: #70cad3 #70cad3 transparent transparent;
border-bottom-right-radius: 2px;
}
.sign_step {
position: relative;
border: 2px solid #54bec2;
}
.sign_step > view::before {
// 对钩样式
position: absolute;
right: 2px;
top: 4px;
z-index: 1;
width: 10px;
height: 5px;
content: "";
background: transparent;
border: 2px solid white;
border-top: none;
border-right: none;
-webkit-transform: rotate(-55deg);
-ms-transform: rotate(-55deg);
transform: rotate(-55deg);
}
</style>
蓝牙搜索用的uni-app的低功耗蓝牙的方法,连接和打印用的安卓原生的方法,连接蓝牙会出现连接不成功的问题(或者连接成功但是连接状态是false)需要额外处理
<!-- 蓝牙打印页面 -->
<template>
<view style="height: 100vh; display: flex; flex-direction: column">
<view style="flex: 1; overflow-y: auto; padding-bottom: 20rpx">
<button
class="button"
hover-class="hover"
@click="startSearch"
:loading="isScanning"
>
搜索蓝牙设备
</button>
<text class="td">(Android8.0+系统需开启定位)</text>
<view v-if="list.length > 0" style="text-align: center">
<view style="font-size: 18px">蓝牙设备列表</view>
<view style="color: #666; font-size: 10px">点击连接蓝牙设备</view>
</view>
<view v-if="deviceinfo.deviceId" class="linkcss"
>蓝牙设备已连接:{{ deviceinfo.name }}</view
>
<scroll-view class="device_list" scroll-y scroll-with-animation>
<view
:class="item.deviceId === deviceinfo.deviceId ? 'sign_step' : ''"
v-for="item in list"
:data-title="item.deviceId"
:data-name="item.name"
:data-advertisData="item.advertisServiceUUIDs"
:key="item.deviceId"
@click="bindViewTap(item)"
class="item"
hover-class="item_hover"
>
<view>
<view style="font-size: 16px">{{ item.name }}</view>
<view style="font-size: 12px">{{ item.deviceId }}</view>
<view style="font-size: 10px; color: #666"
>信号强度: {{ item.RSSI }}dBm
</view>
</view>
</view>
</scroll-view>
</view>
<view class="btncss">
<u-button
:disabled="!deviceinfo.deviceId"
:custom-style="{ width: '200rpx' }"
type="primary"
@click="submitPrinte"
>打 印</u-button
>
</view>
</view>
</template>
<script>
function printAlignment(writer, align) {
// 对齐方式,0:左,1:中,2:右
writer.write(0x1b);
writer.write(0x61);
writer.write(align);
writer.write(0x1b);
writer.write(0x45);
writer.write(0x00);
}
function printFontsize(writer, size) {
// 字体大小
writer.write(0x1b);
writer.write(0x21);
writer.write(size);
writer.write(0x1b);
writer.write(0x45);
writer.write(0x00);
}
export default {
data() {
return {
list: [],
isScanning: false,
BLEInformation: {},
};
},
computed: {
deviceinfo() {
return this.BLEInformation;
},
},
methods: {
submitPrinte() {
console.log("进入打印方法中");
const that = this;
var main = plus.android.runtimeMainActivity();
var BluetoothAdapter = plus.android.importClass(
"android.bluetooth.BluetoothAdapter"
);
var UUID = plus.android.importClass("java.util.UUID");
var uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
var BAdapter = BluetoothAdapter.getDefaultAdapter();
var device = BAdapter.getRemoteDevice(that.BLEInformation.deviceId);
plus.android.importClass(device);
var bluetoothSocket =
device.createInsecureRfcommSocketToServiceRecord(uuid);
plus.android.importClass(bluetoothSocket);
if (!bluetoothSocket.isConnected()) {
console.log("检测到设备未连接,尝试连接....");
bluetoothSocket.connect();
}
console.log(bluetoothSocket.isConnected());
var outputStream = bluetoothSocket.getOutputStream();
plus.android.importClass(outputStream);
const OutputStreamWriter = plus.android.importClass(
"java.io.OutputStreamWriter"
);
const writer = new OutputStreamWriter(outputStream, "GBK");
plus.android.importClass(writer);
writer.write("\r\n"); //打印空行并换行
writer.write("\r\n"); //打印空行并换行
//标题
writer.write("标题:打印测试\r\n");
printFontsize(writer, 14); // 设置字体14
printAlignment(writer, 1); // 设置居中
writer.write("打印居中14号字体\r\n");
printFontsize(writer, 16); // 设置字体14
printAlignment(writer, 0); // 设置居中
writer.write("打印居左16号字体\r\n");
printAlignment(writer, 2); // 设置居中
writer.write("打印居右16号字体\r\n");
writer.write("\r\n"); //打印空行并换行
// 二维码打印——start
const qrcode = "二维码内容放在这里了";
var moduleSize = 8;
var qrcodebytes = plus.android.invoke(qrcode, "getBytes", "gbk");
var length = qrcodebytes.length;
writer.write(0x1b);
writer.write(0x40);
writer.flush();
printAlignment(writer, 1);
// 缓存二维码数据
writer.write(0x1d); // init
writer.write("(k"); // adjust height of barcode
writer.write(length + 3); // pl
writer.write(0); // ph
writer.write(49); // cn
writer.write(80); // fn
writer.write(48); //
writer.write(qrcode);
// 二维码纠错等级
writer.write(0x1d);
writer.write("(k");
writer.write(3);
writer.write(0);
writer.write(49);
writer.write(69);
writer.write(48);
// 设置二维码块大小
writer.write(0x1d);
writer.write("(k");
writer.write(3);
writer.write(0);
writer.write(49);
writer.write(67);
writer.write(moduleSize);
// 打印已缓存的数据二维码
writer.write(0x1d);
writer.write("(k");
writer.write(3); // pl
writer.write(0); // ph
writer.write(49); // cn
writer.write(81); // fn
writer.write(48); // m
writer.flush();
writer.write(0x1b);
writer.write(0x64);
writer.write(2); // 行数
writer.flush();
// 二维码打印——end
writer.flush();
// device = null; //这里关键
// bluetoothSocket.close(); //必须关闭蓝牙连接否则意外断开的话打印错误
},
startSearch() {
var that = this;
uni.openBluetoothAdapter({
success: function (res) {
uni.getBluetoothAdapterState({
success: function (res) {
console.log("openBluetoothAdapter success", res);
if (res.available) {
if (res.discovering) {
} else {
that.getBluetoothDevices();
}
} else {
uni.showModal({
title: "提示",
content: "本机蓝牙不可用",
showCancel: false,
});
}
},
});
},
fail: function (res) {
console.log(res);
uni.showModal({
title: "提示",
content: "蓝牙初始化失败,请到设置打开蓝牙",
showCancel: false,
});
},
});
},
getBluetoothDevices() {
var that = this;
uni.showLoading({
title: "正在搜索",
icon: "loading",
});
that.isScanning = true;
uni.startBluetoothDevicesDiscovery({
success: function (res) {
console.log(res);
setTimeout(function () {
// 不设置延迟获取的servers为空数组
uni.getBluetoothDevices({
success: function (res) {
var devices = [];
var num = 0;
for (var i = 0; i < res.devices.length; ++i) {
if (
res.devices[i].name != "未知设备"
) {
devices[num] = res.devices[i];
num++;
}
}
that.list = devices;
that.isScanning = false;
uni.hideLoading();
uni.stopPullDownRefresh();
uni.stopBluetoothDevicesDiscovery({
success: function (res) {
console.log("停止搜索蓝牙");
that.isScanning = false;
uni.hideLoading();
},
});
},
});
}, 5000);
},
});
},
bindViewTap(item) {
var that = this;
uni.showLoading({
title: "正在连接",
});
var main = plus.android.runtimeMainActivity();
var BluetoothAdapter = plus.android.importClass(
"android.bluetooth.BluetoothAdapter"
);
var UUID = plus.android.importClass("java.util.UUID");
var uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
var BAdapter = BluetoothAdapter.getDefaultAdapter();
var device = BAdapter.getRemoteDevice(item.deviceId);
plus.android.importClass(device);
var bluetoothSocket =
device.createInsecureRfcommSocketToServiceRecord(uuid);
plus.android.importClass(bluetoothSocket);
bluetoothSocket.connect();
console.log("连接:", bluetoothSocket.isConnected());
if (bluetoothSocket.isConnected()) {
that.openControl();
that.BLEInformation.deviceId = item.deviceId;
that.BLEInformation.name = item.name;
that.$forceUpdate();
console.log("that.BLEInformation:", that.BLEInformation);
}
},
openControl() {
// 连接成功后打印
uni.hideLoading();
const that = this;
uni.showModal({
title: "提示",
content: "蓝牙设备连接成功,是否确认打印",
success(res) {
if (res.confirm) {
that.submitPrinte();
}
},
});
},
},
};
</script>
<style scoped lang="scss">
.btncss {
background-color: white;
padding-inline: 20rpx;
width: 100%;
padding-top: 30rpx;
padding-bottom: 50rpx;
box-shadow: 2px 2px 4px 4px rgba(223, 223, 223, 0.5);
z-index: 9999;
}
.linkcss {
border: 2px solid #54bec2;
padding: 10px;
margin: 10px;
}
.button {
margin-top: 20px;
margin-bottom: 20px;
width: 70%;
background-color: #54bec2;
color: white;
border-radius: 98rpx;
background: bg_red;
}
/* 按下变颜色 */
.hover {
background: #dcdcdc;
}
.device_list {
height: auto;
margin-left: 20rpx;
margin-right: 20rpx;
margin-top: 10px;
margin-bottom: 20px;
/* border: 1px solid #EEE; */
width: auto;
}
.td {
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.item {
display: block;
background-color: white;
border-radius: 18rpx;
margin-bottom: 16rpx;
padding: 8px;
}
.item_hover {
background-color: rgba(0, 0, 0, 0.1);
}
.block {
display: block;
color: #ffffff;
padding: 5px;
}
.button::after {
border-width: 0px;
}
.sign_step > view::after {
// 对钩的三角行底色
position: absolute;
right: 0;
top: 0;
width: 0;
height: 0;
content: "";
border: 16px solid;
border-color: #70cad3 #70cad3 transparent transparent;
border-bottom-right-radius: 2px;
}
.sign_step {
position: relative;
border: 2px solid #54bec2;
}
.sign_step > view::before {
// 对钩样式
position: absolute;
right: 2px;
top: 4px;
z-index: 1;
width: 10px;
height: 5px;
content: "";
background: transparent;
border: 2px solid white;
border-top: none;
border-right: none;
-webkit-transform: rotate(-55deg);
-ms-transform: rotate(-55deg);
transform: rotate(-55deg);
}
</style>
收起阅读 »

uni-app使用经典蓝牙串口通信方案
data() {
return {
bluetooth: 1, //1:打开蓝牙 2:关闭蓝牙
turnOnBluetooth: "打开蓝牙", //打开蓝牙
turnOffBluetooth: "关闭蓝牙", //关闭蓝牙
backgroundColor: "#cecece", //搜索蓝牙按钮背景颜色
title: 'Hello',
searchLoadingTxt: '',
isBlueOk: false,
bluetimestoper: null,
startchecktimer: null,
timeoutOfBlueScanFailure30s: 300000,
baseList: [],
bluetoothIndex: [],
targetDeviceName: '',
_deviceId: '', //蓝牙deviceId
pairedList: [], //已配对蓝牙
pairedLists: [], //已配对蓝牙集合
pairedHeight: 0, //已配对蓝牙显示高度
unpairedList: [], //未配对蓝牙
unpairedHeight: 0, //未配对蓝牙显示高度
bluetoothSocket: {},
}
}
//删除已配对设备
removePaire(index) {
var that = this;
uni.showModal({
title: "提示",
content: "是否删除设备",
showCancel: true,
cancelText: "取消",
confirmText: "确定",
success(res) {
// 确定删除设备
if (res.confirm) {
var address = uni.getStorageSync("printerSelected").address;
console.log("已选中蓝牙地址:" + address + " 删除蓝牙地址:" + that.pairedList[index].address);
if (that.pairedList[index].address == address) {
// that.pairedList[0].isSelected=1;
uni.setStorageSync("printerSelected", "");
}
for (var i = 0; i < that.pairedLists.length; i++) {
if (that.pairedLists[i].getAddress() == that.pairedList[index].address) {
that.pairedLists[i].removeBond();
}
}
that.pairedList.splice(index, 1);
//存储打印机
// uni.setStorageSync("pairedList",that.pairedList);
} else {
console.log("取消删除设备");
}
}
})
return false;
},
//设置已选中蓝牙
setSelectedPaired(paired) {
console.log('paired', paired)
var that = this;
for (var i = 0; i < that.pairedList.length; i++) {
if (that.pairedList[i].address == paired.address) {
that.pairedList[i].isSelected = 1;
} else {
that.pairedList[i].isSelected = 0;
}
}
uni.showLoading({
title:'正在建立连接'
})
uni.navigateTo({
url:`detail?name=${paired.name}&address=${paired.address}`
})
paired.isSelected = 1;
//存储已选择打印机
uni.setStorageSync("printerSelected", paired);
//存储打印机
// uni.setStorageSync("pairedList",that.pairedList);
},
//判断蓝牙打开状态
bluetoothStatus() {
var that = this;
const BluetoothAdapter = plus.android.importClass('android.bluetooth.BluetoothAdapter'); // 引入Java 蓝牙类
const blueadapter = BluetoothAdapter.getDefaultAdapter(); //拿到默认蓝牙适配器方法
if (blueadapter) {
// 判断蓝牙是否开启
if (blueadapter.isEnabled()) {
// 开启
that.bluetooth = 0;
that.backgroundColor = "red";
var yilianjie = uni.getStorageSync("printerSelected");
var selectAddress = "";
if (yilianjie) {
selectAddress = yilianjie.address;
}
// console.log("已选中地址:"+selectAddress);
//获取手机已配对蓝牙
var lists = blueadapter.getBondedDevices();
plus.android.importClass(lists);
var iterator = lists.iterator();
plus.android.importClass(iterator);
while (iterator.hasNext()) {
var device = iterator.next();
that.pairedLists.push(device);
plus.android.importClass(device);
that.pairedList.push({
name: device.getName(),
address: device.getAddress(),
isSelected: selectAddress == device.getAddress() ? '1' : '0'
})
// console.log(device.getName()+" ########### "+ device.getAddress());
}
//显示存储的已配对蓝牙
// this.pairedList = uni.getStorageSync("pairedList");
} else {
// 关闭
this.bluetooth = 1;
this.backgroundColor = "#cecece";
this.pairedList = [];
}
this.unpairedList = [];
}
},
//打开蓝牙
openBluetooth() {
var that = this;
// 弹出提示框
uni.showModal({
title: "提示",
content: "蓝牙尚未打开,是否打开蓝牙",
showCancel: true,
cancelText: "取消",
confirmText: "确定",
success(res) {
// 点击确定后通过系统打开蓝牙
if (res.confirm) {
const BluetoothAdapter = plus.android.importClass(
'android.bluetooth.BluetoothAdapter'); // 引入Java 蓝牙类
const blueadapter = BluetoothAdapter.getDefaultAdapter();
if (blueadapter != null) {
that.bluetooth = 0;
that.backgroundColor = "#8A2BCF";
//显示存储的已配对蓝牙
// that.pairedList = uni.getStorageSync("pairedList");
blueadapter.enable();
setTimeout(function() {
that.bluetoothStatus();
}, 2000)
}
} else {
// 点击取消什么也不做
console.log("取消打开蓝牙");
}
}
})
},
//关闭蓝牙
closeBluetooth() {
var that = this;
// 弹出提示框
uni.showModal({
title: "提示",
content: "蓝牙已打开,是否关闭蓝牙",
showCancel: true,
cancelText: "取消",
confirmText: "确定",
success(res) {
// 点击确定后通过系统打开蓝牙
if (res.confirm) {
const BluetoothAdapter = plus.android.importClass(
'android.bluetooth.BluetoothAdapter'); // 引入Java 蓝牙类
const blueadapter = BluetoothAdapter.getDefaultAdapter();
if (blueadapter != null) {
that.bluetooth = 1;
that.backgroundColor = "#cecece";
that.pairedList = [];
that.unpairedList = [];
uni.setStorageSync("printerSelected", "");
return blueadapter.disable();
}
} else {
// 点击取消什么也不做
console.log("取消关闭蓝牙");
}
}
})
},
//点击打开/关闭蓝牙按钮
blueTooth() {
if (this.bluetooth == 1) {
console.log("打开蓝牙");
this.openBluetooth();
} else {
console.log("关闭蓝牙");
this.closeBluetooth();
}
},
//初始化蓝牙模块
openBluetoothAdapter() {
//未打开蓝牙点击搜索蓝牙提示弹窗
if (this.bluetooth == 1) {
uni.showToast({
title: "请先打开蓝牙",
icon: "error"
})
return;
}
let system = uni.getSystemInfoSync(); // 获取系统信息
if (system.platform === 'android') { // 判断平台
var that = this;
var context = plus.android.importClass("android.content.Context");
var locationManager = plus.android.importClass("android.location.LocationManager");
var main = plus.android.runtimeMainActivity();
var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
// 定位检测
if (!mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER)) {
uni.showModal({
title: "提示",
content: "请打开定位服务功能",
showCancel: false, // 不显示取消按钮
success() {
if (!mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER)) {
var Intent = plus.android.importClass('android.content.Intent');
var Settings = plus.android.importClass('android.provider.Settings');
var intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
main.startActivity(intent); // 打开系统设置GPS服务页面
} else {
console.log('GPS功能已开启');
}
}
});
return false
} else {
console.log('GPS功能已开启');
that.searchDevices()
return true
}
}
},
//搜索蓝牙
searchDevices() {
var that = this;
that.unpairedList = []; //未配对
// that.pairedList = []; //已配对
//取内存里面已配对的蓝牙
// that.pairedList = uni.getStorageSync("pairedList");
//打开蓝牙模块
uni.openBluetoothAdapter({
success(res) {
console.log("蓝牙模块:", res);
//获取本机蓝牙适配器状态
uni.getBluetoothAdapterState({
success: function(res) {
console.log("蓝牙适配器状态:", res);
if (res.available) {
//开始搜寻附近的蓝牙外围设备
uni.startBluetoothDevicesDiscovery({
success(res) {
var main = plus.android.runtimeMainActivity();
var IntentFilter = plus.android.importClass(
'android.content.IntentFilter');
var BluetoothAdapter = plus.android.importClass(
"android.bluetooth.BluetoothAdapter");
var BluetoothDevice = plus.android.importClass(
"android.bluetooth.BluetoothDevice");
var BAdapter = BluetoothAdapter
.getDefaultAdapter();
if (BAdapter != null && !BAdapter.isEnabled()) {
let _intent = plus.android.importClass(
'android.content.Intent');
let intent = new _intent(blue_client
.ACTION_REQUEST_ENABLE);
main.startActivityForResult(intent, 200);
}
uni.showLoading({
title: "开始搜索设备",
})
//获取本机蓝牙信息
// var name = BAdapter.getName();
// var address = BAdapter.getAddress();
// console.log("本机蓝牙名称:"+name+" 本机蓝牙地址:"+address);
var filter = new IntentFilter();
var bdevice = new BluetoothDevice();
BAdapter.startDiscovery(); //开启搜索
var receiver;
receiver = plus.android.implements(
'io.dcloud.android.content.BroadcastReceiver', {
onReceive: function(context,
intent) { //实现onReceiver回调函数
plus.android.importClass(
intent); //通过intent实例引入intent类,方便以后的‘.’操作
if (intent.getAction() ==
"android.bluetooth.adapter.action.DISCOVERY_FINISHED"
) {
main.unregisterReceiver(
receiver); //取消监听
console.log("搜索结束");
console.log(that
.unpairedList);
// console.log(that.pairedList);
//把已配对的蓝牙存内存
// uni.setStorageSync("pairedList",that.pairedList);
uni.hideLoading();
} else {
if (intent
.getParcelableExtra(
BluetoothDevice
.EXTRA_DEVICE)
.getBondState() === 10
) {
var y = 0;
for (let x = 0; x <
that.unpairedList
.length; x++) {
if (that
.unpairedList[
x]
.address ==
intent
.getParcelableExtra(
BluetoothDevice
.EXTRA_DEVICE
)
.getAddress()
) {
y++;
}
}
if (y > 0) {
y = 0;
} else {
that.unpairedList
.push({
name: intent
.getParcelableExtra(
BluetoothDevice
.EXTRA_DEVICE
)
.getName(),
address: intent
.getParcelableExtra(
BluetoothDevice
.EXTRA_DEVICE
)
.getAddress()
})
}
}
}
}
});
filter.addAction(bdevice.ACTION_FOUND);
filter.addAction(BAdapter
.ACTION_DISCOVERY_STARTED);
filter.addAction(BAdapter
.ACTION_DISCOVERY_FINISHED);
filter.addAction(BAdapter.ACTION_STATE_CHANGED);
main.registerReceiver(receiver, filter); //注册监听
}
})
}
},
})
}
})
},
//建立连接
createBLEConnection(mac_address) {
// mac_address为获取到蓝牙数据中的address字段
var main = plus.android.runtimeMainActivity();
var BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");
var BluetoothDevice = plus.android.importClass("android.bluetooth.BluetoothDevice");
var UUID = plus.android.importClass("java.util.UUID");
var uuid = UUID.fromString("00001101-0000-1000-8000-00805f9B34FB");
// this.bluetoothSocket = BluetoothDevice.createRfcommSocketToServiceRecord(uuid)
// console.log('bluetoothSocket',this.bluetoothSocket)
var BAdapter = BluetoothAdapter.getDefaultAdapter();
var device = BAdapter.getRemoteDevice(mac_address);
plus.android.importClass(device);
var bdevice = new BluetoothDevice();
var that = this;
//判断是否配对
if (device.getBondState() == bdevice.BOND_NONE) {
console.log("未配对蓝牙设备:" + device.getName() + ' ' + device.getAddress());
//参数如果跟取得的mac地址一样就配对
if (mac_address == device.getAddress()) {
// console.log("111")
if (device.createBond()) { //配对命令.createBond()
console.log("配对成功")
var cha = setInterval(function() {
if (device.getBondState() == bdevice.BOND_BONDED) {
clearInterval(cha);
//删除未配对蓝牙,添加到已配对
for (var i = 0; i < that.unpairedList.length; i++) {
if (that.unpairedList[i].address == mac_address) {
that.pairedList.push(that.unpairedList[i]);
that.unpairedList.splice(i, 1);
break;
}
}
}
}, 1000)
}
}
}
},
},
data() {
return {
bluetooth: 1, //1:打开蓝牙 2:关闭蓝牙
turnOnBluetooth: "打开蓝牙", //打开蓝牙
turnOffBluetooth: "关闭蓝牙", //关闭蓝牙
backgroundColor: "#cecece", //搜索蓝牙按钮背景颜色
title: 'Hello',
searchLoadingTxt: '',
isBlueOk: false,
bluetimestoper: null,
startchecktimer: null,
timeoutOfBlueScanFailure30s: 300000,
baseList: [],
bluetoothIndex: [],
targetDeviceName: '',
_deviceId: '', //蓝牙deviceId
pairedList: [], //已配对蓝牙
pairedLists: [], //已配对蓝牙集合
pairedHeight: 0, //已配对蓝牙显示高度
unpairedList: [], //未配对蓝牙
unpairedHeight: 0, //未配对蓝牙显示高度
bluetoothSocket: {},
}
}
//删除已配对设备
removePaire(index) {
var that = this;
uni.showModal({
title: "提示",
content: "是否删除设备",
showCancel: true,
cancelText: "取消",
confirmText: "确定",
success(res) {
// 确定删除设备
if (res.confirm) {
var address = uni.getStorageSync("printerSelected").address;
console.log("已选中蓝牙地址:" + address + " 删除蓝牙地址:" + that.pairedList[index].address);
if (that.pairedList[index].address == address) {
// that.pairedList[0].isSelected=1;
uni.setStorageSync("printerSelected", "");
}
for (var i = 0; i < that.pairedLists.length; i++) {
if (that.pairedLists[i].getAddress() == that.pairedList[index].address) {
that.pairedLists[i].removeBond();
}
}
that.pairedList.splice(index, 1);
//存储打印机
// uni.setStorageSync("pairedList",that.pairedList);
} else {
console.log("取消删除设备");
}
}
})
return false;
},
//设置已选中蓝牙
setSelectedPaired(paired) {
console.log('paired', paired)
var that = this;
for (var i = 0; i < that.pairedList.length; i++) {
if (that.pairedList[i].address == paired.address) {
that.pairedList[i].isSelected = 1;
} else {
that.pairedList[i].isSelected = 0;
}
}
uni.showLoading({
title:'正在建立连接'
})
uni.navigateTo({
url:`detail?name=${paired.name}&address=${paired.address}`
})
paired.isSelected = 1;
//存储已选择打印机
uni.setStorageSync("printerSelected", paired);
//存储打印机
// uni.setStorageSync("pairedList",that.pairedList);
},
//判断蓝牙打开状态
bluetoothStatus() {
var that = this;
const BluetoothAdapter = plus.android.importClass('android.bluetooth.BluetoothAdapter'); // 引入Java 蓝牙类
const blueadapter = BluetoothAdapter.getDefaultAdapter(); //拿到默认蓝牙适配器方法
if (blueadapter) {
// 判断蓝牙是否开启
if (blueadapter.isEnabled()) {
// 开启
that.bluetooth = 0;
that.backgroundColor = "red";
var yilianjie = uni.getStorageSync("printerSelected");
var selectAddress = "";
if (yilianjie) {
selectAddress = yilianjie.address;
}
// console.log("已选中地址:"+selectAddress);
//获取手机已配对蓝牙
var lists = blueadapter.getBondedDevices();
plus.android.importClass(lists);
var iterator = lists.iterator();
plus.android.importClass(iterator);
while (iterator.hasNext()) {
var device = iterator.next();
that.pairedLists.push(device);
plus.android.importClass(device);
that.pairedList.push({
name: device.getName(),
address: device.getAddress(),
isSelected: selectAddress == device.getAddress() ? '1' : '0'
})
// console.log(device.getName()+" ########### "+ device.getAddress());
}
//显示存储的已配对蓝牙
// this.pairedList = uni.getStorageSync("pairedList");
} else {
// 关闭
this.bluetooth = 1;
this.backgroundColor = "#cecece";
this.pairedList = [];
}
this.unpairedList = [];
}
},
//打开蓝牙
openBluetooth() {
var that = this;
// 弹出提示框
uni.showModal({
title: "提示",
content: "蓝牙尚未打开,是否打开蓝牙",
showCancel: true,
cancelText: "取消",
confirmText: "确定",
success(res) {
// 点击确定后通过系统打开蓝牙
if (res.confirm) {
const BluetoothAdapter = plus.android.importClass(
'android.bluetooth.BluetoothAdapter'); // 引入Java 蓝牙类
const blueadapter = BluetoothAdapter.getDefaultAdapter();
if (blueadapter != null) {
that.bluetooth = 0;
that.backgroundColor = "#8A2BCF";
//显示存储的已配对蓝牙
// that.pairedList = uni.getStorageSync("pairedList");
blueadapter.enable();
setTimeout(function() {
that.bluetoothStatus();
}, 2000)
}
} else {
// 点击取消什么也不做
console.log("取消打开蓝牙");
}
}
})
},
//关闭蓝牙
closeBluetooth() {
var that = this;
// 弹出提示框
uni.showModal({
title: "提示",
content: "蓝牙已打开,是否关闭蓝牙",
showCancel: true,
cancelText: "取消",
confirmText: "确定",
success(res) {
// 点击确定后通过系统打开蓝牙
if (res.confirm) {
const BluetoothAdapter = plus.android.importClass(
'android.bluetooth.BluetoothAdapter'); // 引入Java 蓝牙类
const blueadapter = BluetoothAdapter.getDefaultAdapter();
if (blueadapter != null) {
that.bluetooth = 1;
that.backgroundColor = "#cecece";
that.pairedList = [];
that.unpairedList = [];
uni.setStorageSync("printerSelected", "");
return blueadapter.disable();
}
} else {
// 点击取消什么也不做
console.log("取消关闭蓝牙");
}
}
})
},
//点击打开/关闭蓝牙按钮
blueTooth() {
if (this.bluetooth == 1) {
console.log("打开蓝牙");
this.openBluetooth();
} else {
console.log("关闭蓝牙");
this.closeBluetooth();
}
},
//初始化蓝牙模块
openBluetoothAdapter() {
//未打开蓝牙点击搜索蓝牙提示弹窗
if (this.bluetooth == 1) {
uni.showToast({
title: "请先打开蓝牙",
icon: "error"
})
return;
}
let system = uni.getSystemInfoSync(); // 获取系统信息
if (system.platform === 'android') { // 判断平台
var that = this;
var context = plus.android.importClass("android.content.Context");
var locationManager = plus.android.importClass("android.location.LocationManager");
var main = plus.android.runtimeMainActivity();
var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
// 定位检测
if (!mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER)) {
uni.showModal({
title: "提示",
content: "请打开定位服务功能",
showCancel: false, // 不显示取消按钮
success() {
if (!mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER)) {
var Intent = plus.android.importClass('android.content.Intent');
var Settings = plus.android.importClass('android.provider.Settings');
var intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
main.startActivity(intent); // 打开系统设置GPS服务页面
} else {
console.log('GPS功能已开启');
}
}
});
return false
} else {
console.log('GPS功能已开启');
that.searchDevices()
return true
}
}
},
//搜索蓝牙
searchDevices() {
var that = this;
that.unpairedList = []; //未配对
// that.pairedList = []; //已配对
//取内存里面已配对的蓝牙
// that.pairedList = uni.getStorageSync("pairedList");
//打开蓝牙模块
uni.openBluetoothAdapter({
success(res) {
console.log("蓝牙模块:", res);
//获取本机蓝牙适配器状态
uni.getBluetoothAdapterState({
success: function(res) {
console.log("蓝牙适配器状态:", res);
if (res.available) {
//开始搜寻附近的蓝牙外围设备
uni.startBluetoothDevicesDiscovery({
success(res) {
var main = plus.android.runtimeMainActivity();
var IntentFilter = plus.android.importClass(
'android.content.IntentFilter');
var BluetoothAdapter = plus.android.importClass(
"android.bluetooth.BluetoothAdapter");
var BluetoothDevice = plus.android.importClass(
"android.bluetooth.BluetoothDevice");
var BAdapter = BluetoothAdapter
.getDefaultAdapter();
if (BAdapter != null && !BAdapter.isEnabled()) {
let _intent = plus.android.importClass(
'android.content.Intent');
let intent = new _intent(blue_client
.ACTION_REQUEST_ENABLE);
main.startActivityForResult(intent, 200);
}
uni.showLoading({
title: "开始搜索设备",
})
//获取本机蓝牙信息
// var name = BAdapter.getName();
// var address = BAdapter.getAddress();
// console.log("本机蓝牙名称:"+name+" 本机蓝牙地址:"+address);
var filter = new IntentFilter();
var bdevice = new BluetoothDevice();
BAdapter.startDiscovery(); //开启搜索
var receiver;
receiver = plus.android.implements(
'io.dcloud.android.content.BroadcastReceiver', {
onReceive: function(context,
intent) { //实现onReceiver回调函数
plus.android.importClass(
intent); //通过intent实例引入intent类,方便以后的‘.’操作
if (intent.getAction() ==
"android.bluetooth.adapter.action.DISCOVERY_FINISHED"
) {
main.unregisterReceiver(
receiver); //取消监听
console.log("搜索结束");
console.log(that
.unpairedList);
// console.log(that.pairedList);
//把已配对的蓝牙存内存
// uni.setStorageSync("pairedList",that.pairedList);
uni.hideLoading();
} else {
if (intent
.getParcelableExtra(
BluetoothDevice
.EXTRA_DEVICE)
.getBondState() === 10
) {
var y = 0;
for (let x = 0; x <
that.unpairedList
.length; x++) {
if (that
.unpairedList[
x]
.address ==
intent
.getParcelableExtra(
BluetoothDevice
.EXTRA_DEVICE
)
.getAddress()
) {
y++;
}
}
if (y > 0) {
y = 0;
} else {
that.unpairedList
.push({
name: intent
.getParcelableExtra(
BluetoothDevice
.EXTRA_DEVICE
)
.getName(),
address: intent
.getParcelableExtra(
BluetoothDevice
.EXTRA_DEVICE
)
.getAddress()
})
}
}
}
}
});
filter.addAction(bdevice.ACTION_FOUND);
filter.addAction(BAdapter
.ACTION_DISCOVERY_STARTED);
filter.addAction(BAdapter
.ACTION_DISCOVERY_FINISHED);
filter.addAction(BAdapter.ACTION_STATE_CHANGED);
main.registerReceiver(receiver, filter); //注册监听
}
})
}
},
})
}
})
},
//建立连接
createBLEConnection(mac_address) {
// mac_address为获取到蓝牙数据中的address字段
var main = plus.android.runtimeMainActivity();
var BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");
var BluetoothDevice = plus.android.importClass("android.bluetooth.BluetoothDevice");
var UUID = plus.android.importClass("java.util.UUID");
var uuid = UUID.fromString("00001101-0000-1000-8000-00805f9B34FB");
// this.bluetoothSocket = BluetoothDevice.createRfcommSocketToServiceRecord(uuid)
// console.log('bluetoothSocket',this.bluetoothSocket)
var BAdapter = BluetoothAdapter.getDefaultAdapter();
var device = BAdapter.getRemoteDevice(mac_address);
plus.android.importClass(device);
var bdevice = new BluetoothDevice();
var that = this;
//判断是否配对
if (device.getBondState() == bdevice.BOND_NONE) {
console.log("未配对蓝牙设备:" + device.getName() + ' ' + device.getAddress());
//参数如果跟取得的mac地址一样就配对
if (mac_address == device.getAddress()) {
// console.log("111")
if (device.createBond()) { //配对命令.createBond()
console.log("配对成功")
var cha = setInterval(function() {
if (device.getBondState() == bdevice.BOND_BONDED) {
clearInterval(cha);
//删除未配对蓝牙,添加到已配对
for (var i = 0; i < that.unpairedList.length; i++) {
if (that.unpairedList[i].address == mac_address) {
that.pairedList.push(that.unpairedList[i]);
that.unpairedList.splice(i, 1);
break;
}
}
}
}, 1000)
}
}
}
},
},
收起阅读 »