
vue3兼容APP和微信小程序的base64图片保存到相册的方法
<view style="padding:40rpx;">
<canvas id="myCanvas" canvas-id="myCanvas" type="2d" style="width: 670rpx; height: 670rpx;" @longpress="saveCode"></canvas>
</view>
API请求获取得到buffer
codeSrc.value = "data:image/png;base64," + res.data.buffer; // <image :src="codeSrc"></image>仅展示,要保存到相册,无法直接调用saveImageToPhotosAlbum,也无法间接通过getImageInfo、downloadFile、saveFile获得的临时文件地址再保存,故采用canvasToTempFilePath API解决;如您后端返回是图链该方法不适用。
const bufferRaw = res.data.buffer
由于个人原因小程序端fields获取的context接连抽风绘制不出图形
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').context((res) => {let ctx=res})
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').fields({node: true,context: true})((res) => {let canvas=res[0].node;let ctx=canvas.getContext('2d'); //或 let ctx=res[0].context})
所以小程序只能从canvas入手,最终
// 确保canvas已经挂载后执行下面的代码片段
const tempFilePath = ref("")
// #ifdef APP
const ctx = uni.createCanvasContext("myCanvas", app.proxy)
ctx.rect(0, 0, uni.upx2px(670), uni.upx2px(670))
ctx.setFillStyle('white')
ctx.fill()
ctx.drawImage(codeSrc.value, 0, 0, uni.upx2px(
670), uni.upx2px(670));
// !!!一定要在回调中获得这个canvas的临时地址
ctx.draw(false, async () => {
uni.canvasToTempFilePath({
canvasId: "myCanvas",
success: function(res) {
console.log(res
.tempFilePath)
tempFilePath.value = res
.tempFilePath
// 能预览就是画成功
// uni.previewImage({
// urls: [res
// .tempFilePath
// ],
// })
}
})
})
// #endif
// #ifdef MP
// 小程序废弃了createCanvasContext
const query = uni.createSelectorQuery().in(app.proxy)
query.select('#myCanvas')
.fields({
node: true,
size: true
})
.exec(async (res) => {
// console.log(res)
let canvas = res[0].node
let ctx = canvas.getContext('2d')
// console.log(ctx, canvas)
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
const fsm = wx.getFileSystemManager() // 文件管理器
const fname = app.proxy.$utils.$helper.generateRandomString(16)
const FILE_BASE_NAME = `tmp_base64src_${fname}` // 文件名
const format = 'png' // 文件后缀
const buffer = wx.base64ToArrayBuffer(bufferRaw) // base 转二进制
const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}` // 文件名
fsm.writeFile({ // 写文件
filePath,
data: buffer,
encoding: 'binary',
success: (res) => {
// 能预览就是画成功
// wx.previewImage({
// urls: [filePath],
// })
var img = canvas.createImage();
img.src = filePath
img.onload = function() {
ctx.drawImage(img, 0, 0,
uni
.upx2px(
670), uni.upx2px(670));
// ctx.draw()
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
canvas: canvas,
success: function(res) {
console.log(res
.tempFilePath)
tempFilePath.value = res
.tempFilePath
},
fail: function(error) {
console.error(error)
}
}, app.proxy);
}
},
fail: (err) => {
console.error(err)
}
})
})
// #endif
// 保存到相册
const saveCode = () => {
uni.saveImageToPhotosAlbum({
filePath: tempFilePath.value,
success: function() {
uni.showToast({
title: '保存成功',
icon: 'success'
});
},
fail: function(error) {
uni.showToast({
title: '未保存成功',
icon: 'none'
});
}
});
}
<view style="padding:40rpx;">
<canvas id="myCanvas" canvas-id="myCanvas" type="2d" style="width: 670rpx; height: 670rpx;" @longpress="saveCode"></canvas>
</view>
API请求获取得到buffer
codeSrc.value = "data:image/png;base64," + res.data.buffer; // <image :src="codeSrc"></image>仅展示,要保存到相册,无法直接调用saveImageToPhotosAlbum,也无法间接通过getImageInfo、downloadFile、saveFile获得的临时文件地址再保存,故采用canvasToTempFilePath API解决;如您后端返回是图链该方法不适用。
const bufferRaw = res.data.buffer
由于个人原因小程序端fields获取的context接连抽风绘制不出图形
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').context((res) => {let ctx=res})
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').fields({node: true,context: true})((res) => {let canvas=res[0].node;let ctx=canvas.getContext('2d'); //或 let ctx=res[0].context})
所以小程序只能从canvas入手,最终
// 确保canvas已经挂载后执行下面的代码片段
const tempFilePath = ref("")
// #ifdef APP
const ctx = uni.createCanvasContext("myCanvas", app.proxy)
ctx.rect(0, 0, uni.upx2px(670), uni.upx2px(670))
ctx.setFillStyle('white')
ctx.fill()
ctx.drawImage(codeSrc.value, 0, 0, uni.upx2px(
670), uni.upx2px(670));
// !!!一定要在回调中获得这个canvas的临时地址
ctx.draw(false, async () => {
uni.canvasToTempFilePath({
canvasId: "myCanvas",
success: function(res) {
console.log(res
.tempFilePath)
tempFilePath.value = res
.tempFilePath
// 能预览就是画成功
// uni.previewImage({
// urls: [res
// .tempFilePath
// ],
// })
}
})
})
// #endif
// #ifdef MP
// 小程序废弃了createCanvasContext
const query = uni.createSelectorQuery().in(app.proxy)
query.select('#myCanvas')
.fields({
node: true,
size: true
})
.exec(async (res) => {
// console.log(res)
let canvas = res[0].node
let ctx = canvas.getContext('2d')
// console.log(ctx, canvas)
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
const fsm = wx.getFileSystemManager() // 文件管理器
const fname = app.proxy.$utils.$helper.generateRandomString(16)
const FILE_BASE_NAME = `tmp_base64src_${fname}` // 文件名
const format = 'png' // 文件后缀
const buffer = wx.base64ToArrayBuffer(bufferRaw) // base 转二进制
const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}` // 文件名
fsm.writeFile({ // 写文件
filePath,
data: buffer,
encoding: 'binary',
success: (res) => {
// 能预览就是画成功
// wx.previewImage({
// urls: [filePath],
// })
var img = canvas.createImage();
img.src = filePath
img.onload = function() {
ctx.drawImage(img, 0, 0,
uni
.upx2px(
670), uni.upx2px(670));
// ctx.draw()
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
canvas: canvas,
success: function(res) {
console.log(res
.tempFilePath)
tempFilePath.value = res
.tempFilePath
},
fail: function(error) {
console.error(error)
}
}, app.proxy);
}
},
fail: (err) => {
console.error(err)
}
})
})
// #endif
// 保存到相册
const saveCode = () => {
uni.saveImageToPhotosAlbum({
filePath: tempFilePath.value,
success: function() {
uni.showToast({
title: '保存成功',
icon: 'success'
});
},
fail: function(error) {
uni.showToast({
title: '未保存成功',
icon: 'none'
});
}
});
}
收起阅读 »

分享自用HBuilderX主题 仿 VsCode Default Dark Modern主题
自用 基于HBuiderX酷黑主题上修改的 仿VsCode的 现代深色Default Dark Modern 主题
有一些缺陷,比如:
- 不会修改菜单的背景颜色,所以是酷黑主题原有的颜色
- 没有修改代码颜色,是酷黑主题原有的颜色
如下图
主题预览图:
{
"editor.colorScheme": "Monokai",
"workbench.colorCustomizations": {
"[Default]": {},
"[Monokai]": {
"console.background":"#181818",
"menubar.background":"#181818",
"editor.background": "#1f1f1f",
"editor.foreground": "#808080",
"editor.indentguide": "#404040",
"editor.indicator.sameword": "#343a40",
"editor.selectRegion": "#2a2b2d",
"editor.selection": "#264f78",
"editor.unactive_selection.background": "#9e6a03",
"editor.whitespace": "#1f1f1f",
"editorGroup.border": "#333333",
"editorGroupHeader.tabsBackground": "#181818",
"editorSuggestWidget.background": "#202020",
"editorSuggestWidget.border": "#454545",
"editorSuggestWidget.selectedBackground": "#454545",
"focusBorder": "#0078d4",
"input.background": "#313131",
"input.foreground": "#c3c3c3",
"input.searchbar.foreground": "#989898",
"input.searchbar.foreground.notfinded": "#aeaeae",
"inputList.border": "#313131",
"inputList.foreground": "#8b8b8b",
"inputList.hoverBackground": "#2a2d2e",
"inputList.titleColor": "#cccccc",
"inputValidation.infoBackground": "#222222",
"list.activeSelectionBackground": "#04395e",
"list.activeSelectionForeground": "#ffffff",
"list.foreground": "#cccccc",
"list.highlightForeground": "#ffffff",
"list.hoverBackground": "#2a2d2e",
"minimap.handle.background": "#1f1f1f",
"outlineBackground": "#1f1f1f",
"scrollbarSlider.background": "#434343",
"scrollbarSlider.hoverBackground": "#4f4f4f",
"sideBar.background": "#181818",
"sideBar.border": "#2b2b2b",
"statusBar.background": "#181818",
"statusBar.button.hoverbackground": "#343434",
"statusBar.foreground": "#cccccc",
"tab.activeBackground": "#1f1f1f",
"tab.activeForeground": "#ffffff",
"tab.border": "#2b2b2b",
"tab.hoverBackground": "#1f1f1f",
"tab.inactiveBackground": "#181818",
"tab.inactiveForeground": "#9d9d9d",
"tab.unfocusedActiveForeground": "#737373",
"tab.unfocusedHoverBackground": "#1f1f1f",
"tab.unfocusedInactiveForeground": "#181818",
"terminal.background": "#181818",
"toolBar.background": "#181818",
"toolBar.border": "#2b2b2b",
"toolBar.hoverBackground": "#2d2e2e"
}
},
"editor.tokenColorCustomizations": {
"[Default]": {},
"[Monokai]": {
"rules": [
{
"scope": [
"comment"
],
"settings": {
"foreground": "#6a9955"
}
}
]
}
}
}
自用 基于HBuiderX酷黑主题上修改的 仿VsCode的 现代深色Default Dark Modern 主题
有一些缺陷,比如:
- 不会修改菜单的背景颜色,所以是酷黑主题原有的颜色
- 没有修改代码颜色,是酷黑主题原有的颜色
如下图
主题预览图:
{
"editor.colorScheme": "Monokai",
"workbench.colorCustomizations": {
"[Default]": {},
"[Monokai]": {
"console.background":"#181818",
"menubar.background":"#181818",
"editor.background": "#1f1f1f",
"editor.foreground": "#808080",
"editor.indentguide": "#404040",
"editor.indicator.sameword": "#343a40",
"editor.selectRegion": "#2a2b2d",
"editor.selection": "#264f78",
"editor.unactive_selection.background": "#9e6a03",
"editor.whitespace": "#1f1f1f",
"editorGroup.border": "#333333",
"editorGroupHeader.tabsBackground": "#181818",
"editorSuggestWidget.background": "#202020",
"editorSuggestWidget.border": "#454545",
"editorSuggestWidget.selectedBackground": "#454545",
"focusBorder": "#0078d4",
"input.background": "#313131",
"input.foreground": "#c3c3c3",
"input.searchbar.foreground": "#989898",
"input.searchbar.foreground.notfinded": "#aeaeae",
"inputList.border": "#313131",
"inputList.foreground": "#8b8b8b",
"inputList.hoverBackground": "#2a2d2e",
"inputList.titleColor": "#cccccc",
"inputValidation.infoBackground": "#222222",
"list.activeSelectionBackground": "#04395e",
"list.activeSelectionForeground": "#ffffff",
"list.foreground": "#cccccc",
"list.highlightForeground": "#ffffff",
"list.hoverBackground": "#2a2d2e",
"minimap.handle.background": "#1f1f1f",
"outlineBackground": "#1f1f1f",
"scrollbarSlider.background": "#434343",
"scrollbarSlider.hoverBackground": "#4f4f4f",
"sideBar.background": "#181818",
"sideBar.border": "#2b2b2b",
"statusBar.background": "#181818",
"statusBar.button.hoverbackground": "#343434",
"statusBar.foreground": "#cccccc",
"tab.activeBackground": "#1f1f1f",
"tab.activeForeground": "#ffffff",
"tab.border": "#2b2b2b",
"tab.hoverBackground": "#1f1f1f",
"tab.inactiveBackground": "#181818",
"tab.inactiveForeground": "#9d9d9d",
"tab.unfocusedActiveForeground": "#737373",
"tab.unfocusedHoverBackground": "#1f1f1f",
"tab.unfocusedInactiveForeground": "#181818",
"terminal.background": "#181818",
"toolBar.background": "#181818",
"toolBar.border": "#2b2b2b",
"toolBar.hoverBackground": "#2d2e2e"
}
},
"editor.tokenColorCustomizations": {
"[Default]": {},
"[Monokai]": {
"rules": [
{
"scope": [
"comment"
],
"settings": {
"foreground": "#6a9955"
}
}
]
}
}
}
收起阅读 »

uni-app 最专业的代码生成器
mui 专业代码生成器
1.数据库专业工具
- 后端专业工具
- UI 采用MUI 一键生成
欢迎讨论,提供技术支持
下载地址:
https://download.csdn.net/download/qq512929249/89639950
mui 专业代码生成器
1.数据库专业工具
- 后端专业工具
- UI 采用MUI 一键生成
欢迎讨论,提供技术支持
下载地址:
https://download.csdn.net/download/qq512929249/89639950

技术分享:从崩溃边缘到问题解决 —— SSL证书兼容性问题的实战经历
引言
作为一名开发者,我们经常会遇到一些令人头疼的技术难题。有时候,这些问题看似简单却异常棘手,让人几乎要放弃。今天,我想分享一次特别的经历,它始于一系列的调试失败,最终却在不经意间找到了解决方案。这个故事围绕着SSL证书的兼容性问题展开,希望能给大家带来一些启示。
问题背景
我负责开发的一款小程序需要与后端API进行安全通信。为了保证数据传输的安全性和平台要求,我们采用了SSL/TLS协议,并为服务器配置了一张免费的SSL证书。起初一切看起来都很顺利,直到我们在进行跨平台测试时遇到了问题。
初步排查
我们的测试团队在不同的设备上进行了测试,大部分情况下一切正常,但有一个特定品牌的手机总是无法成功发起HTTPS请求。这个问题一开始并不明显,因为我们主要依赖于模拟器和主流机型进行测试。然而,随着用户反馈的增多,这个问题变得越来越紧迫。
排查步骤
- 日志分析:首先,我们查看了客户端的日志记录,发现了一些关于证书验证失败的错误提示。
- 网络监控:使用抓包工具对网络请求进行了监控,发现客户端在尝试建立HTTPS连接时收到了错误响应。
- 设备差异对比:我们将有问题的设备与其他设备进行了对比测试,试图找出它们之间的差异。
寻找线索
尽管我们进行了初步的排查,但问题仍然没有得到解决。我们开始怀疑是客户端代码的问题,甚至重写了部分网络请求逻辑,但结果依然不尽人意。正当我们几乎要放弃的时候,一个偶然的机会改变了这一切。
关键转折点
在又一次的调试过程中,由于免费证书到期太麻烦,更换一张一年期的付费的SSL证书进行测试。起初,这只是一种无意间的举措,我们并没有抱希望。然而,就在我们更换了证书之后,在那个一直存在问题的手机上进行测试时,奇迹发生了——请求成功了!
分析原因
这次意外的成功让我们意识到,问题可能出在免费SSL证书的兼容性上。为了验证这一猜想,我们进行了更深入的研究:
- 证书类型对比:我们比较了免费证书和付费证书之间的差异,特别是它们的验证方式和兼容性。
- 浏览器和操作系统兼容性:我们查阅了相关文档,了解了不同浏览器和操作系统对于SSL证书的要求。
- 设备特定问题:进一步研究了那款特定品牌的手机的操作系统版本和其他特性,发现它对于某些类型的证书支持较差。
解决方案
最终,我们确定了问题的根本原因是免费SSL证书在某些设备上的兼容性不佳。为了避免类似问题再次发生,我们采取了以下几个措施:
- 升级证书:将免费证书升级为付费证书,确保了更好的兼容性和安全性。
- 全面测试:增加了更多样化的设备和环境进行测试,确保应用程序在各种条件下都能正常运行。
- 用户教育:通过应用内的提示,告知用户如何检查他们的设备是否支持HTTPS连接。
结语
这次经历教会了我们几个重要的教训:
- 不要忽视小众设备:即使是小众的设备也可能成为问题的关键。
- 证书的选择很重要:选择合适的SSL证书对于确保应用的兼容性和安全性至关重要。
- 持续学习:技术总是在不断进步,持续学习新技术和最佳实践可以帮助我们更好地应对挑战。
希望我的这次经历能对你有所帮助,当你面对类似的问题时,不要轻易放弃,
有时候解决之道可能就在不远处。
引言
作为一名开发者,我们经常会遇到一些令人头疼的技术难题。有时候,这些问题看似简单却异常棘手,让人几乎要放弃。今天,我想分享一次特别的经历,它始于一系列的调试失败,最终却在不经意间找到了解决方案。这个故事围绕着SSL证书的兼容性问题展开,希望能给大家带来一些启示。
问题背景
我负责开发的一款小程序需要与后端API进行安全通信。为了保证数据传输的安全性和平台要求,我们采用了SSL/TLS协议,并为服务器配置了一张免费的SSL证书。起初一切看起来都很顺利,直到我们在进行跨平台测试时遇到了问题。
初步排查
我们的测试团队在不同的设备上进行了测试,大部分情况下一切正常,但有一个特定品牌的手机总是无法成功发起HTTPS请求。这个问题一开始并不明显,因为我们主要依赖于模拟器和主流机型进行测试。然而,随着用户反馈的增多,这个问题变得越来越紧迫。
排查步骤
- 日志分析:首先,我们查看了客户端的日志记录,发现了一些关于证书验证失败的错误提示。
- 网络监控:使用抓包工具对网络请求进行了监控,发现客户端在尝试建立HTTPS连接时收到了错误响应。
- 设备差异对比:我们将有问题的设备与其他设备进行了对比测试,试图找出它们之间的差异。
寻找线索
尽管我们进行了初步的排查,但问题仍然没有得到解决。我们开始怀疑是客户端代码的问题,甚至重写了部分网络请求逻辑,但结果依然不尽人意。正当我们几乎要放弃的时候,一个偶然的机会改变了这一切。
关键转折点
在又一次的调试过程中,由于免费证书到期太麻烦,更换一张一年期的付费的SSL证书进行测试。起初,这只是一种无意间的举措,我们并没有抱希望。然而,就在我们更换了证书之后,在那个一直存在问题的手机上进行测试时,奇迹发生了——请求成功了!
分析原因
这次意外的成功让我们意识到,问题可能出在免费SSL证书的兼容性上。为了验证这一猜想,我们进行了更深入的研究:
- 证书类型对比:我们比较了免费证书和付费证书之间的差异,特别是它们的验证方式和兼容性。
- 浏览器和操作系统兼容性:我们查阅了相关文档,了解了不同浏览器和操作系统对于SSL证书的要求。
- 设备特定问题:进一步研究了那款特定品牌的手机的操作系统版本和其他特性,发现它对于某些类型的证书支持较差。
解决方案
最终,我们确定了问题的根本原因是免费SSL证书在某些设备上的兼容性不佳。为了避免类似问题再次发生,我们采取了以下几个措施:
- 升级证书:将免费证书升级为付费证书,确保了更好的兼容性和安全性。
- 全面测试:增加了更多样化的设备和环境进行测试,确保应用程序在各种条件下都能正常运行。
- 用户教育:通过应用内的提示,告知用户如何检查他们的设备是否支持HTTPS连接。
结语
这次经历教会了我们几个重要的教训:
- 不要忽视小众设备:即使是小众的设备也可能成为问题的关键。
- 证书的选择很重要:选择合适的SSL证书对于确保应用的兼容性和安全性至关重要。
- 持续学习:技术总是在不断进步,持续学习新技术和最佳实践可以帮助我们更好地应对挑战。
希望我的这次经历能对你有所帮助,当你面对类似的问题时,不要轻易放弃,
有时候解决之道可能就在不远处。
收起阅读 »
使用了推送功能怎样生成推送证书
使用了推送功能后,要生成推送证书,不过这个推送证书并不是用来打包的,推送证书的作用是放在推送平台里用来发送消息用的,生成了推送证书后,依然还需要生成打包证书。
我们这篇文章来说下,使用了推送功能后,证书和证书profile文件如何修改。
假如你用了推送功能,在苹果创建应用的时候,需要勾选上支持推送,创建identifiers(appId)的时候,要注意勾选下图的选项。
因此修改了苹果开发者中心的应用的属性,所以要重新生成证书,然后参考这篇文章先创建打包证书:https://www.yunedit.com/xueyuan/jx/uniappcreatecert
appId勾选了支持push的时候,是需要绑定一个推送证书的,所以你需要创建一个推送证书。
注意这个推送证书并不是用来打包的,创建推送证书的步骤跟上面链接的教程的流程几乎一样,可以先在香蕉云编生成一个csr文件,然后再去苹果开发者中心的certificates菜单,创建一个cer证书,然后回到香蕉云编上传这个cer文件,生成一个p12。(具体图文教程参考上面发的教程链接),和教程不同的是,创建cer文件的时候,需要选择推送类型,不是其他的类型。
这样,你会生成两个p12证书文件,一个是打包用的证书,一个是推送用的证书,还有一个证书profile文件。总共三个文件。其中打包证书p12文件和证书profile文件,是用来在uniapp打包用的,推送证书p12文件是用来放在推送平台发消息的。这里比较重要,不要用推送证书来打包哦。
使用了推送功能后,要生成推送证书,不过这个推送证书并不是用来打包的,推送证书的作用是放在推送平台里用来发送消息用的,生成了推送证书后,依然还需要生成打包证书。
我们这篇文章来说下,使用了推送功能后,证书和证书profile文件如何修改。
假如你用了推送功能,在苹果创建应用的时候,需要勾选上支持推送,创建identifiers(appId)的时候,要注意勾选下图的选项。
因此修改了苹果开发者中心的应用的属性,所以要重新生成证书,然后参考这篇文章先创建打包证书:https://www.yunedit.com/xueyuan/jx/uniappcreatecert
appId勾选了支持push的时候,是需要绑定一个推送证书的,所以你需要创建一个推送证书。
注意这个推送证书并不是用来打包的,创建推送证书的步骤跟上面链接的教程的流程几乎一样,可以先在香蕉云编生成一个csr文件,然后再去苹果开发者中心的certificates菜单,创建一个cer证书,然后回到香蕉云编上传这个cer文件,生成一个p12。(具体图文教程参考上面发的教程链接),和教程不同的是,创建cer文件的时候,需要选择推送类型,不是其他的类型。
这样,你会生成两个p12证书文件,一个是打包用的证书,一个是推送用的证书,还有一个证书profile文件。总共三个文件。其中打包证书p12文件和证书profile文件,是用来在uniapp打包用的,推送证书p12文件是用来放在推送平台发消息的。这里比较重要,不要用推送证书来打包哦。
收起阅读 »
uni.getLocation偶而获取不到,使用原生代码替换
在APP中一直使用uni.getLocation的系统定位模块获取模糊位置,用以查询同城文章。偶然发现最近升级代码后,ANDROID下uni.getLocation无法正常工作,返回error:2错误。在仔细检查后,怀疑是hbuilderx升级后的BUG。写了一段android原生代码工作正常,并在运行一次此代码获取到位置后,再使用uni.getLocation即能正常。有理由怀疑是uni.getLocation使用了getLastKnownLocation导致的,查android文档,getLastKnownLocation返回最近一次位置缓存,并不保证时效及是否有值。所以在运行这段代码后,缓存了位置值,此后uni.getLocation可以正常动作。
这是一段试验代码,并未加入超时、错误和权限检查等功能,只用于临时替换及检验uni.getLocation是否正常工作。
PS:时间原故未做更多研究,不确定是否是BUG,厂家有结果请予以告知。
__getLocation = (options) => {
const p = new Promise((resolve, reject) => {
const isNull = value => !value && reject({
errMsg: "_getLocation fail."
});
isNull(options);
isNull(options.success);
isNull(typeof options.success === "function");
const mainActivity = plus.android.runtimeMainActivity();
isNull(mainActivity);
const LOCATION_SERVICE = plus.android.getAttribute(mainActivity, "LOCATION_SERVICE");
const locationManager = plus.android.invoke(mainActivity, "getSystemService",
LOCATION_SERVICE);
plus.android.autoCollection(mainActivity);
isNull(locationManager);
const criteria = plus.android.newObject("android.location.Criteria");
isNull(criteria);
const ACCURACY_COARSE = criteria.plusGetAttribute("ACCURACY_COARSE");
plus.android.invoke(criteria, "setAccuracy", ACCURACY_COARSE);
plus.android.invoke(criteria, "setAltitudeRequired", false);
plus.android.invoke(criteria, "setBearingRequired", false);
plus.android.invoke(criteria, "setCostAllowed", false);
const POWER_LOW = criteria.plusGetAttribute("POWER_LOW");
plus.android.invoke(criteria, "setPowerRequirement", POWER_LOW);
const provider = plus.android.invoke(locationManager, "getBestProvider", criteria, true);
plus.android.autoCollection(criteria);
isNull(provider);
const location = plus.android.invoke(locationManager, "getLastKnownLocation", provider);
////怀疑是此处无值导致原函数错误
if (location) {
const longitude = plus.android.invoke(location, "getLongitude");
const latitude = plus.android.invoke(location, "getLatitude");
plus.android.autoCollection(location);
resolve({
longitude,
latitude
});
} else {
////location无值则进行监听至有值返回
let instLocationListener = null;
const locationListener = {
"onLocationChanged": function(location) {
if (location) {
const longitude = plus.android.invoke(location, "getLongitude");
const latitude = plus.android.invoke(location, "getLatitude");
plus.android.invoke(locationManager, "removeUpdates",
instLocationListener);
plus.android.autoCollection(instLocationListener);
plus.android.autoCollection(location);
resolve({
longitude,
latitude
});
}
},
"onStatusChanged": function(provider, status, extras) {
console.log(provider, status);
},
"onProviderEnabled": function(provider) {
console.log(provider + " 启用了");
},
"onProviderDisabled": function(provider) {
console.log(provider + " 关闭了");
}
}
instLocationListener = plus.android.implements("android.location.LocationListener",
locationListener);
isNull(instLocationListener);
plus.android.invoke(locationManager, "requestLocationUpdates", provider,
3000, 10,
instLocationListener);
}
});
p.then(res => options.success(res)).catch(err => options.fail && options.fail(err));
};
__getLocation({
success: res => console.log(res)
});
在APP中一直使用uni.getLocation的系统定位模块获取模糊位置,用以查询同城文章。偶然发现最近升级代码后,ANDROID下uni.getLocation无法正常工作,返回error:2错误。在仔细检查后,怀疑是hbuilderx升级后的BUG。写了一段android原生代码工作正常,并在运行一次此代码获取到位置后,再使用uni.getLocation即能正常。有理由怀疑是uni.getLocation使用了getLastKnownLocation导致的,查android文档,getLastKnownLocation返回最近一次位置缓存,并不保证时效及是否有值。所以在运行这段代码后,缓存了位置值,此后uni.getLocation可以正常动作。
这是一段试验代码,并未加入超时、错误和权限检查等功能,只用于临时替换及检验uni.getLocation是否正常工作。
PS:时间原故未做更多研究,不确定是否是BUG,厂家有结果请予以告知。
__getLocation = (options) => {
const p = new Promise((resolve, reject) => {
const isNull = value => !value && reject({
errMsg: "_getLocation fail."
});
isNull(options);
isNull(options.success);
isNull(typeof options.success === "function");
const mainActivity = plus.android.runtimeMainActivity();
isNull(mainActivity);
const LOCATION_SERVICE = plus.android.getAttribute(mainActivity, "LOCATION_SERVICE");
const locationManager = plus.android.invoke(mainActivity, "getSystemService",
LOCATION_SERVICE);
plus.android.autoCollection(mainActivity);
isNull(locationManager);
const criteria = plus.android.newObject("android.location.Criteria");
isNull(criteria);
const ACCURACY_COARSE = criteria.plusGetAttribute("ACCURACY_COARSE");
plus.android.invoke(criteria, "setAccuracy", ACCURACY_COARSE);
plus.android.invoke(criteria, "setAltitudeRequired", false);
plus.android.invoke(criteria, "setBearingRequired", false);
plus.android.invoke(criteria, "setCostAllowed", false);
const POWER_LOW = criteria.plusGetAttribute("POWER_LOW");
plus.android.invoke(criteria, "setPowerRequirement", POWER_LOW);
const provider = plus.android.invoke(locationManager, "getBestProvider", criteria, true);
plus.android.autoCollection(criteria);
isNull(provider);
const location = plus.android.invoke(locationManager, "getLastKnownLocation", provider);
////怀疑是此处无值导致原函数错误
if (location) {
const longitude = plus.android.invoke(location, "getLongitude");
const latitude = plus.android.invoke(location, "getLatitude");
plus.android.autoCollection(location);
resolve({
longitude,
latitude
});
} else {
////location无值则进行监听至有值返回
let instLocationListener = null;
const locationListener = {
"onLocationChanged": function(location) {
if (location) {
const longitude = plus.android.invoke(location, "getLongitude");
const latitude = plus.android.invoke(location, "getLatitude");
plus.android.invoke(locationManager, "removeUpdates",
instLocationListener);
plus.android.autoCollection(instLocationListener);
plus.android.autoCollection(location);
resolve({
longitude,
latitude
});
}
},
"onStatusChanged": function(provider, status, extras) {
console.log(provider, status);
},
"onProviderEnabled": function(provider) {
console.log(provider + " 启用了");
},
"onProviderDisabled": function(provider) {
console.log(provider + " 关闭了");
}
}
instLocationListener = plus.android.implements("android.location.LocationListener",
locationListener);
isNull(instLocationListener);
plus.android.invoke(locationManager, "requestLocationUpdates", provider,
3000, 10,
instLocationListener);
}
});
p.then(res => options.success(res)).catch(err => options.fail && options.fail(err));
};
__getLocation({
success: res => console.log(res)
});
收起阅读 »

找一个懂安卓原生+uniapp插件包兼职开发
需要做一个安卓原生插件包,供uniapp原生代码调用;
主要需求: 自定义扫条码样式功能、自定义扫二维码样式功能、个别特定原生实现需求提供API供uniapp调用。
需要做一个安卓原生插件包,供uniapp原生代码调用;
主要需求: 自定义扫条码样式功能、自定义扫二维码样式功能、个别特定原生实现需求提供API供uniapp调用。

如何在GitHub免费搭建个人博客网站?
如何在GitHub免费搭建个人博客网站?当你想要开始自己的博客之旅,但又不想花费金钱购买服务器和域名时,还有一些免费的平台可供你选择。以下是一种无需服务器和域名的方法,利用GitHub Pages和Jekyll搭建个人博客网站(http://m.bokequ.com/list/22-0.html)
步骤一:准备 GitHub 账户
如果你还没有 GitHub 账户,首先需要注册一个。GitHub 提供免费的代码托管服务,同时也支持通过 GitHub Pages 托管静态网站。
步骤二:创建 GitHub 仓库
登录你的 GitHub 账户,点击右上角的加号按钮,选择 "New repository"。在 "Repository name" 栏中输入你的用户名(或者你希望的博客地址),比如 yourusername.github.io(注意替换成你的用户名)。勾选 "Initialize this repository with a README" 选项,并点击 "Create repository"。
步骤三:下载 Jekyll 主题
Jekyll 是一个简单易用的静态网站生成器,GitHub Pages 支持使用 Jekyll 搭建个人网站。你可以在 Jekyll 官方网站(https://jekyllrb.com/)或 GitHub 上找到各种免费的 Jekyll 主题。选择一个你喜欢的主题,将其下载并解压缩到本地。
步骤四:上传文件到 GitHub 仓库
将 Jekyll 主题文件夹中的所有文件上传到你在步骤二中创建的 GitHub 仓库中。你可以使用 GitHub Desktop、Git 命令行或者直接通过 GitHub 网站上传文件。
步骤五:访问你的博客网站
等待一段时间,GitHub 会自动构建你的网站,并将其托管在bokequ.github.io这个地址上。你可以在浏览器中输入这个地址,访问你的个人博客网站。
步骤六:定制你的博客
编辑 Jekyll 主题文件夹中的配置文件和内容文件,定制你的个人博客。你可以修改页面布局、添加新的页面和文章,以及调整样式和颜色。
通过 GitHub Pages 和 Jekyll,你可以免费搭建个人博客网站,无需购买服务器和域名。这是一个简单且经济高效的方式,让你能够开始你的博客之旅,并与世界分享你的想法和创作。
如何在GitHub免费搭建个人博客网站?当你想要开始自己的博客之旅,但又不想花费金钱购买服务器和域名时,还有一些免费的平台可供你选择。以下是一种无需服务器和域名的方法,利用GitHub Pages和Jekyll搭建个人博客网站(http://m.bokequ.com/list/22-0.html)
步骤一:准备 GitHub 账户
如果你还没有 GitHub 账户,首先需要注册一个。GitHub 提供免费的代码托管服务,同时也支持通过 GitHub Pages 托管静态网站。
步骤二:创建 GitHub 仓库
登录你的 GitHub 账户,点击右上角的加号按钮,选择 "New repository"。在 "Repository name" 栏中输入你的用户名(或者你希望的博客地址),比如 yourusername.github.io(注意替换成你的用户名)。勾选 "Initialize this repository with a README" 选项,并点击 "Create repository"。
步骤三:下载 Jekyll 主题
Jekyll 是一个简单易用的静态网站生成器,GitHub Pages 支持使用 Jekyll 搭建个人网站。你可以在 Jekyll 官方网站(https://jekyllrb.com/)或 GitHub 上找到各种免费的 Jekyll 主题。选择一个你喜欢的主题,将其下载并解压缩到本地。
步骤四:上传文件到 GitHub 仓库
将 Jekyll 主题文件夹中的所有文件上传到你在步骤二中创建的 GitHub 仓库中。你可以使用 GitHub Desktop、Git 命令行或者直接通过 GitHub 网站上传文件。
步骤五:访问你的博客网站
等待一段时间,GitHub 会自动构建你的网站,并将其托管在bokequ.github.io这个地址上。你可以在浏览器中输入这个地址,访问你的个人博客网站。
步骤六:定制你的博客
编辑 Jekyll 主题文件夹中的配置文件和内容文件,定制你的个人博客。你可以修改页面布局、添加新的页面和文章,以及调整样式和颜色。
通过 GitHub Pages 和 Jekyll,你可以免费搭建个人博客网站,无需购买服务器和域名。这是一个简单且经济高效的方式,让你能够开始你的博客之旅,并与世界分享你的想法和创作。
收起阅读 »
favicon.ico图片在线制作PHP源码分享
【在线ICO图标制作】Favicon.ico图片在线制作网站。favicon.ico一般用于作为缩略的网站标志,它显示位于浏览器的地址栏或者在标签上,用于显示网站的logo,如图红圈的位置, 目前主要的浏览器都支持favicon.ico图标http://www.bokequ.com/580.html
【在线ICO图标制作】Favicon.ico图片在线制作网站。favicon.ico一般用于作为缩略的网站标志,它显示位于浏览器的地址栏或者在标签上,用于显示网站的logo,如图红圈的位置, 目前主要的浏览器都支持favicon.ico图标http://www.bokequ.com/580.html
收起阅读 »
uni.getSystemInfoSync() 返回参数:locationEnabled,总是true
文档说是地理位置的系统开关是否打开。但用户在关闭定位权限情况下也返回true。
文档说是地理位置的系统开关是否打开。但用户在关闭定位权限情况下也返回true。