HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

放弃 uni_modules 拥抱 npm 吧

就 uniapp 目前的技术力量而言,全面拥抱 npm 才是正道。

虽然 uni_modules 貌似王道,但请考虑技术力量不足造成的用户流失的代价。

全面 CLI,拥抱 npm,增强 vscode 插件。

做大做强,再创辉煌。

就 uniapp 目前的技术力量而言,全面拥抱 npm 才是正道。

虽然 uni_modules 貌似王道,但请考虑技术力量不足造成的用户流失的代价。

全面 CLI,拥抱 npm,增强 vscode 插件。

做大做强,再创辉煌。

招聘全栈开发1名,或项目外包,靠谱来

css HTML5 node Vue js uniCloud uniapp

了解前端html css javascript
熟悉vue,熟悉node.js
熟悉uniapp unicloud开发框架
有相关项目经验者优先

了解前端html css javascript
熟悉vue,熟悉node.js
熟悉uniapp unicloud开发框架
有相关项目经验者优先

wap2app打包后,真机测试时经常出现“无法连接服务器,请检查网络设置,”的提示。

wap2app

wap2app打包后,真机测试时经常出现“无法连接服务器,请检查网络设置,”的提示。
"wap2app" : {
"launchError" : "none"
},
添加此参数也不管用的。同类帖子有很多,都没有官方的回复。请官方给一个解决方法。

继续阅读 »

wap2app打包后,真机测试时经常出现“无法连接服务器,请检查网络设置,”的提示。
"wap2app" : {
"launchError" : "none"
},
添加此参数也不管用的。同类帖子有很多,都没有官方的回复。请官方给一个解决方法。

收起阅读 »

iOS APP上架流程(详细)

苹果登录 iOS打包

声明:本文转自http://www.2cto.com/kf/201512/453943.html,侵删。
前言:作为一名iOS开发者,把开发出来的App上传到App Store是必须的。下面就来详细介绍下具体流程。
1.打开苹果开发者中心:https://developer.apple.com
打开后点击:Member Center
如果你的电脑没有保存密码,则会提示你输入开发者帐号和密码,因为我的电脑已经保存了,所以直接进入。
2.点击:Certificates, Identifiers & Profiles
3.点击Devices
一.创建App IDs和Boudle ID
4.点击App IDs,会进入如下界面,点击右上角的 + 号
5.填写App IDs和Boudle ID
6.点击continue
7.点击Submit
8.点击Done
二.创建发布证书(若已创建过发布证书,现在用的是p12文件,可直接跳到第21步)
9.点击Production后,点击 + 号
10.点击App Store and Ad Hoc
11.点击Continue
12.点击Continue

创建本地证书
13.此时返回到桌面,在点开LaunchPad,在其他中找到钥匙串访问,切记不要关闭浏览器
14.打开钥匙串访问,点击电脑左上角的钥匙串访问–证书助理–从证书颁发机构请求证书
15.会出现如下界面,选择存储到磁盘,点击继续

16.选择存储到桌面,存储

17.点击完成

18.你会在桌面上看到下面的文件

19.然后回到浏览器,点击choose File.. 选择创建好的:CertificateSigningRequest.certSigningRequest 文件,点击Generate

<h4 id="20点击download<a href=" http:="" www.2cto.com="" soft"="" target="_blank" class="keylink" style="color: rgb(51, 51, 51); font-family: 宋体; font-size: 14px; line-height: 28px;">下载创建好的发布证书cer后缀的文件然后点击done你创建的发布证书就会存储在帐号中">20.点击Download下载创建好的发布证书(cer后缀的文件),然后点击Done,你创建的发布证书就会存储在帐号中。

注:一般一个开发者帐号创建一个发布证书就够了,如果以后需要在其他电脑上上架App,只需要在钥匙串访问中创建p12文件,把p12文件安装到其他电脑上。这相当于给予了其他电脑发布App的权限。
创建PP文件
21.找到Provisioning Profiles ,点击All,然后点击右上角 + 号
22.选择App Store,点击Continue
23.在App ID 这个选项栏里面找到你刚刚创建的:App IDs(Bundle ID) 类型的套装,点击Continue
24.选择你刚创建的发布证书(或者生成p12文件的那个发布证书),点击Continue
25.在Profile Name栏里输入一个名字(这个是PP文件的名字,可随便输入,在这里我用工程名字,便于分别),然后点击Generate
26.Download生成的PP文件,然后点击Done
在App Store开辟空间
27.回到Member Center,点击iTunes Connect
28.点击我的App
29.点击新建 iOSApp
30.依次按提示填入对应信息,然后点击创建
31.依次把不同尺寸的App截图拉入到对应的里面
32.填入App简介
33.按提示依次输入
34.此时这个构建版本还没有生成,我们先把基本信息填写完毕,然后再进入Xcode中把项目打包发送到过来。
注意:填写完一定要点击右上角的保存。
在Xcode中打包工程
找到你刚刚下载的发布证书(后缀为.cer)或者p12文件,和PP文件,双击,看起来没反应,但是他们已经加入到你的钥匙串中。
35.在Xcode中选择模拟器为iOS Device,按照下图提示操作
36.修改.plist文件,两个.plist文件都要修改
37.然后发送到我的App
38.发送成功后返回到我对App,刷新页面,在构建版本处就会有个 + 号,点击 + 号把发送过来的程序添加上去就行了
39.然后在定价处设置你的App上架后是免费还是收费。
40.回到我的App,点击发布就ok了。
证书我们这边可以借助辅助工具appuploader
Appuploader可以辅助在Windows、linux或mac系统直接申请iOS证书p12,及上传ipa到App Store,最方便在Windows开发上架没有苹果Mac电脑的开发者!配合本教程使用,可以快速掌握如何真机测试及上架!
点击苹果证书按钮


点击新增


输入证书密码,名称
这个密码不是账号密码,而是一个保护证书的密码,是p12文件的密码,此密码设置后没有其他地方可以找到,忘记了只能删除证书重新制作,所以请务必记住密码。还有为了安全起见,密码不要太简单。 证书名称是你为了在证书列表里面便于区别的一个字符,自己好辨识就可以,尽量是是字母和数字之类
选择证书类型
带distribution的是发布类型,带development的是开发类型。
apple类型=ios+mac,所以开发时选择ios app development和apple development 类型都是可以的
选择bundle id
只有部分类型的证书需要选择bundle id,例如推送证书。因为大部分证书是不和app关联的。而是通过描述文件profile文件关联app。
使用appuploader同步服务
如果期望制作好证书后在其他电脑上同样可以下载到这个证书,或者和你同事同步此证书,则需要勾选使用appuploader服务同步。否则您需要手动管理p12文件在不同电脑之间的传输,并且一但创建下载后,无法在其他电脑下载,只能手动复制文件过去。一般情况下,推荐使用appuploader服务同步。
证书类型说明
IOS开发选择apple development或者ios app development 类型 ios 发布选择 apple distribution或者 ios distribution (app store and ad hoc) 开发推送证书选择 apple push notification service ssl (sandbox) 发布推送证书选择 apple push notification service ssl (sandbox & production)
其他证书不是很常用,可以自行百度各种证书说明

继续阅读 »

声明:本文转自http://www.2cto.com/kf/201512/453943.html,侵删。
前言:作为一名iOS开发者,把开发出来的App上传到App Store是必须的。下面就来详细介绍下具体流程。
1.打开苹果开发者中心:https://developer.apple.com
打开后点击:Member Center
如果你的电脑没有保存密码,则会提示你输入开发者帐号和密码,因为我的电脑已经保存了,所以直接进入。
2.点击:Certificates, Identifiers & Profiles
3.点击Devices
一.创建App IDs和Boudle ID
4.点击App IDs,会进入如下界面,点击右上角的 + 号
5.填写App IDs和Boudle ID
6.点击continue
7.点击Submit
8.点击Done
二.创建发布证书(若已创建过发布证书,现在用的是p12文件,可直接跳到第21步)
9.点击Production后,点击 + 号
10.点击App Store and Ad Hoc
11.点击Continue
12.点击Continue

创建本地证书
13.此时返回到桌面,在点开LaunchPad,在其他中找到钥匙串访问,切记不要关闭浏览器
14.打开钥匙串访问,点击电脑左上角的钥匙串访问–证书助理–从证书颁发机构请求证书
15.会出现如下界面,选择存储到磁盘,点击继续

16.选择存储到桌面,存储

17.点击完成

18.你会在桌面上看到下面的文件

19.然后回到浏览器,点击choose File.. 选择创建好的:CertificateSigningRequest.certSigningRequest 文件,点击Generate

<h4 id="20点击download<a href=" http:="" www.2cto.com="" soft"="" target="_blank" class="keylink" style="color: rgb(51, 51, 51); font-family: 宋体; font-size: 14px; line-height: 28px;">下载创建好的发布证书cer后缀的文件然后点击done你创建的发布证书就会存储在帐号中">20.点击Download下载创建好的发布证书(cer后缀的文件),然后点击Done,你创建的发布证书就会存储在帐号中。

注:一般一个开发者帐号创建一个发布证书就够了,如果以后需要在其他电脑上上架App,只需要在钥匙串访问中创建p12文件,把p12文件安装到其他电脑上。这相当于给予了其他电脑发布App的权限。
创建PP文件
21.找到Provisioning Profiles ,点击All,然后点击右上角 + 号
22.选择App Store,点击Continue
23.在App ID 这个选项栏里面找到你刚刚创建的:App IDs(Bundle ID) 类型的套装,点击Continue
24.选择你刚创建的发布证书(或者生成p12文件的那个发布证书),点击Continue
25.在Profile Name栏里输入一个名字(这个是PP文件的名字,可随便输入,在这里我用工程名字,便于分别),然后点击Generate
26.Download生成的PP文件,然后点击Done
在App Store开辟空间
27.回到Member Center,点击iTunes Connect
28.点击我的App
29.点击新建 iOSApp
30.依次按提示填入对应信息,然后点击创建
31.依次把不同尺寸的App截图拉入到对应的里面
32.填入App简介
33.按提示依次输入
34.此时这个构建版本还没有生成,我们先把基本信息填写完毕,然后再进入Xcode中把项目打包发送到过来。
注意:填写完一定要点击右上角的保存。
在Xcode中打包工程
找到你刚刚下载的发布证书(后缀为.cer)或者p12文件,和PP文件,双击,看起来没反应,但是他们已经加入到你的钥匙串中。
35.在Xcode中选择模拟器为iOS Device,按照下图提示操作
36.修改.plist文件,两个.plist文件都要修改
37.然后发送到我的App
38.发送成功后返回到我对App,刷新页面,在构建版本处就会有个 + 号,点击 + 号把发送过来的程序添加上去就行了
39.然后在定价处设置你的App上架后是免费还是收费。
40.回到我的App,点击发布就ok了。
证书我们这边可以借助辅助工具appuploader
Appuploader可以辅助在Windows、linux或mac系统直接申请iOS证书p12,及上传ipa到App Store,最方便在Windows开发上架没有苹果Mac电脑的开发者!配合本教程使用,可以快速掌握如何真机测试及上架!
点击苹果证书按钮


点击新增


输入证书密码,名称
这个密码不是账号密码,而是一个保护证书的密码,是p12文件的密码,此密码设置后没有其他地方可以找到,忘记了只能删除证书重新制作,所以请务必记住密码。还有为了安全起见,密码不要太简单。 证书名称是你为了在证书列表里面便于区别的一个字符,自己好辨识就可以,尽量是是字母和数字之类
选择证书类型
带distribution的是发布类型,带development的是开发类型。
apple类型=ios+mac,所以开发时选择ios app development和apple development 类型都是可以的
选择bundle id
只有部分类型的证书需要选择bundle id,例如推送证书。因为大部分证书是不和app关联的。而是通过描述文件profile文件关联app。
使用appuploader同步服务
如果期望制作好证书后在其他电脑上同样可以下载到这个证书,或者和你同事同步此证书,则需要勾选使用appuploader服务同步。否则您需要手动管理p12文件在不同电脑之间的传输,并且一但创建下载后,无法在其他电脑下载,只能手动复制文件过去。一般情况下,推荐使用appuploader服务同步。
证书类型说明
IOS开发选择apple development或者ios app development 类型 ios 发布选择 apple distribution或者 ios distribution (app store and ad hoc) 开发推送证书选择 apple push notification service ssl (sandbox) 发布推送证书选择 apple push notification service ssl (sandbox & production)
其他证书不是很常用,可以自行百度各种证书说明

收起阅读 »

《一步步了解iOS APP上架流程,让你的APP顺利进入App Store的大门》

iOS打包 苹果审核

随着Apple Store越来越成熟,以及越来越多的开发者和公司希望在该平台上投放自己的产品,iOS APP上架成为许多开发者和公司普遍关注的话题。但是,由于苹果App Store的审核政策日益严格,大多数开发者和公司都不太清楚iOS APP上架的具体流程。今天,我们将为您介绍iOS APP上架的具体流程,希望可以帮助您顺利的完成iOS APP的上架。
1、准备App Store账号和必要的资料;
2、登录App Store Connect并注册开发者账号;
3、填写应用信息,包括:应用名称、描述、标签、版本等;
4、上传产品报告文件;
5、上传应用截图和APP文件;
6、提交审核;
7、审核通过后,即可在App Store上架。
证书我们这边可以借助辅助工具appuploader
Appuploader可以辅助在Windows、linux或mac系统直接申请iOS证书p12,及上传ipa到App Store,最方便在Windows开发上架没有苹果Mac电脑的开发者!配合本教程使用,可以快速掌握如何真机测试及上架!
点击苹果证书按钮
点击新增
输入证书密码,名称
这个密码不是账号密码,而是一个保护证书的密码,是p12文件的密码,此密码设置后没有其他地方可以找到,忘记了只能删除证书重新制作,所以请务必记住密码。还有为了安全起见,密码不要太简单。 证书名称是你为了在证书列表里面便于区别的一个字符,自己好辨识就可以,尽量是是字母和数字之类
选择证书类型
带distribution的是发布类型,带development的是开发类型。
apple类型=ios+mac,所以开发时选择ios app development和apple development 类型都是可以的
选择bundle id
只有部分类型的证书需要选择bundle id,例如推送证书。因为大部分证书是不和app关联的。而是通过描述文件profile文件关联app。
使用appuploader同步服务
如果期望制作好证书后在其他电脑上同样可以下载到这个证书,或者和你同事同步此证书,则需要勾选使用appuploader服务同步。否则您需要手动管理p12文件在不同电脑之间的传输,并且一但创建下载后,无法在其他电脑下载,只能手动复制文件过去。一般情况下,推荐使用appuploader服务同步。
证书类型说明
IOS开发选择apple development或者ios app development 类型 ios 发布选择 apple distribution或者 ios distribution (app store and ad hoc) 开发推送证书选择 apple push notification service ssl (sandbox) 发布推送证书选择 apple push notification service ssl (sandbox & production)
其他证书不是很常用,可以自行百度各种证书说明

继续阅读 »

随着Apple Store越来越成熟,以及越来越多的开发者和公司希望在该平台上投放自己的产品,iOS APP上架成为许多开发者和公司普遍关注的话题。但是,由于苹果App Store的审核政策日益严格,大多数开发者和公司都不太清楚iOS APP上架的具体流程。今天,我们将为您介绍iOS APP上架的具体流程,希望可以帮助您顺利的完成iOS APP的上架。
1、准备App Store账号和必要的资料;
2、登录App Store Connect并注册开发者账号;
3、填写应用信息,包括:应用名称、描述、标签、版本等;
4、上传产品报告文件;
5、上传应用截图和APP文件;
6、提交审核;
7、审核通过后,即可在App Store上架。
证书我们这边可以借助辅助工具appuploader
Appuploader可以辅助在Windows、linux或mac系统直接申请iOS证书p12,及上传ipa到App Store,最方便在Windows开发上架没有苹果Mac电脑的开发者!配合本教程使用,可以快速掌握如何真机测试及上架!
点击苹果证书按钮
点击新增
输入证书密码,名称
这个密码不是账号密码,而是一个保护证书的密码,是p12文件的密码,此密码设置后没有其他地方可以找到,忘记了只能删除证书重新制作,所以请务必记住密码。还有为了安全起见,密码不要太简单。 证书名称是你为了在证书列表里面便于区别的一个字符,自己好辨识就可以,尽量是是字母和数字之类
选择证书类型
带distribution的是发布类型,带development的是开发类型。
apple类型=ios+mac,所以开发时选择ios app development和apple development 类型都是可以的
选择bundle id
只有部分类型的证书需要选择bundle id,例如推送证书。因为大部分证书是不和app关联的。而是通过描述文件profile文件关联app。
使用appuploader同步服务
如果期望制作好证书后在其他电脑上同样可以下载到这个证书,或者和你同事同步此证书,则需要勾选使用appuploader服务同步。否则您需要手动管理p12文件在不同电脑之间的传输,并且一但创建下载后,无法在其他电脑下载,只能手动复制文件过去。一般情况下,推荐使用appuploader服务同步。
证书类型说明
IOS开发选择apple development或者ios app development 类型 ios 发布选择 apple distribution或者 ios distribution (app store and ad hoc) 开发推送证书选择 apple push notification service ssl (sandbox) 发布推送证书选择 apple push notification service ssl (sandbox & production)
其他证书不是很常用,可以自行百度各种证书说明

收起阅读 »

多媒体插件

https://ext.dcloud.net.cn/plugin?id=10659

https://ext.dcloud.net.cn/plugin?id=10659

uni-push 2.0 快速接入指南

uni-appx uni_app unipush

uni-push 2.0 快速接入指南

简介

此文档用于帮助开发者快速接入集成 uni-push 2.0 ,若想详细了解可以查看 uni-push 2.0 业务文档

名词解释

名词 解释
通知消息 指定通知标题和内容后,由个推 SDK 自动处理在系统通知栏中展示通知栏消息,同时响铃或震动提醒用户(响铃和震动受手机系统的设置状态影响)。
透传消息 即自定义消息,消息体格式客户可以自己定义,如纯文本、json 串等。透传消息个推只传递数据,不做任何处理,客户端接收到透传消息后需要自己去做后续动作处理,如通知栏展示、弹框等。
ClientId 个推业务层中的对外用户标识,用于标识客户端身份,由第三方客户端获取并保存到第三方服务端,是个推 SDK 的唯一识别号,简称 CID、cid。
在线推送 app 在前台打开运行时,通过个推渠道下发消息。
离线推送 app在后台、锁屏、进程关闭时,通过厂商渠道下发消息。若未集成 android 多厂商、未配置 ios 推送证书,则该机型无法使用离线推送。

消息下发流程

一、客户端集成

1.1 开通 uni-push 2.0 推送服务

unipush 内部封装好了个推及主流厂商 SDK,开发者在使用前必须开通相关服务。

使用 HBuilder 账号登录 开发者中心 ,创建应用、填写应用信息。


1.2 开通离线厂商推送服务

若未完成开通离线厂商推送,只有在 app 在线时才能收到消息
所有的厂商参数都是在下图所示位置配置,配置完成后,必须进行云打包, app 端才会生效

  • Android 多厂商开通:个推与主流安卓厂商合作融合了厂商推送 SDK,在后台配置 “厂商推送设置”并云打包后,可以同时使用 “离线推送”,能提高在安卓厂商设备上的消息到达率。

  • iOS 推送证书生成:iOS 支持的推送通知功能,从苹果开发者官网导出证书并配置在后台的 “厂商推送设置” 后,可以同时使用 “离线推送”,能提高在 iOS 设备上的消息到达率。

    • iOS 使用推送无需上架 Appstore
  • 鸿蒙Next 开通:纯血鸿蒙(HarmonyOS Next)系统的推送,配置鸿蒙Next 参数并进行云打包。

1.3 云打包

uni-app 框架App端

打开 HBuilderX (3.5.1及其以上版本),双击项目中的 “manifest.json” 文件,选择“App 模块配置”,向下找到“Push(消息推送)”,勾选后,点击 “uniPush” 下面配置。

注意:如果是 APP 集成推送,云打包请一定要勾选“离线推送”。如果不勾选“离线推送”,则打的包是小程序 SDK(小程序 SDK无法在 app 上稳定使用),且仅支持发在线透传消息,不会有通知栏展示。

uni-app x 框架的App端

标准基座不包含uni-push模块,如果需要使用此模块,应当在提交云打包时,项目代码中包含uni-push相关客户端api。点此了解 uni-app x的摇树机制

所以在开发调试时,需要先写一段包含uni-push相关客户端api代码,再打一个自定义基座。

例如先添加如下代码:

uni.getPushClientId({  
    success: (res) => {  
        let push_clientid = res.cid  
        console.log('客户端推送标识cid:',push_clientid)  
    },  
    fail(err) {  
        console.log(err)  
    }  
})

注意:此时由于运行的标准基座中,不包含uni-push模块,如果运行会报错,不用着急继续往下操作

点击菜单栏的【发行】-【原生APP-云打包】然后再弹出的窗口中勾选【制作自定义调试基座】- 点击【打包】
打包成功后,点击菜单栏的【运行】-【运行到手机或模拟器】-【运行到 Android App 基座】然后再弹出的窗口中勾选【使用自定义基座运行】-【运行】
接下来即可使用 uni-push 相关客户端 api

必须操作:云打包

必须填写自己的包名,进行云打包,下一步获取的才是属于自己应用的 cid。否则无法推送
云打包可以选择”正式包“和”自定义基座包“,开发测试建议使用 ”自定义基座包“。

1.4 集成验证

1.4.1 客户端获取 cid

假如我要给“张三”打电话,那就需要知道对方的电话标识,即电话号码是多少。 同理,要给某个客户端推送消息,也需要知道该设备的客户端推送标识。

启动 app 后成功获取 cid 则说明云打包 “在线推送” 成功,支持在线推送。

先跟着示例代码简单体验,详细的uni.getPushClientId API介绍 详情参考 代码示例:

// uni-app客户端获取push客户端标记,代码可以实现在App.vue中  
uni.getPushClientId({  
    success: (res) => {  
        let push_clientid = res.cid  
        console.log('客户端推送标识cid:',push_clientid)  
    },  
    fail(err) {  
        console.log(err)  
    }  
})

1.4.2 校验厂商离线推送是否集成成功

输入上方获取的 cid ,查询到对应的 Device Token 则说明云打包 “离线推送” 成功,同时支持离线推送。

如果未查询到 device token,则只能 “在线推送” 。若需要使用 “离线推送” 请重新检查 ”1.2 开通离线厂商推送服务“

二、服务端推送消息

注意:使用 uni-push 2.0,服务端不支持用个推 api 推送,只能用 dcloud 提供的 服务端(云函数)推送

2.1 云函数创建




注意:扩展库依赖 3 张 opendb 表opendb-tempdata,opendb-device,uni-id-device。公测版 uniCloud,执行扩展库会自动创建。如果你使用的是 uniCloud 正式版需要自己在 uniCloud 的 web控制台 创建这3张表。

示例如下:


2.2 云函数执行

在云函数文件目录右键(或按快捷键ctrl + r)-> 上传并运行云函数,此时你的客户端将收到推送消息(应用关闭时为通知栏消息,在线时代码监听到推送消息)。

云函数中调用uni-cloud-push扩展库的sendMessage方法,向客户端推送消息

// 简单的使用示例  
'use strict';  
const uniPush = uniCloud.getPushManager({appId:"__UNI__XXXXXX"}) //注意这里需要传入你的应用appId  
exports.main = async (event, context) => {  
    return await uniPush.sendMessage({  
        "push_clientid": "xxx",     //填写上一步在uni-app客户端获取到的客户端推送标识push_clientid  
        "force_notification":true,  //填写true,客户端就会对在线消息自动创建“通知栏消息”。  
        "title": "通知栏显示的标题",      
        "content": "通知栏显示的内容",  
        "settings": {  
            //消息有效期设置,单位毫秒,-1表示不设离线。默认是 2 小时,取值范围:-1 ~ 3 * 24 * 3600 * 1000(3天)之间  
            "ttl":86400000  
        },  
        "payload": {  
            "text":"体验一下uni-push2.0"  
        },  
        "category": {  
            //HarmonyOS NEXT系统(纯血鸿蒙、非安卓鸿蒙)的消息分类,要给鸿蒙设备推送时才必传  
            "harmony":"MARKETING"  
        },  
        "options":{  
            "HW": {      
                 // 值为int 类型。1 表示华为测试消息,华为每个应用每日可发送该测试消息500条。此 target_user_type 参数请勿发布至线上。      
                  "/message/android/target_user_type":1      
              } ,    
            "HO": {      
                 //值为int 类型。1 表示测试推送,不填默认为0。荣耀每个应用每日可发送该测试消息1000条。此测试参数请勿发布至线上。  
                  "/android/targetUserType": 1   
              } ,  
            "VV": {      
                 //值为int 类型。0 表示正式推送;1 表示测试推送,不填默认为0。此 pushMode 参数请勿发布至线上。  
                  "/pushMode":1      
              } ,    
            "XM": {      
                 //新小米消息分类下,私信公信id都必须要传,否则请求小米厂商接口会被拦截  
                  "/extra.channel_id": "填写小米平台申请的渠道id"   
              }    
        }  
    })  
};

注意:非OPPO、VIVO软件商店官方渠道下载的应用,厂商不提供公信消息服务。
vivo、oppo 对接离线推送时,可以暂时发送测试消息,额外需要分别在 vivo 开放平台 、 oppo开放平台 录入测试用户(regid 对应个推cid 绑定的 device token,可以从个推后台的“故障排查”中查询 cid 信息获取)。

在线消息无额度限制。离线推送各厂商的限额(包含 extra.channel_id 如何申请),详见: 厂商通道限额

HarmonyOS NEXT系统(纯血鸿蒙、非安卓鸿蒙)的消息分类,harmony取值参考 云端通知category取值

如果你希望当应用在线时,也通过“通知栏消息”来提醒用户;可以通过以下两种方式实现:

  1. 监听到消息内容后,根据业务需要自己判断是否要创建“通知栏消息”,需要就调用创建本地消息API uni.createPushMessage手动创建通知栏消息。
  2. 服务端执行推送时,传递参数force_notification:true,客户端就会自动创建“通知栏消息”(此时你监听不到消息内容),当用户点击通知栏消息后,APP才能监听到消息内容。

先跟着示例代码简单体验,详细的 uniPush.sendMessage API介绍 详情参考
检查确认当前 app 的通知栏权限开启后,则可以开始进行推送测试。

2.2.1 测试在线推送,打开 app 在前台时进行推送

2.2.2 测试离线推送,关闭 app 进程时进行推送

2.2.3 手机成功收到消息展示

恭喜您,如果您已经成功收到 在线离线 的消息展示,那说明已经集成推送成功啦!

2.3 云函数 URL 化 (可选)

在 uniCloud 的云函数中,加载扩展库 uni-cloud-push,直接调用相关 API,无需额外的服务端配置。

传统服务器开发者(例如:Java、php、python等)需要把这个 云函数URL化 后变成 http 接口,再由代码调用这个 http 接口。

云函数URL化 步骤简介----------->

1,上传步骤云函数代码

2,云函数URL化


3,api 工具测试请求(单推示例)

4,云函数代码示例

// 简单的使用示例  
'use strict';  
const uniPush = uniCloud.getPushManager({  
appId: "你的__UNI__开头的AppId"  
})  
exports.main = async (event) => {  
    let obj = JSON.parse(event.body)  
        const res = await uniPush.sendMessage({  
        "push_clientid": obj.cids, // 设备id,支持多个以数组的形式指定多个设备,如["cid-1","cid-2"],数组长度不大于1000  
        "title": obj.title, // 标题  
        "content": obj.content, // 内容  
        "settings": obj.settings, // 消息有效期  
        "payload": obj.payload, // 数据  
        "category": obj.category, // HarmonyOS NEXT系统(纯血鸿蒙、非安卓鸿蒙)的消息分类,要给鸿蒙设备推送时才必传  
        "force_notification": true, //填写true,客户端就会对在线消息自动创建“通知栏消息”,不填写则需要客户端自己处理。  
        "request_id": obj.request_id ,//请求唯一标识号,10-32位之间;如果request_id重复,会导致消息丢失  
        "options":obj.options //消息分类,没申请可以不传这个参数  
    })  
    return res;  
};

注意:如果推送时不传入 cid,则发送的是全推(给所有用户推)消息。全推每分钟不能超过5次,10分钟内不能推重复消息体 。 通过返回值中的 taskid 几个首字母可以判断是什么推送。RASS:单推、 RASL:批量推、 RASA:全推

5,postman请求示例

{  
    "request_id": "212320028909901111",  
    "cids": "此处填写自定义打包获取的clientid参数",  
    "title": "通知标题",  
    "content": "通知内容 ",  
    "settings": {  
        //消息有效期设置,单位毫秒,-1表示不设离线。默认是 2 小时,取值范围:-1 ~ 3 * 24 * 3600 * 1000(3天)之间  
        "ttl": 86400000  
        },  
    "options": {  
        "HW": {  
            // 值为int 类型。1 表示华为测试消息,华为每个应用每日可发送该测试消息500条。此 target_user_type 参数请勿发布至线上。      
            "/message/android/target_user_type": 1  
        },  
        "HO": {  
            //值为int 类型。1 表示测试推送,不填默认为0。荣耀每个应用每日可发送该测试消息1000条。此测试参数请勿发布至线上。  
            "/android/targetUserType": 1  
        },  
        "VV": {  
            //值为int 类型。0 表示正式推送;1 表示测试推送,不填默认为0。此 pushMode 参数请勿发布至线上。  
            "/pushMode": 1  
        },  
        "XM": {  
            //新小米消息分类下,私信公信id都必须要传,否则请求小米厂商接口会被拦截  
            "/extra.channel_id": "填写小米平台申请的渠道id"  
        }  
    },  
    "category": {  
         //HarmonyOS NEXT系统(纯血鸿蒙、非安卓鸿蒙)的消息分类,要给鸿蒙设备推送时才必传  
        "harmony":"MARKETING"  
    },  
    //payload是点击通知栏消息后,传给客户端click回调的自定义参数  
    "payload": {  
        "data1": 1,  
        "data2": 2  
    }  
}

三、客户端接收消息

3.1 客户端监听推送消息

如果您需要对接收到的消息进行自定义处理,可以再阅读一下本文开头的 “消息下发流程图”。

客户端监听推送消息的代码,需要在收到推送消息之前被执行。所以应当写在应用一启动就会触发的 应用生命周期 onLaunch中。

示例代码:

//文件路径:项目根目录/App.vue  
export default {  
    onLaunch: function() {  
        console.log('App Launch')  
        uni.onPushMessage((res) => {  
            // 监听【在线、离线】通知栏消息的点击  
            if(res.type == 'click'){  
                // 如果需要跳转app内指定页面,则自己实现下方的跳转代码。  
                uni.navigateTo({    
                    //页面路径示例值:/pages/pushinfo/pushinfo    
                    url:'指定页面路径'      
                })    
            }  
            // 监听【在线】消息到达。若云函数设置了 "force_notification":true,则不会触发此 receive。  
            if(res.type == 'receive'){  
                console.log("接收到的消息内容",res.payload);  
            }  
        })  
    },  
    onShow: function() {  
        console.log('App Show')  
    },  
    onHide: function() {  
        console.log('App Hide')  
    }  
}

如果要在receive回调里面,自己创建通知栏消息展示,可以调用 createMessage

先跟着示例代码简单体验,详细的 uni.onPushMessage API介绍 详情参考

四、注意事项

4.1 合规上架

-app 若需要上架应用商店,须配置 隐私弹窗 提示用户。
-在使用个推各项SDK产品时,开发者需在App《隐私政策》的 “与授权合作伙伴共享”条款中,将 个推的隐私政策 加入其中。详见: Android平台各功能模块隐私合规协议

4.2 帮助中心

当您在集成推送服务遇到问题时:

先仔细阅读此接入指南及对应的集成文档,查看是否有遗漏。
阅读 uni-push2.0 常见问题 ,查看是否能解决。

继续阅读 »

uni-push 2.0 快速接入指南

简介

此文档用于帮助开发者快速接入集成 uni-push 2.0 ,若想详细了解可以查看 uni-push 2.0 业务文档

名词解释

名词 解释
通知消息 指定通知标题和内容后,由个推 SDK 自动处理在系统通知栏中展示通知栏消息,同时响铃或震动提醒用户(响铃和震动受手机系统的设置状态影响)。
透传消息 即自定义消息,消息体格式客户可以自己定义,如纯文本、json 串等。透传消息个推只传递数据,不做任何处理,客户端接收到透传消息后需要自己去做后续动作处理,如通知栏展示、弹框等。
ClientId 个推业务层中的对外用户标识,用于标识客户端身份,由第三方客户端获取并保存到第三方服务端,是个推 SDK 的唯一识别号,简称 CID、cid。
在线推送 app 在前台打开运行时,通过个推渠道下发消息。
离线推送 app在后台、锁屏、进程关闭时,通过厂商渠道下发消息。若未集成 android 多厂商、未配置 ios 推送证书,则该机型无法使用离线推送。

消息下发流程

一、客户端集成

1.1 开通 uni-push 2.0 推送服务

unipush 内部封装好了个推及主流厂商 SDK,开发者在使用前必须开通相关服务。

使用 HBuilder 账号登录 开发者中心 ,创建应用、填写应用信息。


1.2 开通离线厂商推送服务

若未完成开通离线厂商推送,只有在 app 在线时才能收到消息
所有的厂商参数都是在下图所示位置配置,配置完成后,必须进行云打包, app 端才会生效

  • Android 多厂商开通:个推与主流安卓厂商合作融合了厂商推送 SDK,在后台配置 “厂商推送设置”并云打包后,可以同时使用 “离线推送”,能提高在安卓厂商设备上的消息到达率。

  • iOS 推送证书生成:iOS 支持的推送通知功能,从苹果开发者官网导出证书并配置在后台的 “厂商推送设置” 后,可以同时使用 “离线推送”,能提高在 iOS 设备上的消息到达率。

    • iOS 使用推送无需上架 Appstore
  • 鸿蒙Next 开通:纯血鸿蒙(HarmonyOS Next)系统的推送,配置鸿蒙Next 参数并进行云打包。

1.3 云打包

uni-app 框架App端

打开 HBuilderX (3.5.1及其以上版本),双击项目中的 “manifest.json” 文件,选择“App 模块配置”,向下找到“Push(消息推送)”,勾选后,点击 “uniPush” 下面配置。

注意:如果是 APP 集成推送,云打包请一定要勾选“离线推送”。如果不勾选“离线推送”,则打的包是小程序 SDK(小程序 SDK无法在 app 上稳定使用),且仅支持发在线透传消息,不会有通知栏展示。

uni-app x 框架的App端

标准基座不包含uni-push模块,如果需要使用此模块,应当在提交云打包时,项目代码中包含uni-push相关客户端api。点此了解 uni-app x的摇树机制

所以在开发调试时,需要先写一段包含uni-push相关客户端api代码,再打一个自定义基座。

例如先添加如下代码:

uni.getPushClientId({  
    success: (res) => {  
        let push_clientid = res.cid  
        console.log('客户端推送标识cid:',push_clientid)  
    },  
    fail(err) {  
        console.log(err)  
    }  
})

注意:此时由于运行的标准基座中,不包含uni-push模块,如果运行会报错,不用着急继续往下操作

点击菜单栏的【发行】-【原生APP-云打包】然后再弹出的窗口中勾选【制作自定义调试基座】- 点击【打包】
打包成功后,点击菜单栏的【运行】-【运行到手机或模拟器】-【运行到 Android App 基座】然后再弹出的窗口中勾选【使用自定义基座运行】-【运行】
接下来即可使用 uni-push 相关客户端 api

必须操作:云打包

必须填写自己的包名,进行云打包,下一步获取的才是属于自己应用的 cid。否则无法推送
云打包可以选择”正式包“和”自定义基座包“,开发测试建议使用 ”自定义基座包“。

1.4 集成验证

1.4.1 客户端获取 cid

假如我要给“张三”打电话,那就需要知道对方的电话标识,即电话号码是多少。 同理,要给某个客户端推送消息,也需要知道该设备的客户端推送标识。

启动 app 后成功获取 cid 则说明云打包 “在线推送” 成功,支持在线推送。

先跟着示例代码简单体验,详细的uni.getPushClientId API介绍 详情参考 代码示例:

// uni-app客户端获取push客户端标记,代码可以实现在App.vue中  
uni.getPushClientId({  
    success: (res) => {  
        let push_clientid = res.cid  
        console.log('客户端推送标识cid:',push_clientid)  
    },  
    fail(err) {  
        console.log(err)  
    }  
})

1.4.2 校验厂商离线推送是否集成成功

输入上方获取的 cid ,查询到对应的 Device Token 则说明云打包 “离线推送” 成功,同时支持离线推送。

如果未查询到 device token,则只能 “在线推送” 。若需要使用 “离线推送” 请重新检查 ”1.2 开通离线厂商推送服务“

二、服务端推送消息

注意:使用 uni-push 2.0,服务端不支持用个推 api 推送,只能用 dcloud 提供的 服务端(云函数)推送

2.1 云函数创建




注意:扩展库依赖 3 张 opendb 表opendb-tempdata,opendb-device,uni-id-device。公测版 uniCloud,执行扩展库会自动创建。如果你使用的是 uniCloud 正式版需要自己在 uniCloud 的 web控制台 创建这3张表。

示例如下:


2.2 云函数执行

在云函数文件目录右键(或按快捷键ctrl + r)-> 上传并运行云函数,此时你的客户端将收到推送消息(应用关闭时为通知栏消息,在线时代码监听到推送消息)。

云函数中调用uni-cloud-push扩展库的sendMessage方法,向客户端推送消息

// 简单的使用示例  
'use strict';  
const uniPush = uniCloud.getPushManager({appId:"__UNI__XXXXXX"}) //注意这里需要传入你的应用appId  
exports.main = async (event, context) => {  
    return await uniPush.sendMessage({  
        "push_clientid": "xxx",     //填写上一步在uni-app客户端获取到的客户端推送标识push_clientid  
        "force_notification":true,  //填写true,客户端就会对在线消息自动创建“通知栏消息”。  
        "title": "通知栏显示的标题",      
        "content": "通知栏显示的内容",  
        "settings": {  
            //消息有效期设置,单位毫秒,-1表示不设离线。默认是 2 小时,取值范围:-1 ~ 3 * 24 * 3600 * 1000(3天)之间  
            "ttl":86400000  
        },  
        "payload": {  
            "text":"体验一下uni-push2.0"  
        },  
        "category": {  
            //HarmonyOS NEXT系统(纯血鸿蒙、非安卓鸿蒙)的消息分类,要给鸿蒙设备推送时才必传  
            "harmony":"MARKETING"  
        },  
        "options":{  
            "HW": {      
                 // 值为int 类型。1 表示华为测试消息,华为每个应用每日可发送该测试消息500条。此 target_user_type 参数请勿发布至线上。      
                  "/message/android/target_user_type":1      
              } ,    
            "HO": {      
                 //值为int 类型。1 表示测试推送,不填默认为0。荣耀每个应用每日可发送该测试消息1000条。此测试参数请勿发布至线上。  
                  "/android/targetUserType": 1   
              } ,  
            "VV": {      
                 //值为int 类型。0 表示正式推送;1 表示测试推送,不填默认为0。此 pushMode 参数请勿发布至线上。  
                  "/pushMode":1      
              } ,    
            "XM": {      
                 //新小米消息分类下,私信公信id都必须要传,否则请求小米厂商接口会被拦截  
                  "/extra.channel_id": "填写小米平台申请的渠道id"   
              }    
        }  
    })  
};

注意:非OPPO、VIVO软件商店官方渠道下载的应用,厂商不提供公信消息服务。
vivo、oppo 对接离线推送时,可以暂时发送测试消息,额外需要分别在 vivo 开放平台 、 oppo开放平台 录入测试用户(regid 对应个推cid 绑定的 device token,可以从个推后台的“故障排查”中查询 cid 信息获取)。

在线消息无额度限制。离线推送各厂商的限额(包含 extra.channel_id 如何申请),详见: 厂商通道限额

HarmonyOS NEXT系统(纯血鸿蒙、非安卓鸿蒙)的消息分类,harmony取值参考 云端通知category取值

如果你希望当应用在线时,也通过“通知栏消息”来提醒用户;可以通过以下两种方式实现:

  1. 监听到消息内容后,根据业务需要自己判断是否要创建“通知栏消息”,需要就调用创建本地消息API uni.createPushMessage手动创建通知栏消息。
  2. 服务端执行推送时,传递参数force_notification:true,客户端就会自动创建“通知栏消息”(此时你监听不到消息内容),当用户点击通知栏消息后,APP才能监听到消息内容。

先跟着示例代码简单体验,详细的 uniPush.sendMessage API介绍 详情参考
检查确认当前 app 的通知栏权限开启后,则可以开始进行推送测试。

2.2.1 测试在线推送,打开 app 在前台时进行推送

2.2.2 测试离线推送,关闭 app 进程时进行推送

2.2.3 手机成功收到消息展示

恭喜您,如果您已经成功收到 在线离线 的消息展示,那说明已经集成推送成功啦!

2.3 云函数 URL 化 (可选)

在 uniCloud 的云函数中,加载扩展库 uni-cloud-push,直接调用相关 API,无需额外的服务端配置。

传统服务器开发者(例如:Java、php、python等)需要把这个 云函数URL化 后变成 http 接口,再由代码调用这个 http 接口。

云函数URL化 步骤简介----------->

1,上传步骤云函数代码

2,云函数URL化


3,api 工具测试请求(单推示例)

4,云函数代码示例

// 简单的使用示例  
'use strict';  
const uniPush = uniCloud.getPushManager({  
appId: "你的__UNI__开头的AppId"  
})  
exports.main = async (event) => {  
    let obj = JSON.parse(event.body)  
        const res = await uniPush.sendMessage({  
        "push_clientid": obj.cids, // 设备id,支持多个以数组的形式指定多个设备,如["cid-1","cid-2"],数组长度不大于1000  
        "title": obj.title, // 标题  
        "content": obj.content, // 内容  
        "settings": obj.settings, // 消息有效期  
        "payload": obj.payload, // 数据  
        "category": obj.category, // HarmonyOS NEXT系统(纯血鸿蒙、非安卓鸿蒙)的消息分类,要给鸿蒙设备推送时才必传  
        "force_notification": true, //填写true,客户端就会对在线消息自动创建“通知栏消息”,不填写则需要客户端自己处理。  
        "request_id": obj.request_id ,//请求唯一标识号,10-32位之间;如果request_id重复,会导致消息丢失  
        "options":obj.options //消息分类,没申请可以不传这个参数  
    })  
    return res;  
};

注意:如果推送时不传入 cid,则发送的是全推(给所有用户推)消息。全推每分钟不能超过5次,10分钟内不能推重复消息体 。 通过返回值中的 taskid 几个首字母可以判断是什么推送。RASS:单推、 RASL:批量推、 RASA:全推

5,postman请求示例

{  
    "request_id": "212320028909901111",  
    "cids": "此处填写自定义打包获取的clientid参数",  
    "title": "通知标题",  
    "content": "通知内容 ",  
    "settings": {  
        //消息有效期设置,单位毫秒,-1表示不设离线。默认是 2 小时,取值范围:-1 ~ 3 * 24 * 3600 * 1000(3天)之间  
        "ttl": 86400000  
        },  
    "options": {  
        "HW": {  
            // 值为int 类型。1 表示华为测试消息,华为每个应用每日可发送该测试消息500条。此 target_user_type 参数请勿发布至线上。      
            "/message/android/target_user_type": 1  
        },  
        "HO": {  
            //值为int 类型。1 表示测试推送,不填默认为0。荣耀每个应用每日可发送该测试消息1000条。此测试参数请勿发布至线上。  
            "/android/targetUserType": 1  
        },  
        "VV": {  
            //值为int 类型。0 表示正式推送;1 表示测试推送,不填默认为0。此 pushMode 参数请勿发布至线上。  
            "/pushMode": 1  
        },  
        "XM": {  
            //新小米消息分类下,私信公信id都必须要传,否则请求小米厂商接口会被拦截  
            "/extra.channel_id": "填写小米平台申请的渠道id"  
        }  
    },  
    "category": {  
         //HarmonyOS NEXT系统(纯血鸿蒙、非安卓鸿蒙)的消息分类,要给鸿蒙设备推送时才必传  
        "harmony":"MARKETING"  
    },  
    //payload是点击通知栏消息后,传给客户端click回调的自定义参数  
    "payload": {  
        "data1": 1,  
        "data2": 2  
    }  
}

三、客户端接收消息

3.1 客户端监听推送消息

如果您需要对接收到的消息进行自定义处理,可以再阅读一下本文开头的 “消息下发流程图”。

客户端监听推送消息的代码,需要在收到推送消息之前被执行。所以应当写在应用一启动就会触发的 应用生命周期 onLaunch中。

示例代码:

//文件路径:项目根目录/App.vue  
export default {  
    onLaunch: function() {  
        console.log('App Launch')  
        uni.onPushMessage((res) => {  
            // 监听【在线、离线】通知栏消息的点击  
            if(res.type == 'click'){  
                // 如果需要跳转app内指定页面,则自己实现下方的跳转代码。  
                uni.navigateTo({    
                    //页面路径示例值:/pages/pushinfo/pushinfo    
                    url:'指定页面路径'      
                })    
            }  
            // 监听【在线】消息到达。若云函数设置了 "force_notification":true,则不会触发此 receive。  
            if(res.type == 'receive'){  
                console.log("接收到的消息内容",res.payload);  
            }  
        })  
    },  
    onShow: function() {  
        console.log('App Show')  
    },  
    onHide: function() {  
        console.log('App Hide')  
    }  
}

如果要在receive回调里面,自己创建通知栏消息展示,可以调用 createMessage

先跟着示例代码简单体验,详细的 uni.onPushMessage API介绍 详情参考

四、注意事项

4.1 合规上架

-app 若需要上架应用商店,须配置 隐私弹窗 提示用户。
-在使用个推各项SDK产品时,开发者需在App《隐私政策》的 “与授权合作伙伴共享”条款中,将 个推的隐私政策 加入其中。详见: Android平台各功能模块隐私合规协议

4.2 帮助中心

当您在集成推送服务遇到问题时:

先仔细阅读此接入指南及对应的集成文档,查看是否有遗漏。
阅读 uni-push2.0 常见问题 ,查看是否能解决。

收起阅读 »

wifi打印机打印(二维码,条形码等)

  1. 打印机,需要插usb(或者微信小程序设置wifi)
  2. 打印机的默认端口是9100(一般是,具体看购买的打印机)
  3. wifitool.js是用于连接打印机的
  4. 此文章是用的CPCL指令,可以根据自己的指令格式修改(var command = tsc.jpPrinter.createNew();)
    vue

    <template>  
    <view>  
    <button @click="printSocket">WiFi打印</button>  
    </view>  
    </template>

    js

    
    <script>  
    import tsc from "@/static/libs/tsc.js";  
    import wifiTool from "@/static/libs/WifiTool.js";  
    export default {  
    data() {  
    return {  
      ip: "192.168.4.245",  
      port: 9100,  
      str: "yyy",  
    };  
    },  
    mounted() {  
    wifiTool.connectWifi("192.168.4.245", 9100);  
    },  
    methods: {  
    test(str, ip, port) {  
      str = "test";  
      var Socket = plus.android.importClass("java.net.Socket");  
      var JavaByte = plus.android.importClass("java.lang.Byte");  
      var PrintWriter = plus.android.importClass("java.io.PrintWriter");  
      var BufferedWriter = plus.android.importClass("java.io.BufferedWriter");  
      var OutputStreamWriter = plus.android.importClass("java.io.OutputStreamWriter");  
      var BufferedReader = plus.android.importClass("java.io.BufferedReader");  
      var InputStreamReader = plus.android.importClass("java.io.InputStreamReader");  
    
      //测试改良  
      var StrictMode = plus.android.importClass("android.os.StrictMode");  
      var Build = plus.android.importClass("android.os.Build");  
      if (Build.VERSION.SDK_INT > 9) {  
        var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();  
        StrictMode.setThreadPolicy(policy);  
      }  
      var socket = new Socket(ip, port);  
    
      var outputStreamWriter = new OutputStreamWriter(socket.getOutputStream());  
      var bufferWriter = new BufferedWriter(outputStreamWriter);  
      var out = new PrintWriter(bufferWriter, true);  
    
      var command = tsc.jpPrinter.createNew();  
      command.init(0, 200, 200, 210, 1);  
      command.setCls();  
      command.setQR(30, 40, 2, 6, "123");  
      //   command.setMag(2, 2);  
      //   command.setText1(55, 30, 180, 60, "地址: 内蒙");  
      //   command.setMag(2, 2);  
      //   command.setText1(55, 6, 180, 120, "重量: 15kg");  
      command.setPagePrint();  
      let data = command.getData();  
    
      out.println(data);  
      socket.setSoTimeout(3000);  
      socket.close();  
    },  
    printSocket() {  
      var command = tsc.jpPrinter.createNew();  
      command.init(0, 200, 250, 210, 1);  
      command.setCls();  
      command.setQR(30, 40, 2, 6, "123");  
      command.setMag(2, 2);  
      command.setText1(55, 30, 180, 60, "地址: 内蒙");  
      command.setMag(2, 2);  
      command.setText1(55, 6, 180, 120, "重量: 15kg");  
      command.setPostfeed(32);//打印后走纸  
      command.setPagePrint();  
      let data = command.getData();  
      wifiTool.sendData(data);  
    },  
    connectWifi(ip, port) {  
      if (plus.os.name == "Android") {  
        // plus.nativeUI.showWaiting("正在打印中。。。");  
        var Socket = plus.android.importClass("java.net.Socket");  
        var socket;  
        var outputStream;  
        //解决高低版本兼容  
        var StrictMode = plus.android.importClass("android.os.StrictMode");  
        var Build = plus.android.importClass("android.os.Build");  
        if (Build.VERSION.SDK_INT > 9) {  
          var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();  
          StrictMode.setThreadPolicy(policy);  
        }  
        try {  
          socket = new Socket(ip, port);  
          socket.setKeepAlive(true);  
          outputStream = socket.getOutputStream();  
          plus.android.importClass(outputStream);  
          //   var bytes = plus.android.invoke(str, "getBytes", "gbk");  
          uni.showToast({  
            title: "wifi连接成功",  
          });  
    
          //   plus.nativeUI.closeWaiting();  
        } catch (e) {  
          console.log("网络连接超时,请重新连接!");  
          //TODO handle the exception  
          //   plus.nativeUI.closeWaiting();  
        }  
      }  
    },  
    },  
    };  
    </script>  
WifiTool.js  

```javascript  

/**  
 * 初始化参数  
 */  
//#ifdef APP-PLUS  
var Socket = plus.android.importClass("java.net.Socket");  
var socket;  
var outputStream;  
//解决高低版本兼容  
var StrictMode = plus.android.importClass("android.os.StrictMode");  
var Build = plus.android.importClass("android.os.Build");  
//#endif  
/**  
 * 构造对象  
 */  
var wifiTool = {  
    connectWifi(ip, port) {  
        if (Build.VERSION.SDK_INT > 9) {  
            var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();  
            StrictMode.setThreadPolicy(policy);  
        }  
        try {  
            socket = new Socket(ip, port);  
            socket.setKeepAlive(true);  
            outputStream = socket.getOutputStream();  
            plus.android.importClass(outputStream);  
            //   var bytes = plus.android.invoke(str, "getBytes", "gbk");  
            uni.showToast({  
                title: 'wifi连接成功',  
            });  

            //   plus.nativeUI.closeWaiting();  
        } catch (e) {  
            console.log("网络连接超时,请重新连接!")  
            //TODO handle the exception  
            //   plus.nativeUI.closeWaiting();  
        }  
    },  
    sendData(data) {  

        console.log(outputStream);  
        outputStream.write(data);  
        outputStream.flush();  
        // 关闭socket  
        // socket.shutdownOutput();  
        console.log(socket);  
    }  
}  

module.exports = wifiTool

tsc.js

/**  
 * tsc 命令打印工具类  
 * 2021.04.26 uni-app版本  
 * @auth boolTrue  
 */  
var encode = require("./encoding.js");  
var jpPrinter = {  
    createNew: function () {  
        var jpPrinter = {};  
        var data = "";  
        var command = []  
        var rawCommand = ''  

        jpPrinter.name = "标签模式";  

        jpPrinter.init = function (x, y, z, h, q) {  
            data = "! " + x + " " + y + " " + z + " " + h + " " + q + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.addCommand = function (content) { //将指令转成数组装起  
            //#ifdef MP-WEIXIN  
            var code = new encode.TextEncoder(  
                'gb18030', {  
                NONSTANDARD_allowLegacyEncoding: true  
            }).encode(content)  
            for (var i = 0; i < code.length; ++i) {  
                command.push(code[i])  
            }  
            //#endif  

            //#ifdef APP-PLUS  
            let byteCommand = plus.android.invoke(content, 'getBytes', 'gb18030');  
            for (var i = 0; i < byteCommand.length; ++i) {  
                command.push(byteCommand[i])  
            }  
            //#endif  

            console.log('command--:', content)  
            rawCommand += content  
        }  

        function intToByte(i) {  
            // 此处关键 -- android是java平台 byte数值范围是 [-128, 127]  
            // 因为java平台的byte类型是有符号的 最高位表示符号,所以数值范围固定  
            // 而图片计算出来的是数值是 0 -255 属于int类型  
            // 所以把int 转换成byte类型   
            //#ifdef APP-PLUS  
            var b = i & 0xFF;  
            var c = 0;  
            if (b >= 128) {  
                c = b % 128;  
                c = -1 * (128 - c);  
            } else {  
                c = b;  
            }  
            return c  
            //#endif  
            // 而微信小程序不需要,因为小程序api接收的是 无符号8位  
            //#ifdef MP-WEIXIN  
            return i  
            //#endif  
        }  
        jpPrinter.setPostfeed = function (length) { //打印之后走纸距离指令  
            data = "POSTFEED " +length + "\r\n";  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setSize = function (pageWidght, pageHeight) { //设置页面大小  
            data = "SIZE " + pageWidght.toString() + " mm" + "," + pageHeight.toString() + " mm" + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setSpeed = function (printSpeed) { //设置打印机速度  
            data = "SPEED " + printSpeed.toString() + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setDensity = function (printDensity) { //设置打印机浓度  
            data = "DENSITY " + printDensity.toString() + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setGap = function (printGap) { //传感器  
            data = "GAP " + printGap.toString() + " mm\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setCountry = function (country) { //选择国际字符集  
            /*  
            001:USA  
            002:French  
            003:Latin America  
            034:Spanish  
            039:Italian  
            044:United Kingdom  
            046:Swedish  
            047:Norwegian  
            049:German  
             */  
            data = "COUNTRY " + country + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setCodepage = function (codepage) { //选择国际代码页  
            /*  
            8-bit codepage 字符集代表  
            437:United States  
            850:Multilingual  
            852:Slavic  
            860:Portuguese  
            863:Canadian/French  
            865:Nordic  
            Windows code page  
            1250:Central Europe  
            1252:Latin I  
            1253:Greek  
            1254:Turkish  
            以下代码页仅限于 12×24 dot 英数字体  
            WestEurope:WestEurope  
            Greek:Greek  
            Hebrew:Hebrew  
            EastEurope:EastEurope  
            Iran:Iran  
            IranII:IranII  
            Latvian:Latvian  
            Arabic:Arabic  
            Vietnam:Vietnam  
            Uygur:Uygur  
            Thai:Thai  
            1252:Latin I  
            1257:WPC1257  
            1251:WPC1251  
            866:Cyrillic  
            858:PC858  
            747:PC747  
            864:PC864  
            1001:PC100  
            */  
            data = "CODEPAGE " + codepage + "\r\n";  
            jpPrinter.addCommand(data)  
        }  

        jpPrinter.setCls = function () { //清除打印机缓存  
            data = "CLS " + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setFeed = function (feed) { //将纸向前推出n  
            data = "FEED " + feed + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setBackFeed = function (backup) { //将纸向后回拉n  
            data = "BACKFEED " + backup + "\r\n";  
            jpPrinter.addCommand(data)  
        }  

        jpPrinter.setDirection = function (direction) { //设置打印方向,参考编程手册    
            data = "DIRECTION " + direction + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setReference = function (x, y) { //设置坐标原点,与打印方向有关  
            data = "REFERENCE " + x + "," + y + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setFrom = function () { //定位控制指令  
            data = "FORM \r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setFromfeed = function () { //根据Size进一张标签纸  
            data = "FORMFEED \r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setHome = function () { //根据Size找到下一张标签纸的位置  
            data = "HOME \r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setSound = function (level, interval) { //控制蜂鸣器  
            data = "SOUND " + level + "," + interval + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setLimitfeed = function (limit) { // 检测垂直间距  
            data = "LIMITFEED " + limit + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setBar = function (x, y, width, height) { //绘制线条  
            data = "BAR " + x + "," + y + "," + width + "," + height + "\r\n"  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setBox = function (x_start, y_start, x_end, y_end, thickness) { //绘制方框  
            data = "BOX " + x_start + "," + y_start + "," + x_end + "," + y_end + "," + thickness + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setErase = function (x_start, y_start, x_width, y_height) { //清除指定区域的数据  
            data = "ERASE " + x_start + "," + y_start + "," + x_width + "," + y_height + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setReverse = function (x_start, y_start, x_width, y_height) { //将指定的区域反相打印  
            data = "REVERSE " + x_start + "," + y_start + "," + x_width + "," + y_height + "\r\n";  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setText1 = function (font, s, x, y, str) { //打印文字  
            data = "TEXT " + font + " " + s + " " + x + " " + y + "  " + str + "\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setText = function (x, y, font, x_, y_, str) { //打印文字  
            data = "TEXT " + x + "," + y + ",\"" + font + "\"," + 0 + "," + x_ + "," + y_ + "," + "\"" +  
                str + "\"\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setMag = function (w,h) { //打印二维码  
            data = "SETMAG " + w + " " + h + "\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setQR = function (x, y, m, u, content) { //打印二维码  
            data = "BARCODE QR " + x + " " + y + " M " + m + " U " + u + "\r\n MA," + content + "\r\nENDQR\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setPDF = function (type, x, y,xd,yd,c,s, content) { //打印条形  
            data = "BARCODE " + type + " " + x + " " + y + " XD " + xd + " YD " + yd + " C " + c + " S " + s + "\r\n"+ content+ "\r\nENDPDF\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setBarCode = function (type, w, r, h, x, y, content) { //打印条形码  
            data = "BARCODE " + type + " " + w + " " + r + " " + h + " " + x + " " + y + " " + content + "\r\n"  
            jpPrinter.addCommand(data)  
        };  

        // 固定灰度阈值(128以上的都看作白色)  
        jpPrinter.setBitmap = function (x, y, mode, res) { //添加图片,res为画布参数  
            var width = parseInt((res.width) / 8 * 8 / 8)  
            var height = res.height  
            var imgWidth = res.width  
            var time = 1;  
            var temp = res.data.length - width * 32;  
            var pointList = []  
            var resultData = []  
            console.log(width + "--" + height)  
            data = "BITMAP " + x + "," + y + "," + width + "," + height + "," + mode + ","  
            jpPrinter.addCommand(data)  
            //console.log(res.data)  
            console.log('---以上是原始数据---')  

            //for循环顺序不要错了,外层遍历高度,内层遍历宽度,因为横向每8个像素点组成一个字节  
            for (var y = 0; y < height; y++) {  
                for (var x = 0; x < imgWidth; x++) {  
                    let r = res.data[(y * imgWidth + x) * 4];  
                    let g = res.data[(y * imgWidth + x) * 4 + 1];  
                    let b = res.data[(y * imgWidth + x) * 4 + 2];  
                    let a = res.data[(y * imgWidth + x) * 4 + 3]  
                    //console.log(`当前${y}行${x}列像素,rgba值:(${r},${g},${b},${a})`)  
                    // 像素灰度值  
                    let grayColor = r * 0.299 + g * 0.587 + b * 0.114  
                    //灰度值大于128位   
                    //1不打印, 0打印 (参考:佳博标签打印机编程手册tspl)  
                    if (grayColor > 128) {  
                        pointList.push(1)  
                    } else {  
                        pointList.push(0)  
                    }  
                }  
            }  
            //console.log(pointList)  
            for (var i = 0; i < pointList.length; i += 8) {  
                var p = pointList[i] * 128 + pointList[i + 1] * 64 + pointList[i + 2] * 32 + pointList[i +  
                    3] * 16 + pointList[i + 4] * 8 + pointList[i + 5] * 4 + pointList[i + 6] * 2 +  
                    pointList[i + 7]  
                resultData.push(p)  
            }  
            console.log('最终数据:')  
            //console.log(resultData)  
            for (var i = 0; i < resultData.length; ++i) {  
                command.push(intToByte(resultData[i]))  
            }  
        }  

        jpPrinter.setBitmap2 = function (x, y, mode, res) { //添加图片,res为画布参数  
            var w = res.width  
            var width = parseInt((res.width + 7) / 8 * 8 / 8)  
            var height = res.height;  
            console.log(width + "--" + height)  
            data = "BITMAP " + x + "," + y + "," + width + "," + height + "," + mode + ","  
            jpPrinter.addCommand(data)  
            var r = []  
            var bits = new Uint8Array(height * width);  
            for (y = 0; y < height; y++) {  
                for (x = 0; x < w; x++) {  
                    let r = res.data[(y * w + x) * 4];  
                    let g = res.data[(y * w + x) * 4 + 1];  
                    let b = res.data[(y * w + x) * 4 + 2];  
                    let a = res.data[(y * w + x) * 4 + 3]  
                    var color = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) <<  
                        0);  
                    if ((color & 0xFF) > 128) {  
                        bits[parseInt(y * width + x / 8)] |= (0x80 >> (x % 8));  
                    }  
                }  
            }  
            for (var i = 0; i < bits.length; i++) {  
                //command.push((~bits[i]) & 0xFF);  
                command.push(intToByte(bits[i]));  
                //r.push((~bits[i]) & 0xFF);  
            }  
        }  

        // 平均灰度阈值(先计算平均灰度,然后大于平均灰度的都算作白色)  
        jpPrinter.setBitmap3 = function (x, y, mode, res) { //添加图片,res为画布参数  
            var width = parseInt((res.width) / 8 * 8 / 8)  
            var height = res.height  
            var imgWidth = res.width  
            var time = 1;  
            var temp = res.data.length - width * 32;  
            var pointList = []  
            var resultData = []  
            console.log(width + "--" + height)  
            data = "BITMAP " + x + "," + y + "," + width + "," + height + "," + mode + ","  
            jpPrinter.addCommand(data)  
            //console.log(res.data)  
            console.log('---以上是原始数据---')  

            let sumRed = 0,  
                sumGreen = 0,  
                sumBlue = 0;  
            let total = height * imgWidth;  
            let pix = res.data;  
            for (var i = 0; i < pix.length; i += 4) {  
                sumRed += pix[i]  
                sumGreen += pix[i + 1]  
                sumBlue += pix[i + 2]  
            }  

            let avgRed = parseInt(sumRed / total);  
            let avgGreen = parseInt(sumGreen / total);  
            let avgBlue = parseInt(sumBlue / total);  
            let avgGrayColor = avgRed * 0.299 + avgGreen * 0.587 + avgBlue * 0.114  

            //for循环顺序不要错了,外层遍历高度,内层遍历宽度,因为横向每8个像素点组成一个字节  
            for (var y = 0; y < height; y++) {  
                for (var x = 0; x < imgWidth; x++) {  
                    let r = res.data[(y * imgWidth + x) * 4];  
                    let g = res.data[(y * imgWidth + x) * 4 + 1];  
                    let b = res.data[(y * imgWidth + x) * 4 + 2];  
                    let a = res.data[(y * imgWidth + x) * 4 + 3]  
                    // 像素灰度值  
                    let grayColor = r * 0.299 + g * 0.587 + b * 0.114  
                    //灰度值大于128位   
                    //1不打印, 0打印 (参考:佳博标签打印机编程手册tspl)  
                    if (grayColor > avgGrayColor) {  
                        pointList.push(1)  
                    } else {  
                        pointList.push(0)  
                    }  
                }  
            }  
            //console.log(pointList)  
            for (var i = 0; i < pointList.length; i += 8) {  
                var p = pointList[i] * 128 + pointList[i + 1] * 64 + pointList[i + 2] * 32 + pointList[i +  
                    3] * 16 + pointList[i + 4] * 8 + pointList[i + 5] * 4 + pointList[i + 6] * 2 +  
                    pointList[i + 7]  
                resultData.push(p)  

            }  
            console.log('最终数据:')  
            //console.log(resultData)  
            for (var i = 0; i < resultData.length; ++i) {  
                command.push(intToByte(resultData[i]))  
            }  
        }  

        jpPrinter.RawCommand = function (data) {  
            jpPrinter.addCommand(data)  
        }  

        jpPrinter.setPagePrint = function () { //打印页面  
            // data = "PRINT 1,1\r\n"  
            data = "PRINT \r\n"  
            jpPrinter.addCommand(data)  
        };  
        //获取打印数据  
        jpPrinter.getData = function () {  
            return command;  
        };  

        jpPrinter.getRawData = function () {  
            return rawCommand;  
        };  
        jpPrinter.clearCommand = function () {  
            rawCommand = ''  
        };  

        return jpPrinter;  
    }  
};  

module.exports.jpPrinter = jpPrinter;  
继续阅读 »
  1. 打印机,需要插usb(或者微信小程序设置wifi)
  2. 打印机的默认端口是9100(一般是,具体看购买的打印机)
  3. wifitool.js是用于连接打印机的
  4. 此文章是用的CPCL指令,可以根据自己的指令格式修改(var command = tsc.jpPrinter.createNew();)
    vue

    <template>  
    <view>  
    <button @click="printSocket">WiFi打印</button>  
    </view>  
    </template>

    js

    
    <script>  
    import tsc from "@/static/libs/tsc.js";  
    import wifiTool from "@/static/libs/WifiTool.js";  
    export default {  
    data() {  
    return {  
      ip: "192.168.4.245",  
      port: 9100,  
      str: "yyy",  
    };  
    },  
    mounted() {  
    wifiTool.connectWifi("192.168.4.245", 9100);  
    },  
    methods: {  
    test(str, ip, port) {  
      str = "test";  
      var Socket = plus.android.importClass("java.net.Socket");  
      var JavaByte = plus.android.importClass("java.lang.Byte");  
      var PrintWriter = plus.android.importClass("java.io.PrintWriter");  
      var BufferedWriter = plus.android.importClass("java.io.BufferedWriter");  
      var OutputStreamWriter = plus.android.importClass("java.io.OutputStreamWriter");  
      var BufferedReader = plus.android.importClass("java.io.BufferedReader");  
      var InputStreamReader = plus.android.importClass("java.io.InputStreamReader");  
    
      //测试改良  
      var StrictMode = plus.android.importClass("android.os.StrictMode");  
      var Build = plus.android.importClass("android.os.Build");  
      if (Build.VERSION.SDK_INT > 9) {  
        var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();  
        StrictMode.setThreadPolicy(policy);  
      }  
      var socket = new Socket(ip, port);  
    
      var outputStreamWriter = new OutputStreamWriter(socket.getOutputStream());  
      var bufferWriter = new BufferedWriter(outputStreamWriter);  
      var out = new PrintWriter(bufferWriter, true);  
    
      var command = tsc.jpPrinter.createNew();  
      command.init(0, 200, 200, 210, 1);  
      command.setCls();  
      command.setQR(30, 40, 2, 6, "123");  
      //   command.setMag(2, 2);  
      //   command.setText1(55, 30, 180, 60, "地址: 内蒙");  
      //   command.setMag(2, 2);  
      //   command.setText1(55, 6, 180, 120, "重量: 15kg");  
      command.setPagePrint();  
      let data = command.getData();  
    
      out.println(data);  
      socket.setSoTimeout(3000);  
      socket.close();  
    },  
    printSocket() {  
      var command = tsc.jpPrinter.createNew();  
      command.init(0, 200, 250, 210, 1);  
      command.setCls();  
      command.setQR(30, 40, 2, 6, "123");  
      command.setMag(2, 2);  
      command.setText1(55, 30, 180, 60, "地址: 内蒙");  
      command.setMag(2, 2);  
      command.setText1(55, 6, 180, 120, "重量: 15kg");  
      command.setPostfeed(32);//打印后走纸  
      command.setPagePrint();  
      let data = command.getData();  
      wifiTool.sendData(data);  
    },  
    connectWifi(ip, port) {  
      if (plus.os.name == "Android") {  
        // plus.nativeUI.showWaiting("正在打印中。。。");  
        var Socket = plus.android.importClass("java.net.Socket");  
        var socket;  
        var outputStream;  
        //解决高低版本兼容  
        var StrictMode = plus.android.importClass("android.os.StrictMode");  
        var Build = plus.android.importClass("android.os.Build");  
        if (Build.VERSION.SDK_INT > 9) {  
          var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();  
          StrictMode.setThreadPolicy(policy);  
        }  
        try {  
          socket = new Socket(ip, port);  
          socket.setKeepAlive(true);  
          outputStream = socket.getOutputStream();  
          plus.android.importClass(outputStream);  
          //   var bytes = plus.android.invoke(str, "getBytes", "gbk");  
          uni.showToast({  
            title: "wifi连接成功",  
          });  
    
          //   plus.nativeUI.closeWaiting();  
        } catch (e) {  
          console.log("网络连接超时,请重新连接!");  
          //TODO handle the exception  
          //   plus.nativeUI.closeWaiting();  
        }  
      }  
    },  
    },  
    };  
    </script>  
WifiTool.js  

```javascript  

/**  
 * 初始化参数  
 */  
//#ifdef APP-PLUS  
var Socket = plus.android.importClass("java.net.Socket");  
var socket;  
var outputStream;  
//解决高低版本兼容  
var StrictMode = plus.android.importClass("android.os.StrictMode");  
var Build = plus.android.importClass("android.os.Build");  
//#endif  
/**  
 * 构造对象  
 */  
var wifiTool = {  
    connectWifi(ip, port) {  
        if (Build.VERSION.SDK_INT > 9) {  
            var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();  
            StrictMode.setThreadPolicy(policy);  
        }  
        try {  
            socket = new Socket(ip, port);  
            socket.setKeepAlive(true);  
            outputStream = socket.getOutputStream();  
            plus.android.importClass(outputStream);  
            //   var bytes = plus.android.invoke(str, "getBytes", "gbk");  
            uni.showToast({  
                title: 'wifi连接成功',  
            });  

            //   plus.nativeUI.closeWaiting();  
        } catch (e) {  
            console.log("网络连接超时,请重新连接!")  
            //TODO handle the exception  
            //   plus.nativeUI.closeWaiting();  
        }  
    },  
    sendData(data) {  

        console.log(outputStream);  
        outputStream.write(data);  
        outputStream.flush();  
        // 关闭socket  
        // socket.shutdownOutput();  
        console.log(socket);  
    }  
}  

module.exports = wifiTool

tsc.js

/**  
 * tsc 命令打印工具类  
 * 2021.04.26 uni-app版本  
 * @auth boolTrue  
 */  
var encode = require("./encoding.js");  
var jpPrinter = {  
    createNew: function () {  
        var jpPrinter = {};  
        var data = "";  
        var command = []  
        var rawCommand = ''  

        jpPrinter.name = "标签模式";  

        jpPrinter.init = function (x, y, z, h, q) {  
            data = "! " + x + " " + y + " " + z + " " + h + " " + q + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.addCommand = function (content) { //将指令转成数组装起  
            //#ifdef MP-WEIXIN  
            var code = new encode.TextEncoder(  
                'gb18030', {  
                NONSTANDARD_allowLegacyEncoding: true  
            }).encode(content)  
            for (var i = 0; i < code.length; ++i) {  
                command.push(code[i])  
            }  
            //#endif  

            //#ifdef APP-PLUS  
            let byteCommand = plus.android.invoke(content, 'getBytes', 'gb18030');  
            for (var i = 0; i < byteCommand.length; ++i) {  
                command.push(byteCommand[i])  
            }  
            //#endif  

            console.log('command--:', content)  
            rawCommand += content  
        }  

        function intToByte(i) {  
            // 此处关键 -- android是java平台 byte数值范围是 [-128, 127]  
            // 因为java平台的byte类型是有符号的 最高位表示符号,所以数值范围固定  
            // 而图片计算出来的是数值是 0 -255 属于int类型  
            // 所以把int 转换成byte类型   
            //#ifdef APP-PLUS  
            var b = i & 0xFF;  
            var c = 0;  
            if (b >= 128) {  
                c = b % 128;  
                c = -1 * (128 - c);  
            } else {  
                c = b;  
            }  
            return c  
            //#endif  
            // 而微信小程序不需要,因为小程序api接收的是 无符号8位  
            //#ifdef MP-WEIXIN  
            return i  
            //#endif  
        }  
        jpPrinter.setPostfeed = function (length) { //打印之后走纸距离指令  
            data = "POSTFEED " +length + "\r\n";  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setSize = function (pageWidght, pageHeight) { //设置页面大小  
            data = "SIZE " + pageWidght.toString() + " mm" + "," + pageHeight.toString() + " mm" + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setSpeed = function (printSpeed) { //设置打印机速度  
            data = "SPEED " + printSpeed.toString() + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setDensity = function (printDensity) { //设置打印机浓度  
            data = "DENSITY " + printDensity.toString() + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setGap = function (printGap) { //传感器  
            data = "GAP " + printGap.toString() + " mm\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setCountry = function (country) { //选择国际字符集  
            /*  
            001:USA  
            002:French  
            003:Latin America  
            034:Spanish  
            039:Italian  
            044:United Kingdom  
            046:Swedish  
            047:Norwegian  
            049:German  
             */  
            data = "COUNTRY " + country + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setCodepage = function (codepage) { //选择国际代码页  
            /*  
            8-bit codepage 字符集代表  
            437:United States  
            850:Multilingual  
            852:Slavic  
            860:Portuguese  
            863:Canadian/French  
            865:Nordic  
            Windows code page  
            1250:Central Europe  
            1252:Latin I  
            1253:Greek  
            1254:Turkish  
            以下代码页仅限于 12×24 dot 英数字体  
            WestEurope:WestEurope  
            Greek:Greek  
            Hebrew:Hebrew  
            EastEurope:EastEurope  
            Iran:Iran  
            IranII:IranII  
            Latvian:Latvian  
            Arabic:Arabic  
            Vietnam:Vietnam  
            Uygur:Uygur  
            Thai:Thai  
            1252:Latin I  
            1257:WPC1257  
            1251:WPC1251  
            866:Cyrillic  
            858:PC858  
            747:PC747  
            864:PC864  
            1001:PC100  
            */  
            data = "CODEPAGE " + codepage + "\r\n";  
            jpPrinter.addCommand(data)  
        }  

        jpPrinter.setCls = function () { //清除打印机缓存  
            data = "CLS " + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setFeed = function (feed) { //将纸向前推出n  
            data = "FEED " + feed + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setBackFeed = function (backup) { //将纸向后回拉n  
            data = "BACKFEED " + backup + "\r\n";  
            jpPrinter.addCommand(data)  
        }  

        jpPrinter.setDirection = function (direction) { //设置打印方向,参考编程手册    
            data = "DIRECTION " + direction + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setReference = function (x, y) { //设置坐标原点,与打印方向有关  
            data = "REFERENCE " + x + "," + y + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setFrom = function () { //定位控制指令  
            data = "FORM \r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setFromfeed = function () { //根据Size进一张标签纸  
            data = "FORMFEED \r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setHome = function () { //根据Size找到下一张标签纸的位置  
            data = "HOME \r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setSound = function (level, interval) { //控制蜂鸣器  
            data = "SOUND " + level + "," + interval + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setLimitfeed = function (limit) { // 检测垂直间距  
            data = "LIMITFEED " + limit + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setBar = function (x, y, width, height) { //绘制线条  
            data = "BAR " + x + "," + y + "," + width + "," + height + "\r\n"  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setBox = function (x_start, y_start, x_end, y_end, thickness) { //绘制方框  
            data = "BOX " + x_start + "," + y_start + "," + x_end + "," + y_end + "," + thickness + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setErase = function (x_start, y_start, x_width, y_height) { //清除指定区域的数据  
            data = "ERASE " + x_start + "," + y_start + "," + x_width + "," + y_height + "\r\n";  
            jpPrinter.addCommand(data)  
        };  

        jpPrinter.setReverse = function (x_start, y_start, x_width, y_height) { //将指定的区域反相打印  
            data = "REVERSE " + x_start + "," + y_start + "," + x_width + "," + y_height + "\r\n";  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setText1 = function (font, s, x, y, str) { //打印文字  
            data = "TEXT " + font + " " + s + " " + x + " " + y + "  " + str + "\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setText = function (x, y, font, x_, y_, str) { //打印文字  
            data = "TEXT " + x + "," + y + ",\"" + font + "\"," + 0 + "," + x_ + "," + y_ + "," + "\"" +  
                str + "\"\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setMag = function (w,h) { //打印二维码  
            data = "SETMAG " + w + " " + h + "\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setQR = function (x, y, m, u, content) { //打印二维码  
            data = "BARCODE QR " + x + " " + y + " M " + m + " U " + u + "\r\n MA," + content + "\r\nENDQR\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setPDF = function (type, x, y,xd,yd,c,s, content) { //打印条形  
            data = "BARCODE " + type + " " + x + " " + y + " XD " + xd + " YD " + yd + " C " + c + " S " + s + "\r\n"+ content+ "\r\nENDPDF\r\n"  
            jpPrinter.addCommand(data)  
        };  
        jpPrinter.setBarCode = function (type, w, r, h, x, y, content) { //打印条形码  
            data = "BARCODE " + type + " " + w + " " + r + " " + h + " " + x + " " + y + " " + content + "\r\n"  
            jpPrinter.addCommand(data)  
        };  

        // 固定灰度阈值(128以上的都看作白色)  
        jpPrinter.setBitmap = function (x, y, mode, res) { //添加图片,res为画布参数  
            var width = parseInt((res.width) / 8 * 8 / 8)  
            var height = res.height  
            var imgWidth = res.width  
            var time = 1;  
            var temp = res.data.length - width * 32;  
            var pointList = []  
            var resultData = []  
            console.log(width + "--" + height)  
            data = "BITMAP " + x + "," + y + "," + width + "," + height + "," + mode + ","  
            jpPrinter.addCommand(data)  
            //console.log(res.data)  
            console.log('---以上是原始数据---')  

            //for循环顺序不要错了,外层遍历高度,内层遍历宽度,因为横向每8个像素点组成一个字节  
            for (var y = 0; y < height; y++) {  
                for (var x = 0; x < imgWidth; x++) {  
                    let r = res.data[(y * imgWidth + x) * 4];  
                    let g = res.data[(y * imgWidth + x) * 4 + 1];  
                    let b = res.data[(y * imgWidth + x) * 4 + 2];  
                    let a = res.data[(y * imgWidth + x) * 4 + 3]  
                    //console.log(`当前${y}行${x}列像素,rgba值:(${r},${g},${b},${a})`)  
                    // 像素灰度值  
                    let grayColor = r * 0.299 + g * 0.587 + b * 0.114  
                    //灰度值大于128位   
                    //1不打印, 0打印 (参考:佳博标签打印机编程手册tspl)  
                    if (grayColor > 128) {  
                        pointList.push(1)  
                    } else {  
                        pointList.push(0)  
                    }  
                }  
            }  
            //console.log(pointList)  
            for (var i = 0; i < pointList.length; i += 8) {  
                var p = pointList[i] * 128 + pointList[i + 1] * 64 + pointList[i + 2] * 32 + pointList[i +  
                    3] * 16 + pointList[i + 4] * 8 + pointList[i + 5] * 4 + pointList[i + 6] * 2 +  
                    pointList[i + 7]  
                resultData.push(p)  
            }  
            console.log('最终数据:')  
            //console.log(resultData)  
            for (var i = 0; i < resultData.length; ++i) {  
                command.push(intToByte(resultData[i]))  
            }  
        }  

        jpPrinter.setBitmap2 = function (x, y, mode, res) { //添加图片,res为画布参数  
            var w = res.width  
            var width = parseInt((res.width + 7) / 8 * 8 / 8)  
            var height = res.height;  
            console.log(width + "--" + height)  
            data = "BITMAP " + x + "," + y + "," + width + "," + height + "," + mode + ","  
            jpPrinter.addCommand(data)  
            var r = []  
            var bits = new Uint8Array(height * width);  
            for (y = 0; y < height; y++) {  
                for (x = 0; x < w; x++) {  
                    let r = res.data[(y * w + x) * 4];  
                    let g = res.data[(y * w + x) * 4 + 1];  
                    let b = res.data[(y * w + x) * 4 + 2];  
                    let a = res.data[(y * w + x) * 4 + 3]  
                    var color = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) <<  
                        0);  
                    if ((color & 0xFF) > 128) {  
                        bits[parseInt(y * width + x / 8)] |= (0x80 >> (x % 8));  
                    }  
                }  
            }  
            for (var i = 0; i < bits.length; i++) {  
                //command.push((~bits[i]) & 0xFF);  
                command.push(intToByte(bits[i]));  
                //r.push((~bits[i]) & 0xFF);  
            }  
        }  

        // 平均灰度阈值(先计算平均灰度,然后大于平均灰度的都算作白色)  
        jpPrinter.setBitmap3 = function (x, y, mode, res) { //添加图片,res为画布参数  
            var width = parseInt((res.width) / 8 * 8 / 8)  
            var height = res.height  
            var imgWidth = res.width  
            var time = 1;  
            var temp = res.data.length - width * 32;  
            var pointList = []  
            var resultData = []  
            console.log(width + "--" + height)  
            data = "BITMAP " + x + "," + y + "," + width + "," + height + "," + mode + ","  
            jpPrinter.addCommand(data)  
            //console.log(res.data)  
            console.log('---以上是原始数据---')  

            let sumRed = 0,  
                sumGreen = 0,  
                sumBlue = 0;  
            let total = height * imgWidth;  
            let pix = res.data;  
            for (var i = 0; i < pix.length; i += 4) {  
                sumRed += pix[i]  
                sumGreen += pix[i + 1]  
                sumBlue += pix[i + 2]  
            }  

            let avgRed = parseInt(sumRed / total);  
            let avgGreen = parseInt(sumGreen / total);  
            let avgBlue = parseInt(sumBlue / total);  
            let avgGrayColor = avgRed * 0.299 + avgGreen * 0.587 + avgBlue * 0.114  

            //for循环顺序不要错了,外层遍历高度,内层遍历宽度,因为横向每8个像素点组成一个字节  
            for (var y = 0; y < height; y++) {  
                for (var x = 0; x < imgWidth; x++) {  
                    let r = res.data[(y * imgWidth + x) * 4];  
                    let g = res.data[(y * imgWidth + x) * 4 + 1];  
                    let b = res.data[(y * imgWidth + x) * 4 + 2];  
                    let a = res.data[(y * imgWidth + x) * 4 + 3]  
                    // 像素灰度值  
                    let grayColor = r * 0.299 + g * 0.587 + b * 0.114  
                    //灰度值大于128位   
                    //1不打印, 0打印 (参考:佳博标签打印机编程手册tspl)  
                    if (grayColor > avgGrayColor) {  
                        pointList.push(1)  
                    } else {  
                        pointList.push(0)  
                    }  
                }  
            }  
            //console.log(pointList)  
            for (var i = 0; i < pointList.length; i += 8) {  
                var p = pointList[i] * 128 + pointList[i + 1] * 64 + pointList[i + 2] * 32 + pointList[i +  
                    3] * 16 + pointList[i + 4] * 8 + pointList[i + 5] * 4 + pointList[i + 6] * 2 +  
                    pointList[i + 7]  
                resultData.push(p)  

            }  
            console.log('最终数据:')  
            //console.log(resultData)  
            for (var i = 0; i < resultData.length; ++i) {  
                command.push(intToByte(resultData[i]))  
            }  
        }  

        jpPrinter.RawCommand = function (data) {  
            jpPrinter.addCommand(data)  
        }  

        jpPrinter.setPagePrint = function () { //打印页面  
            // data = "PRINT 1,1\r\n"  
            data = "PRINT \r\n"  
            jpPrinter.addCommand(data)  
        };  
        //获取打印数据  
        jpPrinter.getData = function () {  
            return command;  
        };  

        jpPrinter.getRawData = function () {  
            return rawCommand;  
        };  
        jpPrinter.clearCommand = function () {  
            rawCommand = ''  
        };  

        return jpPrinter;  
    }  
};  

module.exports.jpPrinter = jpPrinter;  
收起阅读 »

蓝牙连接便携式打印机(芝柯)

蓝牙打印

vue

<template>  
  <view>  
    <button @click="searchBle">搜索蓝牙</button>  
    <view style="margin-top: 30upx" :key="index" v-for="(item, index) in devices">  
      <button style="width: 400upx; color: #0081ff" @click="onConn(item)">  
        {{ item.name }}  
      </button>  
    </view>  
    <button style="margin-top: 100upx" @click="senBleLabel()">标签打印</button>  
  </view>  
</template>  

js


<script>  
import tsc from "@/static/libs/tsc.js";  
import bluetoothTool from "@/static/libs/BluetoothTool.js";  

export default {  
  data() {  
    return {  
      devices: [],  
      currDev: null,  
      connId: "",  
      piaojuText: "",  

      tableDomId: "",  
      tableImgPath: "",  

      canvasWidth: 80,  
      canvasHeight: 60,  

      msg: "",  
      count: 0,  
    };  
  },  
  watch: {  
    msg() {  
      uni.showToast({  
        title: this.msg,  
      });  
    },  
  },  
  onReady() {  
    this.renderCanvas();  
  },  
  mounted() {  
    //#ifdef APP-PLUS  
    // 蓝牙  
    bluetoothTool.init({  
      listenBTStatusCallback: (state) => {  
        if (state == "STATE_ON") {  
          let lastBleAddress = uni.getStorageSync("lastBleAddress");  
          if (lastBleAddress) {  
            uni.showLoading({  
              title: "正在连接...",  
            });  
            console.log(lastBleAddress);  
            bluetoothTool.connDevice(lastBleAddress, (result) => {  
              uni.hideLoading();  
              uni.showToast({  
                title: result ? "连接成功!" : "连接失败...",  
              });  
              let _this = this;  

              let countSet = setInterval(() => {  
                if (_this.count == 5) {  
                  clearInterval(countSet);  
                } else {  
                  _this.count  ;  
                  _this.senBleLabel();  
                }  
              }, 2000);  
            });  
          }  
        }  
      },  
      discoveryDeviceCallback: this.onDevice,  
      discoveryFinishedCallback: function () {  
        that.msg = "搜索完成";  
      },  
      readDataCallback: function (dataByteArr) {  
        // 读取蓝牙返回的数据  
        /* if(that.receiveDataArr.length >= 200) {  
                            that.receiveDataArr = [];  
                        }  
                        that.receiveDataArr.push.apply(that.receiveDataArr, dataByteArr); */  
      },  
      connExceptionCallback: function (e) {  
        console.log(e);  
        that.msg = "设备连接失败";  
      },  
    });  
    //#endif  
  },  
  methods: {  
    destroyed: function () {  
      console.log("destroyed----------");  
      if (this.connId != "") {  
        uni.closeBLEConnection({  
          deviceId: this.connId,  
          success(res) {  
            console.log(res);  
          },  
        });  
      }  
    },  
    searchBle() {  
      var that = this;  
      console.log("initBule");  
      // 使用openBluetoothAdapter 接口,免去主动申请权限的麻烦  
      uni.openBluetoothAdapter({  
        success(res) {  
          this.devices = [];  
          console.log("打开 蓝牙模块,开始搜索模式...");  
          console.log(res);  
          bluetoothTool.discoveryNewDevice();  
          //that.onDevice()  
        },  
      });  
    },  
    onDevice(newDevice) {  
      console.log("监听寻找到新设备的事件---------------");  
      console.log(newDevice);  
      if (newDevice.name && newDevice.name != "null") {  
        this.devices.push({  
          name: newDevice.name,  
          address: newDevice.address,  
        });  
      }  
    },  
 stopFindBule() {  
      console.log("停止搜寻附近的蓝牙外围设备---------------");  
      uni.stopBluetoothDevicesDiscovery({  
        success(res) {  
          console.log(res);  
        },  
      });  
    },  
    onConn(item) {  
      console.log("连接蓝牙---------------" + item.address);  

      if (this.selectDevices.includes(item.address)) {  
        that.msg = "该蓝牙已连接";  
      }  
      bluetoothTool.connDevice(item.address, (result) => {  
        if (result) {  
          if (this.selectDevices.length == 3) {  
            this.selectDevices.shift();  
          }  
          this.selectDevices.push(item);  
          uni.setStorageSync("selectDevices", this.selectDevices);  
        }  
        console.log("连接结果:", result);  
      });  
    },  
    senBleLabel() {  
      var command = tsc.jpPrinter.createNew();  
      command.init(0, 200, 200, 210, 1);  
      command.setCls();  
      command.setQR(30, 40, 2, 6, "123");  
      command.setMag(2, 2);  
      command.setText1(55, 30, 180, 60, "地址: 内蒙");  
      command.setMag(2, 2);  
      command.setText1(55, 6, 180, 120, "重量: 15kg");  
      command.setPagePrint();  
      let data = command.getData();  
      bluetoothTool.sendByteData(data);  
    },  
  },  
};  
</script>
继续阅读 »

vue

<template>  
  <view>  
    <button @click="searchBle">搜索蓝牙</button>  
    <view style="margin-top: 30upx" :key="index" v-for="(item, index) in devices">  
      <button style="width: 400upx; color: #0081ff" @click="onConn(item)">  
        {{ item.name }}  
      </button>  
    </view>  
    <button style="margin-top: 100upx" @click="senBleLabel()">标签打印</button>  
  </view>  
</template>  

js


<script>  
import tsc from "@/static/libs/tsc.js";  
import bluetoothTool from "@/static/libs/BluetoothTool.js";  

export default {  
  data() {  
    return {  
      devices: [],  
      currDev: null,  
      connId: "",  
      piaojuText: "",  

      tableDomId: "",  
      tableImgPath: "",  

      canvasWidth: 80,  
      canvasHeight: 60,  

      msg: "",  
      count: 0,  
    };  
  },  
  watch: {  
    msg() {  
      uni.showToast({  
        title: this.msg,  
      });  
    },  
  },  
  onReady() {  
    this.renderCanvas();  
  },  
  mounted() {  
    //#ifdef APP-PLUS  
    // 蓝牙  
    bluetoothTool.init({  
      listenBTStatusCallback: (state) => {  
        if (state == "STATE_ON") {  
          let lastBleAddress = uni.getStorageSync("lastBleAddress");  
          if (lastBleAddress) {  
            uni.showLoading({  
              title: "正在连接...",  
            });  
            console.log(lastBleAddress);  
            bluetoothTool.connDevice(lastBleAddress, (result) => {  
              uni.hideLoading();  
              uni.showToast({  
                title: result ? "连接成功!" : "连接失败...",  
              });  
              let _this = this;  

              let countSet = setInterval(() => {  
                if (_this.count == 5) {  
                  clearInterval(countSet);  
                } else {  
                  _this.count  ;  
                  _this.senBleLabel();  
                }  
              }, 2000);  
            });  
          }  
        }  
      },  
      discoveryDeviceCallback: this.onDevice,  
      discoveryFinishedCallback: function () {  
        that.msg = "搜索完成";  
      },  
      readDataCallback: function (dataByteArr) {  
        // 读取蓝牙返回的数据  
        /* if(that.receiveDataArr.length >= 200) {  
                            that.receiveDataArr = [];  
                        }  
                        that.receiveDataArr.push.apply(that.receiveDataArr, dataByteArr); */  
      },  
      connExceptionCallback: function (e) {  
        console.log(e);  
        that.msg = "设备连接失败";  
      },  
    });  
    //#endif  
  },  
  methods: {  
    destroyed: function () {  
      console.log("destroyed----------");  
      if (this.connId != "") {  
        uni.closeBLEConnection({  
          deviceId: this.connId,  
          success(res) {  
            console.log(res);  
          },  
        });  
      }  
    },  
    searchBle() {  
      var that = this;  
      console.log("initBule");  
      // 使用openBluetoothAdapter 接口,免去主动申请权限的麻烦  
      uni.openBluetoothAdapter({  
        success(res) {  
          this.devices = [];  
          console.log("打开 蓝牙模块,开始搜索模式...");  
          console.log(res);  
          bluetoothTool.discoveryNewDevice();  
          //that.onDevice()  
        },  
      });  
    },  
    onDevice(newDevice) {  
      console.log("监听寻找到新设备的事件---------------");  
      console.log(newDevice);  
      if (newDevice.name && newDevice.name != "null") {  
        this.devices.push({  
          name: newDevice.name,  
          address: newDevice.address,  
        });  
      }  
    },  
 stopFindBule() {  
      console.log("停止搜寻附近的蓝牙外围设备---------------");  
      uni.stopBluetoothDevicesDiscovery({  
        success(res) {  
          console.log(res);  
        },  
      });  
    },  
    onConn(item) {  
      console.log("连接蓝牙---------------" + item.address);  

      if (this.selectDevices.includes(item.address)) {  
        that.msg = "该蓝牙已连接";  
      }  
      bluetoothTool.connDevice(item.address, (result) => {  
        if (result) {  
          if (this.selectDevices.length == 3) {  
            this.selectDevices.shift();  
          }  
          this.selectDevices.push(item);  
          uni.setStorageSync("selectDevices", this.selectDevices);  
        }  
        console.log("连接结果:", result);  
      });  
    },  
    senBleLabel() {  
      var command = tsc.jpPrinter.createNew();  
      command.init(0, 200, 200, 210, 1);  
      command.setCls();  
      command.setQR(30, 40, 2, 6, "123");  
      command.setMag(2, 2);  
      command.setText1(55, 30, 180, 60, "地址: 内蒙");  
      command.setMag(2, 2);  
      command.setText1(55, 6, 180, 120, "重量: 15kg");  
      command.setPagePrint();  
      let data = command.getData();  
      bluetoothTool.sendByteData(data);  
    },  
  },  
};  
</script>
收起阅读 »

在uniapp中使用lodash

lodash

众所周知,小程序的全局对象跟browser的全局对象不同,所以lodash使用browser全局对象下的api会报错。这就需要在uniapp中根据小程序环境引入polyfill。要特殊处理的东西不是很多,就是把Array,DataView等等这些api挂在到小程序环境下的global中。
大部分都会选择直接在项目中实现这个polyfill,那么问题又来了,在项目中定义的ployfill引入执行始终会在npm包之后。因为npm包会被打包到vendor中,这个包因为包含了uniapp的运行时,所以被提前导入。这样的话引入lodash,lodash初始化执行获取全局对象global对应api的时候,ployfill还没有被导入执行,所以还是会报错。想要解决这个问题,最好的方法就是使用npm包的ployfill并提前于lodash导入。
我自己已经构建发布了一个npm包 lodash-miniprogram-polyfill 可以直接使用。想要自己实现也可以,不过都需要发布成一个npm包。
使用的时候也有说法,因为ployfill必须要早于lodash初始化执行前被执行,所以推荐在一个文件中先导入ployfill,同时导入导出lodash的api,项目中使用的时候就直接从这个文件中导入lodash就行了,有类型推断的话也能保留。推荐使用lodash-es,这样可以按需导入,减少打包的体积。

示例

-/src/utils/lodashFix.ts

// #ifdef MP-WEIXIN  
import 'lodash-miniprogram-polyfill'  
// #endif  
export * from 'lodash-es'

-/src/pages/index/index.vue

<script setup lang="ts">  
import { throttle } from '@/utils/lodashFix'  
</script>
继续阅读 »

众所周知,小程序的全局对象跟browser的全局对象不同,所以lodash使用browser全局对象下的api会报错。这就需要在uniapp中根据小程序环境引入polyfill。要特殊处理的东西不是很多,就是把Array,DataView等等这些api挂在到小程序环境下的global中。
大部分都会选择直接在项目中实现这个polyfill,那么问题又来了,在项目中定义的ployfill引入执行始终会在npm包之后。因为npm包会被打包到vendor中,这个包因为包含了uniapp的运行时,所以被提前导入。这样的话引入lodash,lodash初始化执行获取全局对象global对应api的时候,ployfill还没有被导入执行,所以还是会报错。想要解决这个问题,最好的方法就是使用npm包的ployfill并提前于lodash导入。
我自己已经构建发布了一个npm包 lodash-miniprogram-polyfill 可以直接使用。想要自己实现也可以,不过都需要发布成一个npm包。
使用的时候也有说法,因为ployfill必须要早于lodash初始化执行前被执行,所以推荐在一个文件中先导入ployfill,同时导入导出lodash的api,项目中使用的时候就直接从这个文件中导入lodash就行了,有类型推断的话也能保留。推荐使用lodash-es,这样可以按需导入,减少打包的体积。

示例

-/src/utils/lodashFix.ts

// #ifdef MP-WEIXIN  
import 'lodash-miniprogram-polyfill'  
// #endif  
export * from 'lodash-es'

-/src/pages/index/index.vue

<script setup lang="ts">  
import { throttle } from '@/utils/lodashFix'  
</script>
收起阅读 »

不修改组件代码,uni-data-picker选择中间节点的方法

模板中添加事件

<uni-data-picker :step-searh="true" self-field="_id" parent-field="parent_id" v-model="formData.d_ids" collection="opendb-department" field="_id as value, name as text,parent_id" @nodeclick="nodeclick" @popupclosed="popupclosed"></uni-data-picker>

data()函数的return部分添加个变量

      return {  
        tempPdid:"",

方法中添加上面事件对应的方法

    methods: {  
      nodeclick(e){  
        this.tempPdid = e.value  
      },  
      popupclosed(){  
        this.formData.d_ids = this.tempPdid  // 这个例子是用户修改页,d_ids是uni-id-users表的部门字段  
      },

操作效果:点击任意节点,再点击选框之外,会自动关闭选框,选项即生效。

继续阅读 »

模板中添加事件

<uni-data-picker :step-searh="true" self-field="_id" parent-field="parent_id" v-model="formData.d_ids" collection="opendb-department" field="_id as value, name as text,parent_id" @nodeclick="nodeclick" @popupclosed="popupclosed"></uni-data-picker>

data()函数的return部分添加个变量

      return {  
        tempPdid:"",

方法中添加上面事件对应的方法

    methods: {  
      nodeclick(e){  
        this.tempPdid = e.value  
      },  
      popupclosed(){  
        this.formData.d_ids = this.tempPdid  // 这个例子是用户修改页,d_ids是uni-id-users表的部门字段  
      },

操作效果:点击任意节点,再点击选框之外,会自动关闭选框,选项即生效。

收起阅读 »

关于多渠道打包协助

打包 渠道包

作者可提供完整多渠道打包解决方案帮助

作者可提供完整多渠道打包解决方案帮助