UniApp对接文档
TIP
- 请勿使用模拟器运行调试广告,媒体方也要限制禁止模拟器登录或者一个手机同时登录多个账号的行为
- Demo里面的测试ID,只供查看广告效果,通过运行->运行到手机或模拟器->运行到Android基座->标准基座
- 正式广告ID运行调试步骤,发行->原生APP-云打包->打自定义调试基座(广告模块需要勾选)->自定义基座打包完成后再通过运行->运行到手机或模拟器->运行到Android基座->自定义基座
- 广告测试阶段建议每个设备每天调用广告次数在15次左右,中间要有10s的间隔时间,否则可能触发系统的反作弊策略,导致填充降低,收益降低,应用上线后也应该做对应调整
- 调试阶段遇到广告不显示的情况,请提供
@error
事件中的错误信息,截图发在群里
广告错误码
code | message |
---|---|
5001 | 广告位标识adpid为空,请传入有效的adpid |
5002 | 无效的广告位标识adpid,请使用正确的adpid |
5003 | 未开通广告,请在广告平台申请并确保已审核通过 |
5004 | 无广告模块,打包时请配置要使用的广告模块 |
5005 | 广告加载失败,请过段时间重新加载,否则可能触发系统策略导致流量收益下降 |
5006 | 广告未加载完成无法播放,请加载完成后再调show播放 |
5007 | 无法获取广告配置数据,请尝试重试 |
5008 | 广告已过期,请重新加载数据 |
5010 | 其他错误,聚合广告商内部错误 |
IP白名单配置
阿里云
47.92.132.2
47.92.152.34
47.92.87.58
47.92.207.183
8.142.185.204
腾讯云
在UniCloud web控制台,创建付费的腾讯云服务空间,选择一个云函数,在云函数的详情界面可以开启固定出口ip。开启后界面上会显示可用的固定ip。拿着这个ip去需要固定ip的界面(如微信公众号管理界面)配置即可。
打包配置
下面截图为打包时需要勾选的内容
Banner广告
应用内展示的广告组件,可用于banner或信息流。
适用场景
Banner或信息流广告展现场景非常灵活,常见的展现场景为:文章顶部,详情页面顶部,第一屏中部等。建议信息流广告不要放置在底部
代码参考Demo里面pages/index/banner/banner
语法
<template>
<view class="content">
<!-- adpid="1111111111" 此广告位标识仅在HBuilderX标准基座中有效,仅用于测试 -->
<!-- 广告后台申请的广告位(adpid)需要自定义基座/云打包/本地打包后生效 -->
<view class="ad-view">
<ad adpid="1111111111" @load="onload" @close="onclose" @error="onerror"></ad>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'ad',
name:'banner广告、信息流广告、小程序格子广告、小程序视频广告、小程序banner广告'
}
},
methods: {
onload(e) {
console.log("onload");
},
onclose(e) {
console.log("onclose: " + e.detail);
},
onerror(e) {
console.log("onerror: " + e.detail.errCode + " message:: " + e.detail.errMsg);
}
}
}
</script>
<style>
.content {
background-color: #DBDBDB;
padding: 10px;
}
.ad-view {
background-color: #FFFFFF;
margin-bottom: 10px;
}
</style>
- 属性说明
属性名 | 说明 |
---|---|
adpid | 广告位ID |
@load | 广告的加载事件 |
@close | 用户点击广告的关闭按钮事件 |
@error | 广告错误事件,所有广告本身的错误都会触发这个事件 |
全屏视频
全屏视频广告是一个原生组件,层级比普通组件高。全屏视频广告每次创建都会返回一个全新的实例,默认是隐藏的,需要调用 FullScreenVideoAd.show() 将其显示。
代码参考Demo里面pages/index/ad-fullscreen-video/ad-fullscreen-video
语法
<template>
<view>
<ad-fullscreen-video ref="adFullscreenVideo" adpid="1507000611" :preload="false" :loadnext="false"
:disabled="true" v-slot:default="{loading, error}" @load="onadload" @close="onadclose" @error="onaderror">
<view class="ad-error" v-if="error">{{error}}</view>
</ad-fullscreen-video>
<button type="primary" @click="showAd">显示广告</button>
</view>
</template>
<script>
export default {
data() {
return {
name:'全屏视频,不建议对接,直接对接激励视频即可'
}
},
onReady() {
this.$refs.adFullscreenVideo.load();
},
methods: {
showAd() {
this.$refs.adFullscreenVideo.show();
},
onadload(e) {
console.log('广告数据加载成功');
},
onadclose(e) {
const detail = e.detail
// 用户点击了【关闭广告】按钮
if (detail && detail.isEnded) {
// 正常播放结束
console.log("onClose " + detail.isEnded);
} else {
// 播放中途退出
console.log("onClose " + detail.isEnded);
}
this.$refs.adFullscreenVideo.load();
},
onaderror(e) {
// 广告加载失败
console.log(e.detail);
}
}
}
</script>
<style>
.ad-error {
color: orangered;
margin-top: 5px;
}
</style>
属性名 | 说明 |
---|---|
adpid | 广告位ID |
preload | 页面就绪后加载广告数据(默认:true) |
loadnext | 自动加载下一条广告数据(默认:false) |
v-slot:default="{loading, error}" | 作用域插槽可以在页面中展示广告的错误信息 |
@load | 广告的加载事件 |
@close | 用户点击广告的关闭按钮事件 |
@error | 广告错误事件,所有广告本身的错误都会触发这个事件 |
插屏广告
插屏广告组件是由客户端原生的图片、文本、视频控件组成的;插屏广告与信息流或横幅广告相比展现尺寸更大,同样能够满足您对大量曝光和用户转化的需求。
代码参考Demo里面pages/index/ad-interstitial/ad-interstitial
语法
<template>
<view>
<ad-interstitial ref="adInterstitial" adpid="1111111113" :loadnext="false" v-slot:default="{loading, error}" @load="onadload" @close="onadclose" @error="onaderror">
<view v-if="error">{{error}}</view>
</ad-interstitial>
<button type="primary" @click="showAd">显示广告</button>
</view>
</template>
<script>
export default {
data() {
return {
name:'插屏广告'
}
},
methods: {
showAd() {
this.$refs.adInterstitial.show();
},
onadload(e) {
console.log('广告数据加载成功');
},
onadclose(e) {
// 用户点击了关闭广告
console.log("onadclose",e);
},
onaderror(e) {
// 广告加载失败
console.log("onaderror: ", e.detail);
}
}
}
</script>
属性名 | 说明 |
---|---|
adpid | 广告位ID |
preload | 页面就绪后加载广告数据(默认:true) |
loadnext | 自动加载下一条广告数据(默认:false) |
v-slot:default="{loading, error}" | 作用域插槽可以在页面中展示广告的错误信息 |
@load | 广告的加载事件 |
@close | 用户点击广告的关闭按钮事件 |
@error | 广告错误事件,所有广告本身的错误都会触发这个事件 |
激励视频
激励视频广告,是cpm收益最高的广告形式。手机用户观看几十秒视频广告,在广告播放完毕后可获得应用开发商提供的奖励,而应用开发商则可以从广告平台获取不菲的广告收入。
代码参考Demo里面pages/index/ad-rewarded-video/ad-rewarded-video
语法
<template>
<view>
<ad-rewarded-video ref="adRewardedVideo" :url-callback="urlCallback" adpid="1507000689" :preload="false"
:loadnext="false" :disabled="true" v-slot:default="{loading, error}" @load="onadload" @close="onadclose"
@error="onaderror">
<view class="ad-error" v-if="error">{{error}}</view>
</ad-rewarded-video>
<button type="primary" @click="showAd">显示广告</button>
</view>
</template>
<script>
export default {
data() {
return {
// 服务器回调参数,没开启可以不写
urlCallback: {
userId: 'testuser',
extra: 'testdata'
},
name:'激励视频'
}
},
onReady() {
this.$refs.adRewardedVideo.load();
},
methods: {
showAd() {
this.$refs.adRewardedVideo.show();
},
onadload(e) {
console.log('广告数据加载成功');
},
onadclose(e) {
const detail = e.detail
// 用户点击了【关闭广告】按钮
if (detail && detail.isEnded) {
// 正常播放结束
console.log("onClose " + detail.isEnded);
} else {
// 播放中途退出
console.log("onClose " + detail.isEnded);
}
// 播放完毕 手动加载下一条广告
this.$refs.adRewardedVideo.load();
},
onaderror(e) {
// 广告加载失败
console.log(e.detail);
}
}
}
</script>
<style>
.ad-error {
color: orangered;
margin-top: 5px;
}
</style>
服务器回调
激励视频广告可以支持广告服务器到业务服务器的回调,用于业务系统判断是否提供奖励给观看广告的用户。配置服务器回调后,当用户成功看完广告时,广告服务器会访问配置的云函数,通知用户完成观看激励视频。
相对来讲服务器回调将更加安全,可以依赖广告平台的反作弊机制来避免用户模拟观看广告完成的事件。
开通流程
- 登录UniCloud web控制台,新建服务空间(以应用名称命名)
- 在云空间内,将
Yousshkj@163.com
添加为协作者 - 可以选择本地接口或者使用云函数,然后在群里发出云空间名称及云函数名称(接口地址)
- 开通之后会自动创建一个云函数
uniAdCallback
,不可手动调用,自己新建的云函数不可与这个同名
详细说明
云函数例子(本地接口也可以参照)
secret会在群里发出
'use strict';
const { log } = require('console');
const crypto = require('crypto');
const db = uniCloud.database();
const collectionName = 'xxxxxxx'; // 如果选择了腾讯云,需要手动预创建表
class DB {
static save(data) {
return new DB().add(data);
}
add(data) {
const collection = db.collection(collectionName);
const data2 = Object.assign(data, {
ad_type: 0,
create_date: new Date(),
});
return collection.add(data2);
}
}
exports.main = async (event, context) => {
//event为客户端上传的参数
const { path, queryStringParameters } = event;
const data = {
adpid: event.adpid, // 广告位ID
platform: event.platform, //平台 IOS/安卓
provider: event.provider, // 广告的服务商
trans_id: event.trans_id, // 交易id 用户完成观看的交易id
sign: event.sign, // 签名
user_id: event.user_id, // 用户的唯一标识
extra: event.extra, // 自定义的数据,可以为空
};
log(data)
// 注意::必须验签请求来源
const secret =
'xxxxxxxxxxxxxxxxxxxxxxxxx'; // uni-AD Web控制台,找到广告位,点击配置激励视频,展开当前广告位项,可看到生成的 Security key
const trans_id = event.trans_id;
const sign2 = crypto
.createHash('sha256')
.update(`${secret}:${trans_id}`)
.digest('hex');
if (event.sign !== sign2) {
log('签名不一致')
return null;
}
// 可选将回调记录保存到uniCloud,避免用户服务器没有响应时有日志可查,如果选择了保存记录需要做定时清理日志,避免日志过多影响性能
try {
await DB.save(data);
} catch (e) {
console.log(e);
}
return {
isValid: true,
}
};
页面代码
需要携带urlCallback字段 userId为用户唯一标识,extra为自定义数据
<template>
<view class="content">
<ad-rewarded-video adpid="1507000689" :url-callback="urlCallback" :loadnext="true" v-slot:default="{loading, error}">
<button :disabled="loading" :loading="loading">显示广告</button>
<view v-if="error">{{error}}</view>
</ad-rewarded-video>
</view>
</template>
<script>
export default {
data() {
return {
urlCallback: {
userId: 'testuser',
extra: 'testdata'
}
}
}
}
</script>
短视频广告
⼀个视频内容频道,支持上下滑动切换视频内容(类似于抖音)
代码参考pages/index/ad-content-page/ad-content-page
语法
TIP
页面必须是nvue页面
<template>
<view class="content">
<ad-content-page class="ad-content-page" ref="adContentPage" adpid="1111111112" @load="onadload" @error="onaderror"></ad-content-page>
</view>
</template>
<script>
export default {
data() {
return {
title: '短视频联盟广告、类似于快手、抖音等短视频的内容、自带填充内容、收益较低 用来引流'
}
},
onShow() {
this.$nextTick(() => {
// 需要在页面显示时调用广告组件的 show 方法
this.$refs.adContentPage.show();
})
},
onHide() {
// 需要在页面隐藏时调用广告组件的 hide 方法停止广告内容的声音
this.$refs.adContentPage.hide();
},
methods: {
onadload(e) {
console.log("onadload",e);
},
onaderror(e) {
console.log("onaderror",e);
}
}
}
</script>
<style>
.content {
flex: 1
}
.ad-content-page {
flex: 1
}
</style>
属性名 | 说明 |
---|---|
adpid | 广告位ID |
@load | 广告的加载事件 |
@close | 用户点击广告的关闭按钮事件 |
@error | 广告错误事件,所有广告本身的错误都会触发这个事件 |
@start | 开始时触发 |
@pause | 暂停时触发 |
@resume | 恢复播放时触发 |
@complete | 播放完成触发 |
Draw视频流广告
也称为Draw视频信息流广告
沉浸视频流广告为媒体提供了竖屏视频信息流广告样式,适合在全屏的竖屏视频中使用。支持app-nvue页面使用。
代码参考pages/index/ad-draw/ad-draw
语法
TIP
页面必须是nvue页面
<template>
<!-- 仅nvue页面支持 -->
<!-- 必须指定ad-draw的宽度和高度,否则大小全屏 -->
<view class="container">
<swiper vertical class="swiper">
<swiper-item>
<ad-draw id="demo1" class="ad-draw" adpid="1507000690" @load="onload" @error="onerror"></ad-draw>
</swiper-item>
<swiper-item>
<ad-draw id="demo2" class="ad-draw" adpid="1507000690" @load="onload" @error="onerror"></ad-draw>
</swiper-item>
<swiper-item>
<ad-draw id="demo3" class="ad-draw" adpid="1507000690" @load="onload" @error="onerror"></ad-draw>
</swiper-item>
<swiper-item>
<ad-draw id="demo4" class="ad-draw" adpid="1507000690" @load="onload" @error="onerror"></ad-draw>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
data() {
return {}
},
methods: {
onload(e) {
console.log("onload", e);
},
onerror(e) {
console.log("onerror: " + e.detail.errCode + " message:: " + e.detail.errMsg);
}
}
}
</script>
<style>
.container {
flex: 1;
height: 1500rpx;
}
.swiper{
height: 1500rpx;
}
.ad-draw {
flex: 1;
height: 1500rpx;
width: 750rpx;
}
</style>
属性名 | 说明 |
---|---|
adpid | 广告位ID |
@load | 广告的加载事件 |
@error | 广告错误事件,所有广告本身的错误都会触发这个事件 |
webview内容对接
步骤
// 在项目终端,先运行npm init 然后 npm i shenshiad 或者 yarn add shenshiad
npm init
npm i shenshiad / yarn add shenshiad
周公解梦
<template>
<view class="container">
<web-view :update-title="false" src="https://fpvideo.shenshiads.com/h5/zhougong/index.html?t=3"
@message="handlerMessage">
</web-view>
</view>
</template>
<script>
import {
adReward,
rewardedVideoInit
} from 'shenshiad/ads.js'
export default {
data() {
return {
data: {
userId: '17601336219',
extra: 'xxx'
},
wv: null,
}
},
onReady() {},
onLoad() {
let currentWebview = this.$scope.$getAppWebview();
setTimeout(() => {
this.wv = currentWebview.children()[0];
}, 1000)
},
methods: {
handlerMessage(type) {
let that = this
// 激励
if (type.detail.data[0].type == 'reward') {
this.data.extra = 'reward'
rewardedVideoInit('1507000689', this.data)
adReward.onLoad(function() {
console.log('加载成功')
adReward.show();
});
adReward.onError(function(e) {
console.log('加载失败: ' + JSON.stringify(e));
adReward.destroy();
adReward = null;
});
adReward.onClose(function(e) {
if (e.isEnded) {
console.log('激励视频播放完成');
plus.nativeUI.toast('激励视频播放完成');
return that.sendSuccess()
} else {
console.log('激励视频未播放完成关闭!')
return that.sendErr()
}
adReward.destroy();
adReward = null;
});
adReward.load();
}
},
sendErr(res = '', plt = 0) {
this.wv.evalJS(`onError('${res}')`);
},
sendSuccess(res = '', plt = 0) {
this.wv.evalJS(`onSuccess('${res}')`);
},
}
}
</script>
今日黄历
<template>
<view class="container">
<web-view :update-title="false" src="https://fpvideo.shenshiads.com/h5/calendar/index.html?t=3"
@message="handlerMessage">
</web-view>
</view>
</template>
<script>
import {
adReward,
rewardedVideoInit
} from 'shenshiad/ads.js'
export default {
data() {
return {
data: {
userId: '17601336219',
extra: 'xxx'
},
wv: null, // 定义(app)webview对象节点
}
},
onReady() {},
onLoad() {
let currentWebview = this.$scope.$getAppWebview();
setTimeout(() => {
this.wv = currentWebview.children()[0];
}, 1000)
},
methods: {
handlerMessage(type) {
let that = this
// 激励
if (type.detail.data[0].type == 'reward') {
this.data.extra = 'reward'
rewardedVideoInit('1507000689', this.data)
adReward.onLoad(function() {
console.log('加载成功')
adReward.show();
});
adReward.onError(function(e) {
console.log('加载失败: ' + JSON.stringify(e));
adReward.destroy();
adReward = null;
});
adReward.onClose(function(e) {
if (e.isEnded) {
console.log('激励视频播放完成');
plus.nativeUI.toast('激励视频播放完成');
if (type.detail.data[0].msg === 'good') {
return that.sendGoodSuccess()
}
if (type.detail.data[0].msg === 'bad') {
return that.sendBadSuccess()
}
} else {
console.log('激励视频未播放完成关闭!')
if (type.detail.data[0].msg === 'good') {
return that.sendGoodErr()
}
if (type.detail.data[0].msg === 'bad') {
return that.sendBadErr()
}
}
adReward.destroy();
adReward = null;
});
adReward.load();
}
},
sendGoodErr(res = '', plt = 0) {
this.wv.evalJS(`onGoodError('${res}')`);
},
sendGoodSuccess(res = '', plt = 0) {
this.wv.evalJS(`onGoodSuccess('${res}')`);
},
sendBadErr(res = '', plt = 0) {
this.wv.evalJS(`onBadError('${res}')`);
},
sendBadSuccess(res = '', plt = 0) {
this.wv.evalJS(`onBadSuccess('${res}')`);
}
}
}
</script>