最近看到了uniapp官方推荐的cms插件,本着能改坚决不自己写的原则,使用了一下,功能基本满足需求,只是其中有一个激励广告展示文章内容的部分,默认是使用uniad的广告,不是说uniad不好,但是有部分用户肯定还是会选择使用微信官方的广告,所以我对代码做了一些简单的修改。
改的比较粗糙,毕竟能运行就不动,也是一个比较省力的摸鱼方式。
<template>
<view class="unlock-content">
<!-- #ifdef H5 -->
<!-- 等广告支持H5后优化-->
<button class="text" @click="callAd">点击此处观看广告解锁后续内容</button>
<!-- #endif -->
<!-- #ifndef H5 -->
<button class="text" v-if="!isLoadError" @click="callAd" :loading="adLoading">点击此处观看广告解锁后续内容</button>
<!-- #endif -->
</view>
</template>
<script>
// 实例化数据库
const db = uniCloud.database();
// 定义解锁记录表名
const unlockContentDBName = 'uni-cms-unlock-record';
let videoAd = null;
export default {
name: 'ad',
props: {
adpId: String,
watchAdUniqueType: {
type: String,
default: 'device'
}
},
data() {
return {
currentArticleId: '',
currentPageRoute: '',
adLoading: false,
isLoadError: false
};
},
computed: {
// 是否通过设备观看
watchByDevice() {
return this.watchAdUniqueType === 'device';
},
// 是否通过用户观看
watchByUser() {
return this.watchAdUniqueType === 'user';
},
// 获取唯一ID
uniqueId() {
return this.watchByDevice ? uni.getSystemInfoSync().deviceId : uniCloud.getCurrentUserInfo().uid;
}
},
// #ifndef H5
mounted() {
// 获取当前页面信息
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
this.currentArticleId = currentPage.options.id;
this.currentPageRoute = currentPage.route;
// 如果广告位ID未设置,则提示广告无法正常加载
if (!this.adpId) {
uni.showModal({
content: '广告位ID未设置,广告无法正常加载',
showCancel: false
});
} else {
// 加载广告
this.onAdLoad();
}
},
// #endif
methods: {
// 调用并展示广告
callAd() {
// #ifdef H5
// 如果在浏览器中,则提示需在App或小程序中操作
return uni.showModal({
content: '需观看广告解锁内容, 但浏览器不支持广告播放, 请在App或小程序中操作',
showCancel: false
});
// #endif
if (this.watchByUser) {
// 登录跳转URL 请根据实际情况修改
const redirectUrl =
'/uni_modules/uni-id-pages/pages/login/login-withoutpwd' +
(this.currentPageRoute ? '?uniIdRedirectUrl=' + this.currentPageRoute + '?id=' + this.currentArticleId : '');
//::TODO 支持设备与用户
// 如果用户未登录,则提示需要登录
if (uniCloud.getCurrentUserInfo().tokenExpired < Date.now()) {
uni.showModal({
content: '请登录后操作',
success: ({ confirm }) => {
confirm &&
uni.redirectTo({
url: redirectUrl
});
}
});
}
}
// 显示广告
this.adLoading = true;
// this.$refs.rewardedVideo.show()
if (videoAd) {
videoAd.show().catch(() => {
// 失败重试
videoAd
.load()
.then(() => videoAd.show())
.catch((err) => {
console.error('激励视频 广告显示失败', err);
});
});
}
},
// 广告加载
onAdLoad() {
if (uni.createRewardedVideoAd) {
videoAd = uni.createRewardedVideoAd({
adUnitId: this.adpId
});
videoAd.onLoad(() => {
console.log('广告加载成功');
});
videoAd.onError((err) => {
console.log('广告加载失败');
});
videoAd.onClose((status) => {
if ((status && status.isEnded) || status === undefined) {
console.log('广告展示成功,进行回调');
this.adCallback(status);
} else {
console.log('广告展示中断');
this.adLoading = false;
uni.showModal({
content: '请观看完整视频后解锁全文',
showCancel: false
});
}
});
}
},
//广告完成播放后回调
adCallback(status) {
uniCloud
.callFunction({
name: 'uni-cms-unlock-callback',
data: {
trans_id: this.generateTransID(),
extra: JSON.stringify({
article_id: this.currentArticleId,
unique_id: this.uniqueId,
unique_type: this.watchAdUniqueType
})
}
})
.then((res) => {
if (res.result.isValid) {
//验证成功
let i = 3;
this.adLoading = false;
uni.showLoading({
title: '正在解锁全文',
timeout: 7000
});
let queryResult = setInterval(async () => {
i--;
// 查询解锁记录
const res = await db
.collection(unlockContentDBName)
.where({
unique_id: this.uniqueId,
article_id: this.currentArticleId
})
.get();
// 1. result.data.length 为0 说明没有解锁记录
// 2. i <= 0 说明已经轮询了3次,还是没有解锁记录,说明解锁失败
// 3. result.data.length && i > 0 说明已经解锁成功
if (i <= 0) {
console.log('解锁失败', i);
clearInterval(queryResult);
uni.hideLoading();
uni.showToast({
title: '解锁失败!',
icon: 'error',
duration: 2000
});
} else if (res.result && res.result.data.length) {
console.log('解锁成功', i);
clearInterval(queryResult);
uni.hideLoading();
uni.showToast({
title: '解锁成功!',
icon: 'success',
duration: 2000
});
uni.$emit('onUnlockContent');
}
}, 1500);
}
});
},
onAdError(e) {
uni.hideLoading();
this.isLoadError = true;
console.error('onaderror: ', e);
},
generateTransID(length = 16) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let result = '';
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
result += characters[randomIndex];
}
return result;
}
}
};
</script>
<style scoped lang="scss">
.unlock-content {
text-align: center;
padding: 160rpx 0 60rpx;
position: relative;
margin-top: -140rpx;
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 160rpx;
background: linear-gradient(to bottom, transparent, #fff);
}
.text {
margin-top: 20rpx;
background-color: #fff;
font-size: 30rpx;
background: #6666ff;
color: #ffffff;
// background: linear-gradient(to top, rgba(204, 204, 204, 1.0) 0%, rgba(255, 255, 255, 0) 100%)
}
.text::after {
border: none;
}
}
</style>
主要改动是一个uni-cms-artice插件中的一个unlock-content组件,源代码中使用的是ad-rewarded-video组件,这里我们直接改用微信小程序官方的广告代码,由于官方激励广告并没有云端回调的api,所以我自己写了一个回调,主要就是让后台记录用户已经观看了广告,然后schema的扩展js就会在用户再次访问时直接返回全部内容。
回调中有一个签名验证,感觉没啥用我直接就取消了,如果需要的话本地签名再去验证就行了。具体演示可以查看下面的小程序。