nativejs android获取wifi强度及状态
const Context = plus.android.importClass("android.content.Context");
const WifiManager = plus.android.importClass("android.net.wifi.WifiManager");
const wifiManager = plus.android.runtimeMainActivity().getSystemService(Context.WIFI_SERVICE);
const WifiInfo = plus.android.importClass("android.net.wifi.WifiInfo");
const isWifiEnabled = wifiManager.isWifiEnabled();
if (!isWifiEnabled) {
// 未开启wifi
// ....
return;
}
const connectionInfo = wifiManager.getConnectionInfo();
const ipAddress = connectionInfo.getIpAddress();
if (!ipAddress) {
// WiFi未连接
// ....
return;
}
// wifi已连接
const rssi = connectionInfo.getRssi();
// 0格 rssi<=-100
// 1格 (-100, -88]
// 2格 (-88, -77]
// 3格 (-77, -55]
// 4格 rssi>=-55
const Context = plus.android.importClass("android.content.Context");
const WifiManager = plus.android.importClass("android.net.wifi.WifiManager");
const wifiManager = plus.android.runtimeMainActivity().getSystemService(Context.WIFI_SERVICE);
const WifiInfo = plus.android.importClass("android.net.wifi.WifiInfo");
const isWifiEnabled = wifiManager.isWifiEnabled();
if (!isWifiEnabled) {
// 未开启wifi
// ....
return;
}
const connectionInfo = wifiManager.getConnectionInfo();
const ipAddress = connectionInfo.getIpAddress();
if (!ipAddress) {
// WiFi未连接
// ....
return;
}
// wifi已连接
const rssi = connectionInfo.getRssi();
// 0格 rssi<=-100
// 1格 (-100, -88]
// 2格 (-88, -77]
// 3格 (-77, -55]
// 4格 rssi>=-55
收起阅读 »
【IOS相册权限】Native.js IOS相册权限获取 弹窗请求授权
优化官方推荐的uni.authorize文档中permission.js中的相册授权方法,判断是否有授权没有则弹窗请求授权。
发现很多小伙伴有这个需求,自己也在网上搜索了一番无果。
在此分享出来,方便大家开发。
// 判断相册权限是否开启 resolve()返回值可以根据需求更具体一点,在业务中拿到状态码后弹窗提示用户是否要去设置页修改权限
function judgeIosPermissionPhotoLibrary() {
return new Promise((resolve, reject) => {
var PHAuthorizationStatus = {
NotDetermined: 0, // 未申请过权限
Restricted: 1, // 拒绝
Denied: 2, // 拒绝
Authorized: 3, // 拥有
Limited: 4 // iOS 14 新增
};
if (!PHPhotoLibrary) {
var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
}
var status = PHPhotoLibrary.authorizationStatus();
if (status === PHAuthorizationStatus.NotDetermined) {
PHPhotoLibrary.requestAuthorization(() => {
const status = PHPhotoLibrary.authorizationStatus(); {
if (status === PHAuthorizationStatus.Authorized) {
plus.ios.deleteObject(PHPhotoLibrary);
resolve(true)
} else {
plus.ios.deleteObject(PHPhotoLibrary);
resolve(false)
}
}
})
} else if (status === PHAuthorizationStatus.Authorized) {
plus.ios.deleteObject(PHPhotoLibrary);
resolve(true)
} else {
if (status === PHAuthorizationStatus.Denied || status === PHAuthorizationStatus.Restricted) {
console.log("您已拒绝访问相册权限,请在设置中手动开启。");
} else if (status === PHAuthorizationStatus.Limited) {
console.log("相册权限为有限访问。");
}
plus.ios.deleteObject(PHPhotoLibrary);
resolve(false)
}
})
}
优化官方推荐的uni.authorize文档中permission.js中的相册授权方法,判断是否有授权没有则弹窗请求授权。
发现很多小伙伴有这个需求,自己也在网上搜索了一番无果。
在此分享出来,方便大家开发。
// 判断相册权限是否开启 resolve()返回值可以根据需求更具体一点,在业务中拿到状态码后弹窗提示用户是否要去设置页修改权限
function judgeIosPermissionPhotoLibrary() {
return new Promise((resolve, reject) => {
var PHAuthorizationStatus = {
NotDetermined: 0, // 未申请过权限
Restricted: 1, // 拒绝
Denied: 2, // 拒绝
Authorized: 3, // 拥有
Limited: 4 // iOS 14 新增
};
if (!PHPhotoLibrary) {
var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
}
var status = PHPhotoLibrary.authorizationStatus();
if (status === PHAuthorizationStatus.NotDetermined) {
PHPhotoLibrary.requestAuthorization(() => {
const status = PHPhotoLibrary.authorizationStatus(); {
if (status === PHAuthorizationStatus.Authorized) {
plus.ios.deleteObject(PHPhotoLibrary);
resolve(true)
} else {
plus.ios.deleteObject(PHPhotoLibrary);
resolve(false)
}
}
})
} else if (status === PHAuthorizationStatus.Authorized) {
plus.ios.deleteObject(PHPhotoLibrary);
resolve(true)
} else {
if (status === PHAuthorizationStatus.Denied || status === PHAuthorizationStatus.Restricted) {
console.log("您已拒绝访问相册权限,请在设置中手动开启。");
} else if (status === PHAuthorizationStatus.Limited) {
console.log("相册权限为有限访问。");
}
plus.ios.deleteObject(PHPhotoLibrary);
resolve(false)
}
})
}
收起阅读 »
安卓软件彻底重启
重启app,会杀掉所有进程以及服务后重启软件;plus.runtime.restart()只能重新加载,并非彻底重启,导致之前的服务进程无法退出
const main = plus.android.runtimeMainActivity();
const Intent = plus.android.importClass("android.content.Intent");
const Process = plus.android.importClass("android.os.Process");
const intentMainActivity = new Intent(Intent.ACTION_MAIN);
const packageName = main.getPackageName();
intentMainActivity.setClassName(packageName, "io.dcloud.PandoraEntry");
intentMainActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
main.startActivity(intentMainActivity);
Process.killProcess(Process.myPid());
重启app,会杀掉所有进程以及服务后重启软件;plus.runtime.restart()只能重新加载,并非彻底重启,导致之前的服务进程无法退出
const main = plus.android.runtimeMainActivity();
const Intent = plus.android.importClass("android.content.Intent");
const Process = plus.android.importClass("android.os.Process");
const intentMainActivity = new Intent(Intent.ACTION_MAIN);
const packageName = main.getPackageName();
intentMainActivity.setClassName(packageName, "io.dcloud.PandoraEntry");
intentMainActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
main.startActivity(intentMainActivity);
Process.killProcess(Process.myPid());
收起阅读 »
安卓11及以上版本申请所有文件访问权限
安卓11以后,文件读写权限申请变得更严格,常见的就是读取sdcard内的公共文件都提示没有权限,以下方法用于申请所有文件访问读写权限(并非所有空间都能读写,具体查看相关文档),添加MANAGE_EXTERNAL_STORAGE权限可能导致google play审核不通过,目前一般只允许文件管理器之类主要功能依赖文件读写的应用上架。
/**
* 安卓11及以上版本(SDK>=30),需要申请MANAGE_EXTERNAL_STORAGE权限,否则按钮无法点击,如下
* 在manifest.json>app-plus>distribute>android>permissions中添加权限
* <uses-permission android:name=\"android.permission.MANAGE_EXTERNAL_STORAGE\"/>
*/
requestPermission() {
const main = plus.android.runtimeMainActivity();
const pkName = main.getPackageName();
const Intent = plus.android.importClass("android.content.Intent");
const Build = plus.android.importClass("android.os.Build");
const Settings = plus.android.importClass("android.provider.Settings");
const Environment = plus.android.importClass("android.os.Environment");
if (Build.VERSION.SDK_INT >= 30) {
// 权限未获取跳转到设置页
if (!Environment.isExternalStorageManager()) {
let intent = new Intent(
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
);
const Uri = plus.android.importClass("android.net.Uri");
const uri = Uri.fromParts("package", pkName, null);
intent.setData(uri);
main.startActivity(intent);
}
// 权限已获取,自定义处理
else {
}
}
}
安卓11以后,文件读写权限申请变得更严格,常见的就是读取sdcard内的公共文件都提示没有权限,以下方法用于申请所有文件访问读写权限(并非所有空间都能读写,具体查看相关文档),添加MANAGE_EXTERNAL_STORAGE权限可能导致google play审核不通过,目前一般只允许文件管理器之类主要功能依赖文件读写的应用上架。
/**
* 安卓11及以上版本(SDK>=30),需要申请MANAGE_EXTERNAL_STORAGE权限,否则按钮无法点击,如下
* 在manifest.json>app-plus>distribute>android>permissions中添加权限
* <uses-permission android:name=\"android.permission.MANAGE_EXTERNAL_STORAGE\"/>
*/
requestPermission() {
const main = plus.android.runtimeMainActivity();
const pkName = main.getPackageName();
const Intent = plus.android.importClass("android.content.Intent");
const Build = plus.android.importClass("android.os.Build");
const Settings = plus.android.importClass("android.provider.Settings");
const Environment = plus.android.importClass("android.os.Environment");
if (Build.VERSION.SDK_INT >= 30) {
// 权限未获取跳转到设置页
if (!Environment.isExternalStorageManager()) {
let intent = new Intent(
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
);
const Uri = plus.android.importClass("android.net.Uri");
const uri = Uri.fromParts("package", pkName, null);
intent.setData(uri);
main.startActivity(intent);
}
// 权限已获取,自定义处理
else {
}
}
}
收起阅读 »
wifi打印机打印(二维码,条形码等)
- 打印机,需要插usb(或者微信小程序设置wifi)
- 打印机的默认端口是9100(一般是,具体看购买的打印机)
- wifitool.js是用于连接打印机的
-
此文章是用的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;
- 打印机,需要插usb(或者微信小程序设置wifi)
- 打印机的默认端口是9100(一般是,具体看购买的打印机)
- wifitool.js是用于连接打印机的
-
此文章是用的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>
收起阅读 »
请问使用5+app中的plus.android.importClass('android.media.AudioRecord');引入对象后,调用对象的 read 方法一直返回null是怎么回事呢?
请问使用5+app中的plus.android.importClass('android.media.AudioRecord');引入对象后,调用对象的 read() 方法一直返回null是怎么回事呢?
在调用对象的 read() 方法之前已经实例化AudioRecord,并调用了 startRecording() 方法,请各位大佬赐教
请问使用5+app中的plus.android.importClass('android.media.AudioRecord');引入对象后,调用对象的 read() 方法一直返回null是怎么回事呢?
在调用对象的 read() 方法之前已经实例化AudioRecord,并调用了 startRecording() 方法,请各位大佬赐教
关于Android 部分手机NotificationManagerCompat.from 返回null 解决办法
在做一个检查应用是否拥有通知权限功能的时候发现部分手机(Redmi Note 5A 【Android 7.1.2】)调用NotificationManagerCompat.from(context) 会返回null
查阅了Android Dev 文档,官方描述NotificationManagerCompat.from 的返回值是 NonNull的 理应不会返回null
尝试修复方式如下,我自己去看了NotificationManagerCompat.from + NotificationManagerCompat.areNotificationsEnabled源代码手撸的;
相当于给NotificationManagerCompat.from 添加了个Polyfill;
const activity = plus.android.runtimeMainActivity();
const NotificationManagerCompat = plus.android.importClass('androidx.core.app.NotificationManagerCompat');
const manager = NotificationManagerCompat.from(activity) || {
/** 手动实现 NotificationManagerCompat,因为部分手机NotificationManagerCompat.from会返回null */
areNotificationsEnabled() {
const Build = plus.android.importClass('android.os.Build');
if (Build.VERSION.SDK_INT >= 24) {
plus.android.importClass('android.app.NotificationManager');
const notificationManager = activity.getSystemService(activity.NOTIFICATION_SERVICE);
const areNotificationsEnabled = notificationManager.areNotificationsEnabled();
plus.android.autoCollection(notificationManager);
return areNotificationsEnabled;
} else if (Build.VERSION.SDK_INT >= 19) {
const AppOpsManager = plus.android.importClass('android.app.AppOpsManager');
const ApplicationInfo = plus.android.importClass('android.content.pm.ApplicationInfo');
const appOps = activity.getSystemService(activity.APP_OPS_SERVICE);
const appInfo = activity.getApplicationInfo();
try {
const isEnabled = appOps.checkOpNoThrow(
AppOpsManager.OP_POST_NOTIFICATION,
plus.android.getAttribute(appInfo, 'uid'), //直接appInfo.uid 返回的是undefined
activity.getApplicationContext().getPackageName()
) === AppOpsManager.MODE_ALLOWED;
plus.android.autoCollection(appOps);
plus.android.autoCollection(appInfo);
return isEnabled;
} catch (e) {
return true;
}
}
return true;
}
};
console.log(manager.areNotificationsEnabled())
在做一个检查应用是否拥有通知权限功能的时候发现部分手机(Redmi Note 5A 【Android 7.1.2】)调用NotificationManagerCompat.from(context) 会返回null
查阅了Android Dev 文档,官方描述NotificationManagerCompat.from 的返回值是 NonNull的 理应不会返回null
尝试修复方式如下,我自己去看了NotificationManagerCompat.from + NotificationManagerCompat.areNotificationsEnabled源代码手撸的;
相当于给NotificationManagerCompat.from 添加了个Polyfill;
const activity = plus.android.runtimeMainActivity();
const NotificationManagerCompat = plus.android.importClass('androidx.core.app.NotificationManagerCompat');
const manager = NotificationManagerCompat.from(activity) || {
/** 手动实现 NotificationManagerCompat,因为部分手机NotificationManagerCompat.from会返回null */
areNotificationsEnabled() {
const Build = plus.android.importClass('android.os.Build');
if (Build.VERSION.SDK_INT >= 24) {
plus.android.importClass('android.app.NotificationManager');
const notificationManager = activity.getSystemService(activity.NOTIFICATION_SERVICE);
const areNotificationsEnabled = notificationManager.areNotificationsEnabled();
plus.android.autoCollection(notificationManager);
return areNotificationsEnabled;
} else if (Build.VERSION.SDK_INT >= 19) {
const AppOpsManager = plus.android.importClass('android.app.AppOpsManager');
const ApplicationInfo = plus.android.importClass('android.content.pm.ApplicationInfo');
const appOps = activity.getSystemService(activity.APP_OPS_SERVICE);
const appInfo = activity.getApplicationInfo();
try {
const isEnabled = appOps.checkOpNoThrow(
AppOpsManager.OP_POST_NOTIFICATION,
plus.android.getAttribute(appInfo, 'uid'), //直接appInfo.uid 返回的是undefined
activity.getApplicationContext().getPackageName()
) === AppOpsManager.MODE_ALLOWED;
plus.android.autoCollection(appOps);
plus.android.autoCollection(appInfo);
return isEnabled;
} catch (e) {
return true;
}
}
return true;
}
};
console.log(manager.areNotificationsEnabled())
收起阅读 »
uniapp 官方公布的plug 不支持 流文件写入,给你们来一个简单的
uniapp 流文件的写入
fileEntry.createWriter(function(write){
writer.seek(0);
//此处的base64不含 文件的头信息,不能有\r\n. 相当于不能通过 readAsBase64来获取,或者自行替换。
writer.writeAsBinary(base64Str);
writer.abort();
})
没有测试 苹果的,我看的是安卓的,按理说,官方应该同时支持的。
官方还有没公布的,可能有用的 “readAsBase64”,不过跟readAsDataURL差不多,只是 readAsBase64出来的没有文件头,且有\r\n。
uniapp 流文件的写入
fileEntry.createWriter(function(write){
writer.seek(0);
//此处的base64不含 文件的头信息,不能有\r\n. 相当于不能通过 readAsBase64来获取,或者自行替换。
writer.writeAsBinary(base64Str);
writer.abort();
})
没有测试 苹果的,我看的是安卓的,按理说,官方应该同时支持的。
官方还有没公布的,可能有用的 “readAsBase64”,不过跟readAsDataURL差不多,只是 readAsBase64出来的没有文件头,且有\r\n。
iOS 本地消息推送通知
效果如图
参考 iOS 最新的 UNNotificationRequest API
function notifyWithInterval(interval) {
//content https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent?language=objc
const content = plus.ios.newObject("UNMutableNotificationContent")
const Sound = plus.ios.importClass('UNNotificationSound')
content.plusSetAttribute("title", 'title');
content.plusSetAttribute("subtitle", 'subtitle');
content.plusSetAttribute("body", 'body_' + interval);
content.plusSetAttribute('sound', Sound.defaultSound());
//trigger https://developer.apple.com/documentation/usernotifications/unnotificationtrigger?language=objc
const Trigger = plus.ios.importClass("UNTimeIntervalNotificationTrigger")
const trigger = Trigger.triggerWithTimeIntervalrepeats(interval, false)
const UUID = plus.ios.newObject('NSUUID')
const uuid = UUID.plusGetAttribute('UUIDString')
// const uuid = plus.tools.UUID('TIMER');
//request
const Req = plus.ios.importClass('UNNotificationRequest')
const req = Req.requestWithIdentifiercontenttrigger(uuid, content, trigger)
const NotiCenter = plus.ios.importClass("UNUserNotificationCenter")
const userNotiCenter = NotiCenter.currentNotificationCenter()
userNotiCenter.addNotificationRequest(req)
}
调用如下:
export default {
......
onLaunch: function() {
......
// 5 秒后推送本地提醒
notifyWithInterval(5)
}
......
}
其实不复杂,只是参考资料太少了,花两百买了一段代码,结果还是iOS废弃的api,自己看 iOS的文档重写了一个。
这里只写了一个 triggerWithTimeIntervalrepeats
的例子,其他的可参考 unnotificationtrigger
比较遗憾的是 delegate功能一直没调通,也就是自定义收到消息的后续操作,完全按 iOS 的文档实现 UNUserNotificationCenterDelegate
怎么都不行,有实现了的可以交流下,不打算弄原生插件,打算弃坑了……
效果如图
参考 iOS 最新的 UNNotificationRequest API
function notifyWithInterval(interval) {
//content https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent?language=objc
const content = plus.ios.newObject("UNMutableNotificationContent")
const Sound = plus.ios.importClass('UNNotificationSound')
content.plusSetAttribute("title", 'title');
content.plusSetAttribute("subtitle", 'subtitle');
content.plusSetAttribute("body", 'body_' + interval);
content.plusSetAttribute('sound', Sound.defaultSound());
//trigger https://developer.apple.com/documentation/usernotifications/unnotificationtrigger?language=objc
const Trigger = plus.ios.importClass("UNTimeIntervalNotificationTrigger")
const trigger = Trigger.triggerWithTimeIntervalrepeats(interval, false)
const UUID = plus.ios.newObject('NSUUID')
const uuid = UUID.plusGetAttribute('UUIDString')
// const uuid = plus.tools.UUID('TIMER');
//request
const Req = plus.ios.importClass('UNNotificationRequest')
const req = Req.requestWithIdentifiercontenttrigger(uuid, content, trigger)
const NotiCenter = plus.ios.importClass("UNUserNotificationCenter")
const userNotiCenter = NotiCenter.currentNotificationCenter()
userNotiCenter.addNotificationRequest(req)
}
调用如下:
export default {
......
onLaunch: function() {
......
// 5 秒后推送本地提醒
notifyWithInterval(5)
}
......
}
其实不复杂,只是参考资料太少了,花两百买了一段代码,结果还是iOS废弃的api,自己看 iOS的文档重写了一个。
这里只写了一个 triggerWithTimeIntervalrepeats
的例子,其他的可参考 unnotificationtrigger
比较遗憾的是 delegate功能一直没调通,也就是自定义收到消息的后续操作,完全按 iOS 的文档实现 UNUserNotificationCenterDelegate
怎么都不行,有实现了的可以交流下,不打算弄原生插件,打算弃坑了……
uniapp实现安卓禁止截屏和允许截屏
let flag = 0
let WindowManager = null
let mainActivity = null
let window_android = null
document.addEventListener('plusready', function(){
WindowManager = plus.android.importClass('android.view.WindowManager')
plus.android.importClass("android.view.Window");
mainActivity = plus.android.runtimeMainActivity();
window_android = mainActivity.getWindow();
flag = WindowManager.LayoutParams.FLAG_SECURE
});
function allowJp(){
// 允许截屏
window_android.clearFlags(flag);
}
function forbidJp(){
// 禁止截屏
window_android.addFlags(flag);
}
直接调用上面的方法即可实现禁止和允许截屏
Tips: 在vue文件里面写不用监听plusready,可以直接把function里面的代码拿出来
let flag = 0
let WindowManager = null
let mainActivity = null
let window_android = null
document.addEventListener('plusready', function(){
WindowManager = plus.android.importClass('android.view.WindowManager')
plus.android.importClass("android.view.Window");
mainActivity = plus.android.runtimeMainActivity();
window_android = mainActivity.getWindow();
flag = WindowManager.LayoutParams.FLAG_SECURE
});
function allowJp(){
// 允许截屏
window_android.clearFlags(flag);
}
function forbidJp(){
// 禁止截屏
window_android.addFlags(flag);
}
直接调用上面的方法即可实现禁止和允许截屏
Tips: 在vue文件里面写不用监听plusready,可以直接把function里面的代码拿出来