示例图:


文献参考:

参考文档:https://zhuanlan.zhihu.com/p/597629702
uni-app官网:uni.createSelectorQuery() | uni-app官网
微信小程序官网:canvas | 微信开放文档

海报内容准备:

1、背景图片
2、二维码
3、用户头像,用户名称
4、简短的描述文案

PS:

1、若使用<canvas type="2d" id="myCanvas"></canvas> 则报错canvasToTempFilePath:fail fail canvas is empty。
2、若canvas不设置canvas-id,则报错<canvas>: canvas-id attribute is undefined(env: Windows,mp,1.06.2308310; lib: 2.25.3)。
3、若只设置canvas-id,则节点信息为null。
const query = uni.createSelectorQuery().in(this); query.select('#canvas').boundingClientRect(data => { console.log("节点信息" + JSON.stringify(data)); // null }).exec();
4、canvas绘制的图片不支持网络图片,因此使用网络需使用uni.getImageInfo获取图片信息。

实现

HTML页面

// 触发按钮
生成海报
// 海报容器

// 生成的海报图片

JS页面

// 单网图
data: {
return {
imgAddRess: "",
shareBg: " https://img2.baidu.com/it/u=3334525604 ,928778682&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1703955600&t=c88ebba9f3d8aeee92c6afd219945f9a",
memberCount: 100,
userImage:"/static/img/code/kong-img.png",
userName: "快乐星球",
shareQrImageUrl: "/static/img/code/kong-img.png"
}
}
// 生成海报
handleClick() {
const _this = this;
// 因shareBg图片为线上图片,需做转换uni.getImageInfo({ src: this.shareBg })
// 单个图片处理
uni.getImageInfo({ src: this.shareBg }).then(res => {
this.shareBg = res[1].path; // 获取转换后的图片路径
this.createdCanvas().then(()=>{
// 绘制需要延迟,不然第一次加载为空白
setTimeout(() => {
// 将生成的canvas图片,转为真实图片-地址
uni.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: "canvass",
success: res => {
_this.imgAddRess = res.tempFilePath;
console.log('真实图片>>>>>>', res);
},
fail: (err) => { console.log('error', err) }
},this);
}, 500);
});
});
},
handleClick2() {
const _this = this;
// 多张图片处理
const Images = [this.shareBg, this.shareQrImageUrl, this.userImage];
Promise.all(Images.map(img => uni.getImageInfo({ src: img }))).then(
imageInfos => {
console.log('Images then>>>>>>', imageInfos);
this.shareBg = imageInfos[0][1].path;
this.shareQrImageUrl = imageInfos[1][1].path;
this.userImage = imageInfos[2][1].path;

//根据参数开始绘图
this.createdCanvas().then(()=>{
// 绘制需要延迟,不然第一次加载为空白
setTimeout(() => {
// 将生成的canvas图片,转为真实图片-地址
uni.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: "canvass",
success: res => {
_this.imgAddRess = res.tempFilePath;
console.log('真实图片>>>>>>', res);
},
fail: (err) => { console.log('error', err) }
},this);
}, 500);
})
}
);
}
createdCanvas(){
const _this = this;
return new Promise((resolve, reject) => {
//绘图上下文
const ctx = uni.createCanvasContext('canvass', this);
uni.createSelectorQuery()
.in(this)
.select('#canvas')
.boundingClientRect(rect => {
if(!rect) return
var width = rect.width;
var height = rect.height;
// 背景图
ctx.drawImage( _this.shareBg, 0, 0, width, height);

// 文案:百位超能大神带你飞
ctx.font = "bold 31px 'DINAlternate-Bold, DINAlternate'"
ctx.setFillStyle('#ff9900');
ctx.setTextAlign('left');
ctx.fillText(_this.memberCount, Math.ceil(width0.32), Math.ceil(height0.103*2)+6);

ctx.setFillStyle('#ff9900');
ctx.setTextAlign('left');
ctx.font = "16px 'PingFangSC-Medium, PingFang SC'"
ctx.fillText('位超能大神带你飞', Math.ceil(width0.32)+66, Math.ceil(height0.103*2));

// 二维码区背景背景
ctx.beginPath();
// r:8 ,
// 起始点
ctx.moveTo(12, height - 92 + 8);
// 左上角
ctx.arcTo(12, height - 92, 12 + 8, height - 92, 8);
// 右上角
ctx.arcTo(width - 12, height - 92, width - 12, height - 92 + 8, 8);
// 右下角
ctx.arcTo(width - 12, height - 12, width - 12 - 8, height - 12, 8);
// 左下角
ctx.arcTo(12, height - 12, 12, height - 12 - 8, 8);
ctx.fillStyle = '#ffffff';
ctx.closePath();
ctx.fill();

//用户头像+用户名
let avatarurl_width = 50; //绘制的头像宽度
let avatarurl_heigth = 50; //绘制的头像高度
let avatarurl_x = 22; //绘制的头像在画布上的位置
let avatarurl_y = height - 77; //绘制的头像在画布上的位置
ctx.save(); // 保存绘图上下文
ctx.beginPath(); // 开始创建一个路径
ctx.arc(
avatarurl_width / 2 + avatarurl_x,
avatarurl_heigth / 2 + avatarurl_y,
avatarurl_width / 2,
0,
Math.PI * 2,
false
); // 画一个圆形裁剪区域
ctx.clip(); // 裁剪
ctx.drawImage(
this.userImage,
avatarurl_x,
avatarurl_y,
avatarurl_width,
avatarurl_heigth
); // //分享人头像-绘制图片x,y轴
ctx.restore(); // 恢复之前保存的绘图上下文

// 分享userName
ctx.setFillStyle('#141414');
ctx.setTextAlign('left');
ctx.font = "bold 16px 'PingFangSC-Medium, PingFang SC'"
let title = _this.userName;
if(title.length>14){
title =title.substr(0,14)+'...'
}
ctx.fillText(title, 80, height - 55) ;

// 分享描述
ctx.setFillStyle('#666666');
ctx.setTextAlign('center');
ctx.font = "11px 'PingFangSC-Regular, PingFang SC'"
ctx.fillText('欢迎来到快乐星球根据地', 140, height - 33);ht - 33);

// 二维码图片
ctx.drawImage(_this.shareQrImageUrl, width - 84, height - 84, 64, 64 );
ctx.draw();
}).exec()
//获取节点
resolve()
})
}

多网图

data: {
return {
imgAddRess: "",
shareBg:" https://img0.baidu.com/it/u=2868999810 ,2001254139&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=714",
shareQrImageUrl: " https://img1.baidu.com/it/u=206225810 ,1732683717&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
avater: " https://img2.baidu.com/it/u=1979438230 ,3745650916&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
}
}
// 生成海报
handleSetImage() {
const _this = this;
const Images = [this.shareBg, this.shareQrImageUrl, this.avater];
let aa = Images.map(img => uni.getImageInfo({ src: img }));

Promise.all(Images.map(img => uni.getImageInfo({ src: img }))).then(
imageInfos => {
console.log('Images then>>>>>>', imageInfos);
this.shareBg = imageInfos[0][1].path;
this.shareQrImageUrl = imageInfos[1][1].path;
this.avater = imageInfos[2][1].path;

//根据参数开始绘图
this.createdCanvas().then(()=>{
// 绘制需要延迟,不然第一次加载为空白
setTimeout(() => {
wx.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: "mc",
success: res => {
_this.imgAddRess = res.tempFilePath;
console.log('真实图片>>>>>>', res);
},
fail:(error)=>{
console.log('error',error)
uni.showToast({
title: error.errMsg,
icon:'none',
duration:2000,
});
}
},this);
}, 500);
})
}
);
},
// 海报绘图
createdCanvas() {
const _this = this;
const query = wx.createSelectorQuery().in(this);
query.select('#mc').boundingClientRect(data => {
console.log("得到布局位置信息" + JSON.stringify(data));
}).exec();

return new Promise((resolve, reject) => {
//绘图上下文
const ctx = wx.createCanvasContext('mc', this);
wx.createSelectorQuery()
.in(this)
.select('#mc')
.boundingClientRect(rect => {
console.log('rect111',rect)
if(!rect) return
var width = rect.width;
var height = rect.height;
let qrw = (width-200) / 2;
let qrh = ((height - 200) / 2 + 80);
// 背景图
ctx.drawImage( _this.shareBg, 0, 0, width, height);

// 头像
ctx.drawImage(_this.avater, (width - 80) / 2 , 50 , 80, 80 );

// 文案
ctx.setFillStyle('#ffffff');
ctx.setTextAlign('center');
ctx.font = "bold 26px 'PingFangSC-Medium, PingFang SC'"
ctx.fillText('超能小飞侠', 180, 170, width);

ctx.font = "bold 16px 'DINAlternate-Bold, DINAlternate'"
ctx.setFillStyle('#000000');
ctx.setTextAlign('center');
ctx.fillText("诚邀您参与超能封神", 185, 205, width); // (文本,X坐标,Y坐标, 最大宽度)

// 二维码:(图片,X坐标,Y坐标, 图宽,图高)
ctx.drawImage(_this.shareQrImageUrl, qrw , qrh , 200, 200 );
//二维码图片
ctx.draw();
}).exec()
//获取节点
resolve()
})
},

检测版本与自行安装

<view @click="handleUpdate">检测新版本</view>
const handleUpdate = () => {
	try {
		// 获取当前应用版本
		const currentVersion = plus.runtime.version;
		console.log("获取当前应用版本: ", currentVersion)
	
		// 请求服务器,获取最新版本信息
		const res = await uni.request({
	 	url: 'https://localhost:5566/check-update', // 查询最新版本接口
	 	method: 'GET',
	 	data: {
			version: currentVersion
		}
	 });
	
	// const serverData = res.data;
	// 假设服务器返回 
	const serverData = { 
			update: true, 
			latest: '1.1.0', 
			fileName: "check_"+dayjs().format("YYYYMMDDHHmmss")+".apk",
			url: 'https://app.liuyingyong.cn/build/download/8bef5430-8d5b-11f0-a322-2597c8f390f2',
			note: '测试自行安装', force: false }
		if (serverData.update && serverData.latest > currentVersion) {
			showUpdateDialog(serverData); // 显示更新弹窗
		}
	} catch (error) {
		console.error('检查更新失败:', error);
	}
}
function showUpdateDialog(updateInfo) {
	uni.showModal({
		title: `发现新版本 ${updateInfo.latest}`,
		content: updateInfo.note || '本次更新带来了全新的功能和体验',
		confirmText: '立即更新',
		cancelText: updateInfo.force ? null : '稍后再说', // 强制更新时可能不显示取消按钮
		success: (res) => {
			if (res.confirm) {
				downloadApk(updateInfo.url); // 开始下载APK
			} else if (updateInfo.force) {
				// 如果是强制更新,用户取消则退出应用
				plus.runtime.quit();
			}
		}
	});
}
function downloadApk(apkUrl) {
	uni.showLoading({
		title: '准备下载...',
		mask: true
	});

	// 创建下载任务
	const downloadTask = plus.downloader.createDownload(
		apkUrl, {
			filename: '_doc/download/check_new.apk' // 文件保存路径,_doc 目录可读写
		},
		(download, status) => {
			console.log("打印download:", download, status)
			uni.hideLoading();
			if (status === 200) {
				uni.showToast({
					title: '下载完成,开始安装',
					icon: 'none'
				});
				installApk(download.filename); // 下载完成,开始安装
			} else {
				uni.showToast({
					title: '下载失败,请重试',
					icon: 'none'
				});
				console.error('Download failed, status:', status);
			}
		}
	);

	// 监听下载进度变化
	downloadTask.addEventListener('statechanged', (task, status) => {
		if (task.downloadedSize && task.totalSize) {
			const percent = (task.downloadedSize / task.totalSize * 100).toFixed(0);
			uni.showLoading({
				title: `下载中 ${percent}%`,
				mask: true
			}); // 或更新自定义进度条组件
		}
	});

	downloadTask.start(); // 启动下载任务
}
function installApk(filePath) {
	plus.runtime.install(
		filePath, {
			force: false // 是否强制安装
		},
		function() {
			console.log('安装成功,重启应用');
			plus.runtime.restart(); // 安装成功,重启应用
		},
		function(e) {
			uni.showToast({
				title: '安装失败',
				icon: 'none'
			});
			console.error('安装失败:', e);
		}
	);
}
posted on 2024-01-14 20:03  羽丫头不乖  阅读(1464)  评论(0)    收藏  举报