实现服务器到服务器的兑换回调

使用服务器到服务器 (S2S) 回调来检测和防止在奖励玩家时作弊。

工作原理

当玩家完整观看视频广告时,Unity Ads 服务器会将签名的回调发送到您指定的 URL。这发生在视频实际结束之前,因此游戏可以在玩家返回游戏之前完成奖励周期。

Tip: Depending on the traffic, callbacks can take some time to arrive. To ensure a smooth gameplay experience, reward players immediately, then use S2S callbacks for sanity checks against cheating. Show the reward notification after the ad view finishes, to avoid distracting the player until the video ends.

实施

要使用 S2S 回调,您需要在显示广告之前设置服务器 ID (sid)。S2S 兑换回调默认不可用。如果您想为您的项目启用它们,请联系支持,并在消息中提供您的游戏 ID及其各自的回调 URL。Unity 会向您发送一个用于签署和验证回调的秘密哈希值。

Unity 示例

要在 C# 代码中实现回调,请将ShowOptions.gamerSid 值设置为您的服务器 ID,然后通过Show 方法传递选项对象。

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]

请参考下表以获取有关查询参数的信息

参数

内容

CALLBACK_URL

回调 URL 的基本 URL,例如

https://developer.example.com/award.php?productid=1234.

要配置此项,请联系支持

SEPARATOR1

如果 URL 中尚未存在 ?,请使用 ?。否则使用 &

SID

您要发送到端点的用户 ID 或任何自定义数据。

SEPARATOR&
OID

由 Unity Ads 服务器生成的唯一优惠 ID。

SEPARATOR&
SIGNATURE

参数字符串的 HDMAC-MD5 哈希值

例如:106ed4300f91145aff6378a355fced73

回调 URL 示例

https://developer.example.com/award.php?productid=1234&sid=1234567890&oid=0987654321&hmac=106ed4300f91145aff6378a355fced73

签署回调 URL

回调 URL 请求将附带一个签署,该签署附加到 URL 参数中。签署是参数字符串的 HDMAC-MD5 哈希值,该字符串通过按字母顺序将所有 URL 参数(除了 HMAC)以键值形式连接起来,并用逗号分隔。

例如,回调 URL 的 SID 和 OID 为

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 已经使用过,或者签署不匹配,或者任何其他导致用户最终未获得承诺物品的错误),服务器应返回 400500 范围内的 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";
?>