小程序分享模块超级详解

导语:在小程序项目开发中,分享能力几乎是每个项目必备的要求,但原生的分享能力比较有限,不够灵活,今天就我们就一起来研究下,如何在现有基础上,增强小程序分享的能力,使信息传递更加直观、灵活。

示例项目地址: github.com/ycvcb123/sh…

本文目录:

  • 小程序分享基础 API 介绍
  • 基于 canvas 动态绘制分享图片
  • canvas 对不同来源图片的处理(本地图片, 网络图片 , base64图片 )
  • canvas 生成图片后如何保存到本地
  • 如何生成小程序码及验证小程序码所带信息
  • 抽离配置文件,使绘制更加灵活

小程序分享基础 API 介绍

微信分享的 API 只提供了分享给微信好友的能力,并没有提供分享朋友圈的能力,这是为啥子呢!!!

从网上收集的一些咨询来看,主要有如下两点原因:

  1. 由于微商泛滥,公众号鸡汤泛滥,朋友圈质量已经有所下降,如果小程序再开放分享朋友圈功能,可能会进一步影响到整个微信生态,造成用户活跃度下降,用户流失等问题。
  2. 微信不让小程序在朋友圈转发,更多是保护朋友圈的”广告位”阵地,不能够让这块”肥肉”变成了公益设施。

其实一些童鞋应该留意到了在朋友圈,官方已经推了一些小程序的广告,只不过这项能力还没有完全放开,以后会不会放开先不讨论,智慧的开发小哥哥早已想到了通过生成带有小程序码的海报作为替代方案(撒花!!!),本文后面的部分也会说到,我们先回到正题。

用法:

Page({
    onShareAppMessage: function(){
         return {
            title: 'xxxxx', //自定义转发标题
            path: '/page/user?id=123', //分享页面路径
            imageUrl: '/common/images/xxx.png' //分享图片 宽高比 5:4
        }
    }
})
//如果只写成如下形式,title默认是小程序名,path为当前页面路径(不带参数),imageUrl为当前页面截图
Page({
    onShareAppMessage: function(){}
})
复制代码

触发方法(一定要在 page 中先写入上述方法):

  1. 点击小程序的胶囊菜单,会从底部弹出转发选项。
  2. <button> 组件 open-type="share" 即 <button open-type="share"> ,点击后触发。

触发后效果如下:

观察上述结果,不难看出, title 能分享出去的信息非常有限,那我们能不能对分享的图片做些文章,让它带出更多的信息呢?下面进入到我们的第二个部分基于 canvas 动态绘制分享图片

基于 canvas 动态绘制分享图片

因为每个页面的信息很多都是通过接口返回或者用户输入产生,是在不断变化的,设计师所画的静态图片肯定是不足以去展示这些信息的,那么我们就要想,有没有一种办法,是可以把 静态图片动态信息 绘制在一起后在生成一张 新的图片 ?答案是肯定的!!!

把图片和文字画在一起?我们就一定会想到神奇的 canvas ,根据小程序 画布 相关的 API 绘制如下:

//创建画布(组件中一定要绑定this,切记!!!)
var ctx = wx.createCanvasContext('myCanvas', this);
//画布上绘制图片
ctx.drawImage(path, 0, 0, width, height);
//画布上绘制文字
ctx.setFillStyle('#fff');
ctx.setFontSize(32);
ctx.fillText(startTime, 24, 54);
//其他信息绘制
//... 
ctx.draw();
复制代码

上述已经通过 canvas 把图片和文字绘制到了一起,那如何把这个画布转成一个图片,供开发者使用呢?

强大的小程序给我们提供了原生的方法: wx.canvasToTempFilePath

//在上面代码的draw()的回调中使用wx.canvasToTempFilePath
var that = this;
ctx.draw(true, () => {
    setTimeout(() => {
        wx.canvasToTempFilePath({
            canvasId: 'myCanvas',
            success: (res) => { 
                that.setData({
                    //res.tempFilePath 生成图片的临时路径
                    picUrl: res.tempFilePath
                });

            }
        }, that); //在组件中使用这里一定记得要绑定this,切记!!!
    }, 300); //此处加入300毫秒延时是为了解决小程序绘制过程中的渲染问题
});
复制代码

把图片路径传递给 <image> 标签,得到下图结果。

<image src="{{picUrl}}"/>
复制代码

同理:把 picUrl 赋值给 onShareAppMessage 中的 imageUrl ,分享出去后的图片则带有了动态信息!

对不同来源图片的处理(本地图片, 网络图片 , base64图片 )

在上面的例子中,绘制本地图片时直接使用 ctx.drawImage(path, 0, 0, width, height) , path 直接传入图片路径即可。但是如果是 网络图片 或者是 base64 的图片时, drawImage 是无法直接绘制的 ,下面就介绍下针对上述两种情况如何做兼容处理。

  1. 网络来源图片
//将网络图片转换为本地路径
handleNetImg: function(imagePath) {
    var that = this;
    return new Promise((resolve, reject) => {
        wx.getImageInfo({
            src: imagePath,
            success: function(res) {
                resolve(res);
            }
        });
    });
}

handleNetImg('网络图片地址').then((res) => {
    console.log(res.path); //输出转换后的本地图片路径
    ctx.drawImage(res.path, 0, 0, width, height); //此时图片即可在画布上绘制出来
})
复制代码
  1. base64 图片

使用 ctx.drawImage(base64Data, 0, 0, width, height) 在小程序开发者工具上是可以绘制的, 然而!!!这个大骗纸!!!真机上是失效的!!!(心碎一分钟。。。)

跟上面类似的思路,我们把 base64的图片 转为本地的 png图片

var handleBase64Img = function() {
    //wx.getFileSystemManager 小程序文件管理器
    var fsm = wx.getFileSystemManager();
    var FILE_NAME = 'base64src';
    var base64src = function(base64data) {
        return new Promise((resolve, reject) => {
            //解析base64,提取出图片类型: imgtype,解析内容bodyData(去掉data:image/png;base64,以后的内容)
            var [, imgType, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
            if (!imgType) {
                reject(new Error('ERROR_BASE64SRC_PARSE'));
            }
            /**
             *wx.env.USER_DATA_PATH
             *本地用户文件
             *本地用户文件是从 1.7.0 版本开始新增的概念。提供了一个用户文件目录给开发者,开发者对这个目录有完全自由的读写权限。通过 wx.env.USER_DATA_PATH 可以获取到这个目录的路径。
             */
            var filePath = `${wx.env.USER_DATA_PATH}/${FILE_NAME}.${imgType}`;
            //按指定写入文件的字符编码encoding,向地址filepath,写入数据data。
            fsm.writeFile({
                filePath,
                data: bodyData,
                encoding: 'base64',
                success() {
                    resolve(filePath);
                },
                fail() {
                    reject(new Error('ERROR_BASE64SRC_WRITE'));
                },
            });
        });
    };
    return base64src;
}

var base64src = that.handleBase64Img();
var handleBase64src = base64src(base64data);
handleBase64src.then(res => {
    //res 即为base64 转化为图片后的本地路径,即可在画布上绘制成功
    that.ctx.drawImage(res, left, top, width, height);
});
复制代码

通过上述的一些内容,我们已经知道如何利用 canvas 把图片和文字绘制在一起后生成一张新的图片,这里就产生了一个新的问题: 我们如何把生成的图片保存下来呢 ??? 我们接着往细看canvas 生成图片后如何保存到本地

canvas 生成图片后如何保存到相册中

想要保存到相册中第一步首先当然是要获得访问相册的权限!!!

image

//访问相册授权wx.getSetting({
success: (res) => {
//检查是否有访问相册的权限,如果没有则通过wx.authorize方法授权(授权只需要一次就好,后面就可以直接访问相册)
if (!res.authSetting['scope.writePhotosAlbum']) {
console.log('没有获取授权');
wx.authorize({
scope: 'scope.writePhotosAlbum',
success: (res) => {
//用户点击允许获取相册信息后逻辑进入这里,如上图所示
}
})
}
}
});

//获取了相册的访问权限,使用 wx.saveImageToPhotosAlbum 将图片保存到相册中
wx.saveImageToPhotosAlbum({
filePath: that.data.sharePicPath,
success: (res) => {
//保存成功弹出提示,告知一下用户
wx.showModal({
title: '已保存到手机相册',
content: '将图片发送到朋友圈,邀请好友加入',
confirmColor: '#0bc183',
confirmText: '知道了',
showCancel: false
})
}
})
复制代码

如何生成小程序码及验证小程序码所带信息

在小程序的分享朋友圈的解决方案中,往往在生成的海报页面中都会有一个小程序码,使得用户有进入小程序的入口,那么这个小程序码如何生成呢?

官方文档:获取小程序码

注意:因为生成小程序码的接口参数需要 access_token,安全起见,一般都通过后台调用在拿到base64的数据在返回给前端。

我们在回到正题:

上述三种生成接口,大家根据情况按需使用,因为我的项目里,需要经常生成不同页面对应的小程序码, B 类接口比较符合我的要求,这里就重点描述下 B 类接口的 使用 和 自测

B 类接口入参,出参官方说明-- 接口 B:适用于需要的码数量极多的业务场景

重点看下 scene : 最大32个可见字符,有页面路径带参数的情况下要尤其注意!!!

page , scene 等参数传递给后台后,后台调用 B 类接口,返回给前端一个base64的图片数据,我们把这个数据绘制到海报上就好!!!

绘制方法上面已经说过canvas 对不同来源图片的处理(本地图片, 网络图片 , base64图片 )

现在小程序码的图片已经生成了,那么我们要如何自测呢?怎么才能知道小程序码中所携带信息是否正确呢?

官方给出的方法:

上述方法在开发阶段是比较方便,但是在正式的提测阶段,此种方式显得有些牵强,有人想到真机调试?

官方接口只能生成已发布的小程序的二维码

也就是说,你扫码就连上生产环境了!!!没有办法调试,那到底怎么办呢???

解决办法就要借助强大的小程序开发者工具啦!!!

首先把生成的小程序码保存到电脑里,方法见上述canvas 生成图片后如何保存到本地部分。

然后通过开发者工具选择二维码编译模式,文件夹中选择带有小程序码的图片即可!!!

注意: 获取 scene 值时要 decodeURIComponent

Page({
  onLoad(query) {
    // scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene
    const scene = decodeURIComponent(query.scene)
  }
})
复制代码

抽离配置文件,使绘制更加灵活

我们观察如下一个小程序海报:

除了上图红框中的的内容会发生写变化以外,整体的结构大部分是基本已经固定了的,因为海报内容和业务是强相关的,如果我把绘制的逻辑写入组件里,那岂不是换个业务,我的组件就要改一次?这样失去了组件的通用型肯定是不行的,那怎么办呢?下面介绍一个业界比较好的解决方案:

小程序海报说白了就是由 canvas 画布上绘制的一些形状,图片,文字,线等等组成的,那我们是不是可以把这些绘制的基本能力封装成方法,通过设计稿量出海报上每个元素的位置大小等信息,当作一个配置文件传递给这些绘制方法,这样就保证组件的通用型,而且绘制信息抽离成一个配置文件也更加方便后期维护。

share-config.js:

function setShareInfo(time, start, end, imageSrc) {
    return {
        width: 750,
        height: 1300,
        background: '#F2FCF8',
        views: [{
                type: 'rect',
                parent: true,
                radius: true,
                radiusVal: 16,
                left: 40,
                width: 670,
                height: 1140,
                shadow: true,
                background: '#cacacd',
                shadowColor: 'rgba(0,0,0,.6)',
                line: true
            },
            //....
            {
                type: 'text',
                content: '长按或扫描二维码,查看这条线路',
                color: '#9B9BA1',
                top: 1052,
                left: 224,
                fontSize: 28,
                font: 'PingFangSC-Medium',
            },
            {
                type: 'image',
                path: '/common/images/station-flag.png',
                top: 746,
                left: 80,
                width: 32,
                height: 104
            }
        ]
    }
}

export {
    setShareInfo
}
复制代码

只需要在几个动态信息改变时,传入这些变化的值即可。

import { setShareInfo } from '../../common/config/share-config';
page({
    onLoad: function() {
        this.setData({
            shareMessageInfoTimeline: setShareInfo('3月7号 下午16:30发车', '腾讯大厦', '平安国际中心', '')
        });
        //...
    },
});

复制代码

通过 shareMessageInfoTimeline 获取配置信息

<view class="container">
    <mod-share-timeline timelineShow="{{timelineShow}}" picContent="{{shareMessageInfoTimeline}}" bindcloseTimelineShow="closeTimelineShow"/>
</view>
复制代码

总结

本文对小程序分享所需的基础能力进行了拆分详解,把上述能力进行不同的组合,应该可以满足大部分的分享需求。

比如:

  1. 动态绘制分享给微信好友的分享图片。
  2. 生成并保存小程序海报。

作者:你猜我叫啥

原文:小程序分享模块超级详解-实战教程-小程序社区-微信小程序-微信小程序开发社区-小程序开发论坛-微信小程序联盟

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容