背景
我们的公司需要给APP、IOS、小程序对接数商云,而我们的这个几个产品都是通过uni-app去开发的,比较特殊的一点是,我们公司没有专门的原生工程师,因此对接这3个产品的责任就交给了我这个前端去负责。
对接方案
接到这个任务的时候,我首先做的是阅读数商云的文档,数商云提供了以下几种接入方式:小程序SDK、JS SDK、IOS_SDK以及Android_SDK。小程序使用小程序SDK接入就好了,没有问题。问题在于app和ios要如何接入,采用原生的方案对接我一个前端难度很大啊?我想到以前好像看到过说APP/ios是可以通过小程序SDK进行对接的,因此我决定APP和ios也采用小程序SDK去进行对接。
最终我们的项目也是按照此方案进行对接的,也许可以给有类似需求的人们一点启发。
多端产品均采用小程序SDK对接的好处是:
- 对接的方式对前端更为友好
- 小程序、app、ios可以采用同一套方案进行对接
但与此同时也存在一些问题:
- 都采用了小程序SDK导致,无法直接通过数商云判断平台来源(当然也有相应的解决方案,后面会提及)
说干就干,我按照文档安装插件npm install --save shushangyun-masdk
,这时我发现小程序原生和UNI-APP项目还是有区别啊,接入方案生搬硬套文档是行不通的。
大致存在这几个问题:
- uni-app不支持小程序的npm构建
- uni-app的语法和小程序不尽相同
通过观察,比较,我发现它npm构建的内容其实就是node_modules\shushangyun-masdk\miniprogram_dist
现在,我要做的就是要在uni-app引入这个SDK里面的原生自定义组件。通过查阅文档,确定了 [^1]
uni-app 支持在 App 和 小程序 中使用小程序自定义组件。
参考了以下文档:uni-app使用小程序原生自定义组件
在根目录新建wxcomponents文件夹(注意必须要叫这个名字),将npm install --save shushangyun-masdk
下载下来的node_modules\shushangyun-masdk\miniprogram_dist
这个文件夹里的文件复制到新建的文件夹中,结构类似以下这样:
├─pages
│ └─index
├─static
└─wxcomponents
└─components
接着全局注册组件:
// pages.json
{
"pages": [
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
// 注册全局组件
"usingComponents": {
"banner": "/wxcomponents/components/banner",
"trigger": "/wxcomponents/components/trigger"
}
}
}
这时已经引入了原生组件了,但是我们还需要引入数商云的页面,这时,就不能直接引入了,还好在看过代码后,我发现这个page页面比较简单,因此我决定将它转换为普通的.vue页面,新建/pages/webview/index.vue。
// /pages/webview/index.vue
<template>
<web-view :src="path"></web-view>
</template>
<script>
export default {
data () {
return {
path: ''
}
},
onLoad (options) {
let webview = options.webview;
console.log(webview);
let url = decodeURIComponent(unescape(webview));
this.path = url
}
}
</script>
<style lang="scss" scoped>
</style>
修改pages.json文件
{
"pages": [
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app"
}
},
{
"path": "pages/webview/index"
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"usingComponents": {
"banner": "/wxcomponents/components/banner",
"trigger": "/wxcomponents/components/trigger"
}
}
}
现在,可以试着去初始化一下SDK了。
配置App.vue,这里和文档一样,为了方便,直接在启动时就进行上传用户信息,正式使用时应该在登录用户(获取到用户信息)时使用
<script>
const masdk = require('./wxcomponents/index');
export default {
onLaunch: function () {
this.masdkInit()
},
methods: {
// 初始化数商云sdk
masdkInit () {
//初始化sdk,应该在小程序打开的时候就初始化。
masdk.init({
appKey: "应用key",//应用key,必填
appSecret: "应用secret",//应用secret,必填
debug: fasle,//是否开启debug模式,选填,默认为fasle
domain: '服务器地址',//服务器地址,一般不用配置此项,此项只针对私有化部署客户
webviewUrl: '/pages/webview/index',//用来打开活动的页面,选填,默认值是组件提供的webview页面:miniprogram_npm/shushangyun-masdk/pages/webview,如果有需要,此项指针对需要使用自己定义的页面去打开活动的开发者
})
//登录一个测试用户
//上传用户信息,这个方法应该在用户登录之后调用,此例子直接在onLaunch方法里调用了。正式使用时应该在登录用户(获取到用户信息)时使用
masdk.infosUser({
userid: "user12345",
sex: "男",
province: "广东省",
//具体字段以商家自定义的用户表决定。
});
},
},
}
</script>
<style>
/*每个页面公共css */
</style>
同时在需要的地方引入组件
// 根据业务需要使用组件的地方
<template>
<view>
<button size="mini"
type="primary"
plain="true"
@click="triggerDemo">触发Demo</button>
<!--引入这个trigger组件显示触发图标-->
<trigger :param="param" />
<!-- 数商云后台设置的key -->
<banner position-key="后台设置的key"
:swiper-options="swiperOptoins"
default-image="/static/img/image/bg.png" />
</view>
</template>
<script>
const masdk = require('../../wxcomponents/index');
export default {
data () {
return {
param: {}, //数商云触发返回的数据
swiperOptoins: { //投放组件轮播图的配置,配置项请参考小程序的swiper组件
indicatorDots: true,
displayMultipleItems: 1
}
}
},
methods: {
triggerDemo () {
//调用sdk的trigger方法
let infosUser = uni.getStorageSync('infosUser')
try {
infosUser = JSON.parse(infosUser)
if (infosUser && infosUser.userid) {
masdk.trigger({
userid: infosUser.userid, //触发用户id
eventKey: '事件key', // 事件key
conditions: {
loginFrequency: 20,
loginTime: '2019-10-28 08:00:00',
registrationTime: '2019-10-01 08:00:00',
storeConsumption: 10000
}
}).then((res) => {
this.param = res.data
})
.catch((err) => {
console.log(err);
})
}
} catch (error) {
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
这时运行uni-app项目是会报错的,因为数商云的组件引入SDK的路径是错误的。例如:
// /wxcomponents/components/banner.js
// 原始代码是这样的,现在没有用到npm安装依赖,自然不应该这样引入,事实上,好像安装了依赖好像也是引入不了的,我记得当时我是npm安装了的,但是一样会报错
const masdk = require('shushangyun-masdk');
需要改成这样:
// /wxcomponents/components/banner.js 以及 /wxcomponents/components/trigger.js
const masdk = require('../index');
当时的我是这样做的,但是发现还是有报错,Cannot read property 'appKey' of undefined
。这个问题我排查了很久,对比了原生小程序接入SDK,以及debugger,发现正常情况下,小程序组件引入的masdk对象里是会带有初始化时传入的配置信息的,但是uni-app这个项目里的原生组件里的masdk (如: /wxcomponents/components/banner.js 以及 /wxcomponents/components/trigger.js里引入了masdk),里面masdk对象没有初始化到。原因我也不确定,可能是跨模块通信有问题?毕竟本来uni-app是用vue的,引入原生组件,相互通信间可能有一些兼容问题吧。
现在,我遇到的问题是,数商云的对象masdk无法在小程序自定义组件和普通的uni-app页面公用,因此我决定将这个对象存入全局对象globalData中,以解决通信的问题。
// App.vue
globalData: {
// 一般的全局变量使用vuex实现,现在我遇到一个问题,数商云对象masdk无法在小程序自定义组件和普通页面公用,因此采用此种方式实现
masdk
},
同时,自定义的小程序组件也使用globalData的masdk。
// /wxcomponents/components/banner.js 以及 /wxcomponents/components/trigger.js
const masdk = getApp().globalData.masdk;
这时应该就可以调通数商云了,接下来就是根据业务需要进行埋点了。
关于埋点
由于本人即将离职,因此后续的埋点工作我是转交给了同事去进行的。虽然没有直接参与,有些东西还是可以聊聊的。
由于我这个方案,只用了小程序SDK去进行对接,数商云无法直接判断平台来源。
为此我需要传一个条件去标明用户触发的平台是小程序、app、ios。
另外,由于运营那边希望用户不登录也可以触发数商云,因此userid定义了一个特殊的游客id,这个时候,为了让数商云可以方便判断用户是否游客,需要传一个条件去标明用户是否已登录。
大致就是这样,后面如果有需要补充的,我也会继续更新文章。
本文目的
写这篇博客是因为替公司面试前端时,发现一个前端简历上的博客竟然有好几页那么多,想到自己博客里的寥寥几篇文章,心里难免有点波动。又发现自己的github上竟然在别人提了issues两个多月后才看到,心里还是很惊讶的。
工作越来越忙,半年007,挤占了我大部分的时间,连生活的节奏都被打乱,很多希望自己养成的习惯都被放下了。那个面试的前端,她的博客我看了一下,每篇都不是很长,但一直都在坚持,我也想试着实践一下,记录一下自己的一些小小的收获,小小的心得。
参考:
[1]: https://uniapp.dcloud.io/frame?id=%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%BB%84%E4%BB%B6%E6%94%AF%E6%8C%81