实现服务器到服务器兑换回调
在奖励玩家时可使用服务器到服务器 (S2S) 回调来检测和防止作弊。
工作原理
当玩家完整观看视频广告时,Unity 广告服务器会向您指定的 URL 发送已签名的回调。这个过程发生在视频实际结束之前,因此可以在玩家返回游戏之前完成奖励循环。
提示:根据流量,回调可能需要一些时间才能到达。为确保顺畅的游戏体验,请立即奖励玩家,然后使用 S2S 回调进行完整性检查以防作弊。为避免在视频结束之前分散玩家的注意力,应在广告观看结束之后再显示奖励通知。
实现
要使用 S2S 回调,您需要在展示广告之前设置服务器 ID (sid)。默认情况下,S2S 兑换回调不可用。如果您需要为项目启用这些回调,请联系支持团队,并在消息中提供您的 Game ID(游戏 ID)及其各自的回调 URL。Unity 将向您发送用于签名和验证回调的密钥哈希值。
Unity 示例
要在 C# 代码中实现回调,请将 ShowOptions.gamerSid
值设置为您的服务器 ID,然后通过 Show
方法传递 options 对象。
using UnityEngine;
using System.Collections;
using UnityEngine.Advertisements;
public class UnityAdsManager : MonoBehaviour
{
public string gameId;
public string placement = "rewardedVideo"
public void ShowAd() {
ShowOptions options = new ShowOptions();
// setting the server ID
options.gamerSid = "your-side-id";
Advertisement.Show(placementID, options);
}
}
Android 示例
要在 Java 代码中实现回调,请将 PlayerMetaData.setServerId
值设置为您的服务器 ID。
PlayerMetaData playerMetaData = new PlayerMetaData(context);
playerMetaData.setServerId("example");
playerMetaData.commit();
UnityAds.show(activity);
iOS 示例
要在 Objective-C 代码中实现回调,请将 playerMetaData.setServerId
值设置为您的服务器 ID。
id playerMetaData = [[UADSPlayerMetaData alloc] init];
[playerMetaData setServerId:@"example"];
[playerMetaData commit];
[UnityAds show:self
placementId: placementId
showDelegate: showDelegate];
回调信息
回调来源
回调将来自于此处列出的 IP 地址/网络。该列表将在每个月的第一天更新。发行商可以放心忽略或阻止来自任何其他地方的回调。
回调 URL 格式
该请求是对以下格式的 URL 的 HTTP/1.1 GET
请求:
[CALLBACK_URL][SEPARATOR1]sid=[SID][SEPARATOR]oid=[OID][SEPARATOR]hmac=[SIGNATURE]
有关 query 参数的信息,请参阅下表:
参数 | 内容 |
---|---|
CALLBACK_URL | 回调 URL 的基 URL,例如:
要配置此参数,请联系支持团队 |
SEPARATOR1 | 如果 URL 中不存在 |
SID | 用户 ID 或要发送到终端的任何自定义数据。 |
SEPARATOR | & |
OID | Unity Ads 服务器生成的唯一 Offer ID(优惠 ID)。 |
SEPARATOR | & |
SIGNATURE | 参数字符串的 HDMAC-MD5 哈希值 例如: |
回调 URL 示例
https://developer.example.com/award.php?productid=1234&sid=1234567890&oid=0987654321&hmac=106ed4300f91145aff6378a355fced73
回调 URL 的签名
回调 URL 请求会将一个签名附加到 URL 参数。该签名是通过以键值形式连接所有 URL 参数(HMAC 除外,按字母顺序排列并以逗号分隔)创建的参数字符串的 HDMAC-MD5 哈希值。
例如,一个包含 SID 和 OID 的回调 URL
https://developer.example.com/award.php?productid=1234&sid=1234567890&oid=0987654321
将具有以下参数字符串:
oid=0987654321,productid=1234,sid=1234567890
此字符串与您即将从支持团队收到的密钥进行哈希处理后,返回一个由奖励回调触发为 URL 的哈希值。例如:
https://developer.example.com/award.php?productid=1234&sid=1234567890&oid=0987654321&hmac=106ed4300f91145aff6378a355fced73
**重要:**回调 URL 中包含的所有参数必须按字母顺序用于签名计算。否则,签名将不匹配。
回调响应
如果该请求通过了所有检查并且用户获得了奖励物品,则 URL 必须以 HTTP/1.1 200 OK
响应作为应答并在 HTTP 请求的正文中包含字符 1
。例如:
回调响应示例
HTTP/1.1 200 OK
Date: Wed, 22 Feb 2012 23:59:59 GMT
Content-Length: 8
1
如果出现错误(例如,OID 已被使用,或签名不匹配,或者当用户未能获得承诺物品时的任何其他错误),服务器应返回 400
或 500
范围内的 HTTP 错误,并显示人类可读的错误。例如:
回调错误响应示例
HTTP/1.1 400 ERROR
Date: Wed, 22 Feb 2012 23:59:59 GMT
Content-Length: 12
Duplicate order
node.js 中的回调示例
以下示例演示了如何使用 node.js + express 来验证签名:
node.js 中的回调示例
// NODE.js S2S callback endpoint sample implementation
// Unity Ads
var express = require('express');
var crypto = require('crypto')
var app = express();
app.listen(process.env.PORT || 3412);
function getHMAC(parameters, secret) {
var sortedParameterString = sortParams(parameters);
return crypto.createHmac('md5', secret).update(sortedParameterString).digest('hex');
}
function sortParams(parameters) {
var params = parameters || {};
return Object.keys(params)
.filter(key => key !== 'hmac')
.sort()
.map(key => params[key] === null ? `${key}=` : `${key}=${params[key]}`)
.join(',');
}
app.get('/', function (req, res) {
var sid = req.query.sid;
var oid = req.query.oid;
var hmac = req.query.hmac;
// Save the secret as an environment variable. If none is set, default to xyzKEY
var secret = process.env.UNITYADSSECRET || 'xyzKEY';
var newHmac = getHMAC(req.query, secret);
if (hmac === newHmac) {
// Signatures match
// Check for duplicate oid here (player already received reward) and return 403 if it exists
// If there's no duplicate - give virtual goods to player. Return 500 if it fails.
// Save the oid for duplicate checking. Return 500 if it fails.
// Callback passed, return 200 and include '1' in the message body
res.status(200).send('1');
} else {
// no match
res.sendStatus(403);
}
});
PHP 中的回调示例
以下示例演示了如何在 PHP 中验证签名:
PHP 中的回调示例
<?php
function generate_hash($params, $secret) {
ksort($params); // All parameters are always checked in alphabetical order
$s = '';
foreach ($params as $key => $value) {
$s .= "$key=$value,";
}
$s = substr($s, 0, -1);
$hash = hash_hmac('md5', $s, $secret);
return $hash;
}
$hash = $_GET['hmac'];
unset($_GET['hmac']);
$signature = generate_hash($_GET, 'xyzKEY'); // insert here the secret hash key you received from Unity Ads support
error_log("req hmac".$hash);
error_log("sig hmac".$signature);
// check signature
if($hash != $signature) { header('HTTP/1.1 403 Forbidden'); echo "Signature did not match"; exit; }
// check duplicate orders
if(check_duplicate_orders($_GET['oid']) { header('HTTP/1.1 403 Forbidden'); echo "Duplicate order"; exit; }
// if not then give the player the item and check that it succeeds.
if(!give_item_to_player($_GET['sid'], $_GET['product']) { header('HTTP/1.1 500 Internal Server Error'); echo "Failed to give item to the player"; exit; }
// save the order ID for duplicate checking
if(save_order_number($_GET['oid']) { header('HTTP/1.1 500 Internal Server Error'); echo "Order ID saving failed, user granted item"; exit; }
// everything OK, return "1"
header('HTTP/1.1 200 OK');
echo "1";
?>