在奖励玩家时可使用服务器到服务器 (S2S) 回调来检测和防止作弊。
工作原理
当玩家完整观看视频广告时,Unity 广告服务器会向您指定的 URL 发送已签名的回调。这个过程发生在视频实际结束之前,因此可以在玩家返回游戏之前完成奖励循环。

实现
要使用 S2S 回调,您需要在展示广告之前设置服务器 ID (sid)。默认情况下,S2S 兑换回调不可用。如果您需要为项目启用这些回调,请联系支持团队,并在消息中提供您的 Game ID(游戏 ID)及其各自的回调 URL。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); } }
要在 Java 代码中实现回调,请将 PlayerMetaData.setServerId
值设置为您的服务器 ID。
PlayerMetaData playerMetaData = new PlayerMetaData(context); playerMetaData.setServerId("example"); playerMetaData.commit(); UnityAds.show(activity);
要在 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 必须以 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"; ?>