自管理虚拟货币

自管理虚拟货币当您使用您自己的服务器管理货币时使用。这种方式可以让您更好的管理您的用户的货币,同时也意味着您要负责存储和分发用户的货币。getCurrencyBalance, awardCurrency, 和 spendCurrency接口只在Tapjoy管理货币可用。Tapjoy并不提供自管理虚拟货币任何客户端或者App端的通知,当我们给您的服务器回调时,您要负责通知app和用户。您必须为自管理虚拟货币设置回调服务器。

注意: Tapjoy会以最快的速度奖励用户,但是我们不能保证每次奖励都是实时的,因为有很多因素都会影响到奖励的花费时间。我们推荐您定期在某些地方检查用户余额,比如应用启动,应用重新激活,升级时,视频关闭时,打开应用商店之前等。我们建议您可以通知客户完成广告需要一定的时间。

注意: 即使自管理虚拟货币,每一个平台都必须定义虚拟货币。

1. 回调URL

当用户完成广告并获得奖励时,我们会发一个an HTTP GET request到如下URL。参数的格式如下

<callback_url>?snuid=<user_id>&currency=<currency>&mac_address=<mac_address>

//Example

http://www.sampledoman.com/payments/offers/tapjoy?&amp;snuid=42&amp;currency=50&amp;mac\_address=00-16-41-34-2C-A6

默认的回调参数包括snuid, currency(给用户奖励数目)和用户的wifi mac_address (如果可用).

服务器响应

Tapjoy服务器期望从您的服务器得到200或者403响应。

您的服务器只有在如下情况下给200响应:

  • 用户正确得到了奖励。

您的服务器在如下情况下给403响应:

  • verifier参数和计算值不一致
  • snuid参数在您的系统中不存在
  • 其他不可用重试的错误

如果收到了200和403之外的响应,Tapjoy会重试。(注意如果回复非200响应,请不要奖励客户,因为Tapjoy会重试回调,这样的话有可能会导致重复奖励。) 我们会在4天之内每两分钟尝试一次。如果5秒之内没有收到任何响应,我们会任何回调失败。

注意:响应的主体需要是UTF-8。如果不是UTF-8,即使响应200,我们还是会重试。

防作弊可选参数

您可以通过控制面板 > 变现 > 虚拟货币 > 创建/编辑来得到您虚拟货币的安全密钥。这个密钥不同于应用的SDK密钥。使用在回调中使用虚拟货币密钥:

如果在虚拟货币中设置了secret key,我们将会在回调中添加如下参数:I

  • id – 具体一次奖励的唯一id (注意这不是currency_id,代表的 request_id)
  • verifier – 使用 id, snuid, currency 和密钥得到的MD5值 (参考Verifier说明)

常见作弊场景

  • 如果您看到在回调URL中id被重用或者verifier不正确,可以考虑为作弊。
  • 如果您的user id值只包含数据,我们建议您执行简单的验证,以确保不会混淆用户标识。比如Tapjoy区分 “001234″ and “1234″ 为两个user id,但是您的系统有可能不区分。

Verifier

verifier是利用通过冒号分割的id, snuid, currency 和密钥MD5哈希而成,在Ruby代码如下:

Digest::MD5.hexdigest("#{id}:#{snuid}:#{currency}:#{secret_key}")

您的服务器要重新计算verifier,拒绝任何不匹配的请求。如果verifier不匹配,服务器响应403.

注意每个应用要使用不同的密钥,不要在所有的应用使用相同的密钥,如果使用相同的密钥,有可能会导致在多个应用中同时奖励用户。以上id代表的是request_id而不是currency_id。

2. 升级Callback URL

为了提供更多信息和安全性,我们升级了上面列出的回调。如果您想使用此升级版本,请联系您的客户经理或我们的支持团队,以帮助您启用此版本的回调。

当用户通过完成广告获得虚拟货币时,我们将向您提供的URL发出POST请求。参数的格式为:

{
    "id": "reward.id",
    “rev”: 100,
    “cp”: ”your_custom_string”
    "currency": {
	"id": "currency_id",						
        "reward": "xxx",
        "currency_sale": "",
    },
    "offer": {
        "name": "Some offer",
	 “type”: “”,
	 “icon_url”: “offer_icon_url,
	     },
   “placement”: {
	 “content_type”: “offerwall”,
	 “name”: “placement_name”
},
    "user": {
        "id": "pub_user_id"
    },
    “timestamp”: “123491324”
}

参数 类型 说明
id string 当前请求唯一的奖励ID
rev integer 以美分计算的应得Revenue
cp string 通过SDK中setCustomParameter方法传入的自定义传参数
currency.id string 当前虚拟货币ID
currency.reward integer 应奖励给用户的虚拟货币数量
currency.currency_sale float 虚拟货币促销倍数(如适用)
offer.name string 广告主广告名称
offer.type 当前不支持
offer.icon_url string 广告的Icon URL
placement.name string 当前转化对应的展示位置名称
placement.content_type string 当前展示位置中的广告类型
user.id string 通过SDK setUserID方法设置的User ID
timestamp timestamp 当前转化的时间

JSON主体将使用 SHA512 哈希算法进行哈希处理。验证器将根据POST虚拟货币货币回调请求主体和我们的共享密钥(可在Tapjoy后台上找到您的回调 URL)生成。此验证器将在POST虚拟货币回调请求标头中发送。

HMAC_SHA-256(<Request-Body>,<Secret-Key>)

Tapjoy header with signature示例:

X-Tapjoy-Signature => 7205ccfdfa1fe28cd05a1b56a9508d898cc938aa555a6c18848097fe4ee0975b

3. 用户ID

调用setUserID对于使用自管理虚拟货币非常重要。setUserID中的值即是在回调URL中snuid的值。请一定要调用Tapjoy connect成功之后和请求广告之前调用setUserID(在SDK 11.7之后版本,Tapjoy SDK实现了设置成功/失败的回调,建议在请求广告之前监听这些回调)。

如果设置不正确,您的App 用户将不会得到奖励并且您也无法得到收益。setUserID需要设置用户在游戏中的唯一ID(一般是数字)。

**出于数据安全和GDPR合规性的要求,setUserID参数不应该包括任何身份信息,比如用户名,真实姓名或者邮箱地址。**出于安全和反作弊的目的,user ID要是始终如一的。(比如不能随着用户的等级或者分数改变而改变)。

User ID支持最多190个字符的长度。

下面的示例代码指示了如何使用connect flag 和如何直接调用setUserID API设置user id。我们推荐使用connect flag:

iOS 用法


// Recommended approach using connect flag
NSDictionary *connectFlags = @{TJC_OPTION_USER_ID : @"<USER_ID_HERE>"};
[Tapjoy connect:@"SDK_KEY_GOES_HERE" options:connectFlags];

// Setting the user id directly
[Tapjoy setUserIDWithCompletion:@"<USER_ID_HERE>" completion:^(BOOL success, NSError *error) {

}];

Android 用法

// Recommended approach using connect flag
Hashtable<String, Object> connectFlags = new Hashtable<String, Object>();
connectFlags.put(TapjoyConnectFlag.USER_ID, "<USER_ID_HERE>"); // Important for self-managed currency

Tapjoy.connect(getApplicationContext(), "SDK_KEY_GOES_HERE", connectFlags, new TJConnectListener() {...});

// Setting the user id directly

Tapjoy.setUserID("<USER_ID_HERE>", new TJSetUserIDListener() {
  @Override
  public void onSetUserIDSuccess() {
    
  }

  @Override
  public void onSetUserIDFailure(String error) {

  }
});

Unity 用法

// Recommended approach using connect flag
Dictionary<string,string> connectFlags = new Dictionary<string,string>();
connectFlags.Add("TJC_OPTION_USER_ID", "<USER_ID_HERE>");

#if UNITY_ANDROID
  Tapjoy.Connect("your_android_sdk_key", connectFlags);
#elif UNITY_IOS
  Tapjoy.Connect("your_ios_sdk_key", connectFlags);
#endif

// Callbacks for SetUserID
TJPlacement.OnSetUserIDSuccess += HandleOnSetUserIDSuccess;
TJPlacement.OnSetUserIDFailure += HandleOnSetUserIDFailure;

// Setting the user id directly
Tapjoy.SetUserID("<USER_ID_HERE>")

React Native 用法

// Recommended approach using connect flag
try {
  let flags: object = { TJC_OPTION_USER_ID: '<userId>' };
  await Tapjoy.connect('<sdk_key>', flags);
} catch (error) {
  console.log(error);
}

// Setting the user id directly
try {
  await Tapjoy.setUserId('<userId>');
} catch (error) {
  console.log(error);
}

您可以在iOS, Android, 和 Unity 文档中找到更详细的示例.

故障解决: 如果您调用了setUserID,但是在回调URL中并非您设置的值,您需要在调用积分墙或视频广告之前调用setUserID。如果没有设置userID,默认我们会使用设备id作为snuid,比如,用户在调用设置setUserID之前进入了积分墙,所以请一定在调用connect之后调用。

如果您没有设置user ID,我们会使用device ID作为user ID。一般情况下,我们使用广告ID。但是这取决于SDK版本,设备型号,设备操作系统版本和Google Play Service版本。其他可能的device ID包括Android ID,udid和mac地址。

4. 设置用户余额

每次请求展示位置时,您都可以告诉Tapjoy用户当前余额。您必须在请求展示位置内容之前设置此项。

iOS用法

Objective-C
Swift
TJPlacement *placement = [TJPlacement placementWithName:@"placementName" delegate:nil];
[placement setBalance:100 forCurrencyId:@"1234" withCompletion:^(NSError * _Nullable error) {
    if (error != nil) {
        //Failure
        NSString *message = error.localizedDescription;
    } else {
        //Success
    }
}]; 

Android用法

TJPlacement placement = Tapjoy.getPlacement("placement", this);
placement.setCurrencyBalance("1234", 100, new TJSetCurrencyBalanceListener() {
    @Override
    public void onSetCurrencyBalanceSuccess() {
        
    }

    @Override
    public void onSetCurrencyBalanceFailure(int code, String error) {

    }
}); 

Unity用法

TJPlacement placement = TJPlacement.CreatePlacement("placementName");
placement.SetCurrencyBalance("[CURRENCY_ID]", 100);

// Optional callbacks

void OnEnable() 
{	
    TJPlacement.OnSetCurrencyBalanceSuccess += HandleSetCurrencyBalanceSuccess;	
    TJPlacement.OnSetCurrencyBalanceFailure += HandleSetCurrencyBalanceFailure;	
}

void OnDisable() 
{	
    TJPlacement.OnSetCurrencyBalanceSuccess -= HandleSetCurrencyBalanceSuccess;	
    TJPlacement.OnSetCurrencyBalanceFailure -= HandleSetCurrencyBalanceFailure;
}

public void HandleSetCurrencyBalanceSuccess(TJPlacement placement) 
{

}

public void HandleSetCurrencyBalanceFailure(TJPlacement placement, int code, string error)
{

}

React Native用法

let placement = new TJPlacement('placementName');
try {
  await placement?.setCurrencyBalance('1234', 100);
} catch (e: any) {
  let code = e.code;
  let message = e.message;
}

所需的数量

如果您设置了余额,您还可以在placemnet上设置所需的虚拟货币数量。

iOS用法

Objective-C
Swift
TJPlacement* placement = [TJPlacement placementWithName:@"placementName" delegate:nil];
placement setRequiredAmount:100 forCurrencyId:@"1234" withCompletion:^(NSError * _Nullable error) {
    if (error != nil) {
        //Failure
        NSString *message = error.localizedDescription;
    } else {
        //Success
    }
} 

Android用法

TJPlacement placement = Tapjoy.getPlacement("placement", this);
placement.setCurrencyAmountRequired("1234", 100, new TJSetCurrencyAmountRequiredListener() {
    @Override
    public void onSetCurrencyAmountRequiredSuccess() {
        
    }

    @Override
    public void onSetCurrencyAmountRequiredFailure(int code, String error) {

    }
}); 

Unity用法

TJPlacement placement = TJPlacement.CreatePlacement("placementName");
placement.SetRequiredAmount("[CURRENCY_ID]", 200); 

// Optional callbacks

void OnEnable() 
{	
    TJPlacement.OnSetCurrencyAmountRequiredSuccess += HandleSetRequiredAmountSuccess;	
    TJPlacement.OnSetCurrencyAmountRequiredFailure += HandleSetRequiredAmountFailure;}

void OnDisable() 
{	
    TJPlacement.OnSetCurrencyAmountRequiredSuccess -= HandleSetRequiredAmountSuccess;	
    TJPlacement.OnSetCurrencyAmountRequiredFailure -= HandleSetRequiredAmountFailure;
}

public void HandleSetCurrencyBalanceSuccess(TJPlacement placement)
{

}

public void HandleSetCurrencyBalanceFailure(TJPlacement placement, int code, string error)
{

}

public void HandleSetRequiredAmountSuccess(TJPlacement placement)
{

}
public void HandleSetRequiredAmountFailure(TJPlacement placement, int code, string error)
{

} 

React Native用法

let placement = new TJPlacement('placementName');
try {
await offerwallPlacement?.setRequiredAmount(100, '100');
} catch (e: any) {
  let code = e.code;
  let message = e.message;
} 

5. 奖励回调IP Whitelisting

如果您的奖励回调服务器需要添加权限(白名单)才能访问,这是 Tapjoy 的 IP 列表。(最后更新时间:2024 年 5 月 12 日)

18.215.207.89
18.235.142.165
23.20.255.113
23.23.134.165
3.210.188.32
3.215.42.140
3.217.209.177
3.218.95.35
3.219.236.53
3.231.137.161

6. Tapjoy管理虚拟货币和自管理虚拟货币切换

如果您的应用还没有正式启用,您可以在Tapjoy控制面板中编辑虚拟货币页面从Tapjoy管理虚拟货币切换到自管理虚拟货币。在切换时一定要填写正确的回调URL,要不然改变将不会起作用。

如果您线上的app正在使用Tapjoy管理虚拟货币,切换的流程比较复杂,您需要考虑如下的事情:

  • 您需要创建包含一个新SDK密钥的新App。这样可以保证没有升级到最新版本的老版本的用户不受到影响。如果您在自管理虚拟货币版本的App中使用相同的SDK密钥,在Tapjoy管理的版本中的用户将不会得到奖励。
  • 您需要暂停定向到老的App ID的广告,然后创建新的广告指向新的App ID。
  • 切换到自管理虚拟货币还需要您代码的改动。您将不能使用getCurrencyBalance, awardCurrency, 或者spendCurrency,这些接口只能在托管情况下使用。
  • 在切换之前请咨询您的AM。
  • 我们无法从自管理虚拟货币切换回Tapjoy管理,所以请慎重选择。

迁移用户余额,我们推荐如下步骤:

  1. 在首次启动时,使用Tapjoy管理虚拟货币老的SDK密钥,调用getCurrencyBalance来获取余额。
  2. 使用getCurrencyBalance获得的值更新您的余额。
  3. 在接下来的启动中使用新的SDK密钥。

如果您正在考虑切换到自管理虚拟货币模式,但是您不确定怎样搭建您自己的服务器,我们推荐您参考下面链接中的方案 Parse 或者 UrbanAirship