自社管理仮想通貨

自社管理 仮想通貨は、ユーザーの仮想通貨の増減の処理をパブリッシャーの用意する自社サーバーで行うものです。この方法の場合、ユーザーの仮想通貨管理をより柔軟に行えますが、全ユーザーの仮想通貨管理と運用のバックエンド作業をアプリ開発者自身が行う必要があります。getCurrencyBalance、 awardCurrency、および spendCurrency は Tapjoy管理仮想通貨でしか使用できません。Tapjoyは自社管理仮想通貨に関してはクライアントサイド(アプリ側)への通知の仕組みは提供していません。Tapjoyから自社のサーバにコールバックが行われた際のアプリおよびユーザーへ通知を行う仕組みはパブリッシャ自身が面倒を見る必要があります。また、自社管理仮想通貨を使用するためにはコールバック用のサーバを用意する必要があります。

注: Tapjoyはユーザーへのリワードを可能な限り素早く付与しますが、ユーザーがすぐにリワードされる事は保証できません。ユーザーへリワードを行う時間に関わる要素が多く割るため、ユーザーへのリワードが行われる時間を決定する事は困難です。ベスト・プラクティスとしては、動画広告が閉じた後に仮想通貨残高をチェックするのに加え、定期的、および起動・レジューム・レベル完了・アプリ内ストアの表示前等のアプリイベントで残高を確認する事をお勧めします。また、ユーザーにオファーの完了までに時間がかかる場合がある旨を知らせておく事もお勧めします。

注: 自社管理通貨の場合でも、仮想通貨はプラットフォーム固有となります。

1. コールバックURL

ユーザーが広告のアクションを完了して仮想通貨を獲得すると、TapjoyサーバーがHTTP(S) GETリクエストを送信します。 パラメーターのフォーマットは次のようになります:

<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 (setUserIDで指定したユーザーID)、currency(ユーザーのアカウントに追加する仮想通貨量)、および取得可能な場合ユーザーのWiFiのmac アドレスが含まれます。

サーバーレスポンス

Tapjoyサーバーは、アプリ開発者のサーバーから200または403レスポンスを受け取ります。

アプリ開発者のサーバーが200をレスポンスする場合:

  • ユーザーが通貨を正常に獲得した

アプリ開発者のサーバーが403をレスポンスする場合:

  • 算出された値とverifierの値が一致しない
  • snuid パラメータの値がシステム内で不明だった
  • その他の、再送されるべきでないエラーが発生した

Tapjoyサーバーが200もしくは403以外のレスポンスコードを受け取った場合、Tapjoyは再送を試みます。(注: 200以外のレスポンスを返す場合には、ユーザーにリワードを付与しないようにして下さい。Tapjoyはコールバックを再送する場合があり、リワードが複数回行われてしまう場合があるからです)。再送は2分毎に4日間行います。また、サーバーからのレスポンスが5秒を超える場合にも失敗として取り扱います。

注: コールバックのレスポンスのbodyの内容はUTF-8である必要があります。UTF-8以外のエンコーディングの場合、レスポンスコードが200であっても再送する場合があります。

不正検知および対策用のオプションパラメータ

ダッシュボードの[マネタイズ]-[仮想通貨]-[Secret Key]-[作成/編集]から仮想通貨のSecret Keyを取得できます。 このキーは アプリのSDK Keyとは違うものです。この仮想通貨 Secret Key を使用してコールバックを署名します。

仮想通貨にSecret Keyが指定されている場合、Tapjoyからのコールバックに以下のパラメータを追加します:

  • id: 特定の仮想通貨付与イベントに割り振られたユニークID (仮想通貨のIDではありません)
  • verifier: id、 snuid、 currency、および Secret Key の MD5ハッシュ値(下記参照)

注意するべき不正のシナリオ

  • コールバックURL注のidパラメータ値が既に利用されていた値だったり、verifier 値が正しくない場合はTapjoyが送ったものではないため、不正と考えるべきです。
  • ユーザーIDを数値で指定している場合、snuidに指定された値が変更されていないかチェックするようにして下さい。例えば、Tapjoyでは "001234" と "1234" のユーザーIDを異なる物として扱いますが、サーバの検証ロジックではそうなっていない場合には不正が検知できていないかもしれません。

Verifier

verifierはID、snuid、仮想通貨および秘密鍵をコロンで区切った文字列のMD5ハッシュ値です。 Rubyでは、次のコードで計算できます:

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

アプリ開発者のサーバーは、ベリファイアを再計算して一致しないリクエストを却下します。verifierが一致しない場合にはサーバーは403レスポンスを返すようにして下さい。

各アプリケーションは異なるSecret Keyを指定するようにして下さい。アプリケーション間で共通のSecret Keyを使用した場合、あるアプリケーションのユーザーに対するリワードが別のアプリケーションでのリワードに再利用される可能性があります。また、idパラメータが仮想通貨のIDではなくリワードに対するユニーク値だと言う事も留意して下さい。

2. 改良されたコールバック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 獲得した収益(USDセント単位)
cp string setCustomParameterメソッドでSDKから渡されたカスタムパラメータ
currency.id string この通貨のID
currency.reward integer ユーザーに付与される通貨の量
currency.currency_sale float カレンシーセールの乗数(該当する場合)
offer.name string 広告主のオファー名
offer.type 現時点ではサポートされていません
offer.icon_url string オファーのアイコンURL
placement.name string このコンバージョンに使用したプレイスメント名
placement.content_type string 使用されたプレイスメントの種類
user.id string setUserIDメソッドを通じてSDKから渡されたユーザーID
timestamp timestamp このトランザクションのタイムスタンプ

JSON本文はSHA256ハッシュアルゴリズムを使用してハッシュ化されます。verifierはPOST通貨コールバックリクエストの本文と、共有シークレットキー(TapjoyダッシュボードでコールバックURLと共に表示されています)から生成されます。 このverifierはPOST通貨コールバックリクエストのヘッダーに送信されます。

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

verifierのシグネチャを含むTapjoyヘッダの例:

X-Tapjoy-Signature => 7205ccfdfa1fe28cd05a1b56a9508d898cc938aa555a6c18848097fe4ee0975b

2. User ID

自社管理仮想通貨を使用する場合、User ID を指定する事は非常に重要です。この値はコールバックURLで snuid パラメータの値として設定されます。User ID の指定にはコンテンツをリクエストする前の、SDK初期化時のconnect flagを使用する事をおすすめします。

正しく設定されなかった場合、ユーザーはリワードを得られないでしょうし、レベニューが発生しない場合もあります。User IDの値はユーザーを特定できる一意のID (通常は数値) である必要があります。

セキュリティ上、およびGDPR準拠の観点から、setUerIDのパラメータの値にユーザー名、氏名、メールアドレス等の認識・識別可能な情報を使うべきではありません。 セキュリティおよび不正検知の観点から、ユーザーIDはユーザーのアプリプラットフォーム上での利用期間全般において同じ値が使われるようにするべきです。(例えば、レベルやスコア等の変化する値を付加する事は行わないで下さい)

User ID は最大190文字までです。

以下のコードサンプルは connect flagを使う方法、および必要がある場合(connectの後に)setUserID APIを直接呼び出す例です。APIを直接呼び出す場合にはUser IDが設定されたかを確認するためにコールバックを利用してください。可能な限り、connect flag を使う方法を強くおすすめします。

iOS 手順


// connect flag でUser IDを指定する(推奨)
NSDictionary *connectFlags = @{TJC_OPTION_USER_ID : @"<USER_ID_HERE>"};
[Tapjoy connect:@"SDK_KEY_GOES_HERE" options:connectFlags];

// User IDを直接指定する
[Tapjoy setUserIDWithCompletion:@"<USER_ID_HERE>" completion:^(BOOL success, NSError *error) {

}];

Android 手順

// connect flag でUser IDを指定する(推奨)
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() {...});

// User IDを直接指定する

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

  @Override
  public void onSetUserIDFailure(String error) {

  }
});

Unity 手順

// connect flag でUser IDを指定する(推奨)
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;

// SUser IDを直接指定する
Tapjoy.SetUserID("<USER_ID_HERE>")

React Native 手順

// connect flag を使用する方法(推奨)
try {
  let flags: object = { TJC_OPTION_USER_ID: '<userId>' };
  await Tapjoy.connect('<sdk_key>', flags);
} catch (error) {
  console.log(error);
}

// User IDを直接指定する
try {
  await Tapjoy.setUserId('<userId>');
} catch (error) {
  console.log(error);
}

詳細な例はクイックスタートのページ(iOSAndroidUnity) および React Native もご参照ください。

トラブルシュート: コールバックURLのsnuidの値がsetUserIDでセットしたユーザIDと異なる場合は、setUserIDをTapjoy広告をリクエストする前に呼び出すようにしてください。端末にひもづいたUser IDが見つからない場合、TapjoyはTapjoy内部で使用している端末のユニークIDをコールバックのsnuidパラメータに指定して送ります。こうした事態を避けるためにアプリ起動毎にTapjoyコネクトコールが呼び出され、成功の直後にsetUserIDが確実に呼び出されるような実装をお勧めします。

User IDを設定していなかった場合、Tapjoy システムは使用可能な代替デバイスIDを使用します。多くの場合これは広告IDとなりますが、SDKのバージョンやデバイス種別・バージョン、OSバージョン、Google Play Servicesのバージョン等により実際に使用されるIDは異なります。Tapjoy内部で使用されるudidやmac_addressから構成される場合もあります。

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;
}

必要量

残高を設定する場合、必要な仮想通貨の量もプレイスメントに設定できます。

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 ホワイトリスティング

リワードコールバックの送信IPアドレスをサーバで制限する必要がある場合は、英語版の "Reward Callback IP Whitelisting"に記載されているIPアドレスをご参照下さい。

6. 仮想通貨のTapjoy管理から自社管理への切り替え

まだアプリをローンチしていない場合、TapjoyダッシュボードからTapjoy管理の仮想通貨を自社管理の仮想通貨へ仮想通貨の編集画面で行えます。callback URLフィールドに正しい形式の自社サーバのURL(もしくは "NO_CALLBACK")を指定して下さい。異常な形式の場合、設定が保存されません。

流通している既存アプリでTapjoy管理の仮想通貨を使用している場合、切り替えはより複雑になります。 以下の状況を考える必要があります:

  • Tapjoyダッシュボード上で新たにアプリを登録し、新しいSDK Keyを取得します。これにより、古いバージョンのアプリを使用して新しいバージョンにアップグレードしていないユーザーへの悪影響を避けます。
  • 既存のAPP IDでの広告出稿をすべて停止し、新規APP IDでの広告に切り替えます。
  • 自社管理仮想通貨を使ったアプリのコードを修正します。Tapjoy管理の仮想通貨でのみ利用できた、getCurrencyBalance、awardCurrency、および spendCurrency を自社のシステムに置き換える必要があります。
  • Tapjoy管理仮想通貨から自社管理仮想通貨へ切り替える場合は事前にTapjoyアカウントマネージャと相談する事をおすすめします。
  • 自社管理仮想通貨からTapjoy管理仮想通貨に切り替える事はできません。変更を行う際は慎重に行って下さい。

ユーザーの仮想通貨残高を移行するには、以下の手順をおすすめします:

  1. 既存App IDで起動しgetCurrencyBalanceですべての仮想通貨を取得します。
  2. 取得した仮想通貨を自社管理サーバに更新します。
  3. 新規App IDでアプリを再起動します。

仮想通貨の自社管理を検討している方は ParseUrbanAirship を利用したソリューションも検討ください。