# Tapjoy 托管货币

> 使用 Tapjoy Offerwall 托管货币在 Tapjoy 服务器上存储和管理用户货币余额。

使用 Tapjoy 托管货币在 Tapjoy 服务器上存储和管理用户的虚拟货币金额。这项免费服务对所有集成 Tapjoy 发行商 SDK 的开发者均开放，确保了无需在您的应用后端存储货币。

## 获取货币余额##get-currency-balance

要检查用户当前的虚拟货币余额，请采用各平台对应的方法。最好是频繁调用 `getCurrencyBalance` 以确保余额信息准确无误。常见的余额检查时机包括以下情况：

* ​​app程序启动
* 应用恢复时
* Tapjoy 视图关闭时
* 广告位内容消失时

为了获得最佳效果，建议在广告内容结束后约 3.5 秒调用 `getCurrencyBalance`。这样可以保证有足够时间处理奖励的更新。立即检查余额可能无法显示新获得的奖励。

### 获取货币余额##retrieve-currency-balances

Tapjoy 致力于及时发放奖励。但是，由于可能有网络延迟，无法保证奖励立即到账。请提醒用户，完成任务的奖励可能需要一些时间才会显示。为了确保数据准确，请在固定的时间间隔和发生关键应用事件检查余额，如以下事件：

* ​应用启动时
* 应用恢复时
* 关卡之间
* 商店加载前

请参阅以下各平台对应的方法来获取货币余额：

1. **iOS**

   要在 iOS 设备上获取当前的虚拟货币余额，请使用以下方法：

   ```objective-c title="Objective-C"
   // This method requests the tapjoy server for current virtual currency of the user.
   //Get currency
   [Tapjoy getCurrencyBalanceWithCompletion：^(NSDictionary *parameters, NSError *error) {
     if (error) {
       //Show error message
       NSLog(@"getCurrencyBalance error: %@", [error localizedDescription]);
     } else {
       //Update currency value of your app
       NSLog(@"getCurrencyBalance returned %@: %d", parameters[@"currencyName"], [parameters[@"amount"] intValue]);
     }
   }];
   ```

   completion 代码块会返回余额，其中 `currencyName` 表示货币名称，`amount` 表示用户的总金额。如需了解实现细节，请参考 SDK 包中的示例应用程序。

2. **Android**

   要在 Android 设备上获取当前的虚拟货币余额，请使用以下方法：

   ```java title="Java"
     Tapjoy.getCurrencyBalance(new TJGetCurrencyBalanceListener(){
       @Override
       public void onGetCurrencyBalanceResponse(String currencyName, int balance) {
         Log.i(TAG, "getCurrencyBalance returned " + currencyName + ":" + balance);
       }
       @Override
       public void onGetCurrencyBalanceResponseFailure(String error) {
         Log.i("Tapjoy", "getCurrencyBalance error: " + error);
       }
     });
   ```

   您将在 `onGetCurrencyBalanceResponse` 回调中收到余额，在 `onGetCurrencyBalanceResponseFailure` 中收到报错。为确保数据准确无误，请在应用启动和恢复时调用 `getCurrencyBalance`。花费和奖励回调也会返回总余额，并可用于更新您的应用。

3. **Unity**

   ```csharp title="C#"
   // Get currency
   Tapjoy.GetCurrencyBalance();

   // on enable, add delegates
   void OnEnable() {
     Tapjoy.OnGetCurrencyBalanceResponse += HandleGetCurrencyBalanceResponse;
     Tapjoy.OnGetCurrencyBalanceResponseFailure += HandleGetCurrencyBalanceResponseFailure;
   }

   // on disable, remove delegates
   void OnDisable() {
     Tapjoy.OnGetCurrencyBalanceResponse -= HandleGetCurrencyBalanceResponse;
     Tapjoy.OnGetCurrencyBalanceResponseFailure -= HandleGetCurrencyBalanceResponseFailure;
   }
   public void HandleGetCurrencyBalanceResponse(string currencyName, int balance) {
     Debug.Log("C#: HandleGetCurrencyBalanceResponse: currencyName: " + currencyName + ", balance: " + balance);
   }
     
   public void HandleGetCurrencyBalanceResponseFailure(string error) {
     Debug.Log("C#: HandleGetCurrencyBalanceResponseFailure: " + error);
   }
   ```

   您将在指定的 `OnGetCurrencyBalanceResponse` 处理程序中收到货币余额通知，该处理程序将传递 `currencyName` 和 `balance` 参数。您将在 `OnGetCurrencyBalanceResponseFailure` 处理程序中收到错误通知。

4. **React Native**

   ```javascript title="JavaScript"
   try {
     let result = await Tapjoy.getCurrencyBalance();
       let currencyName = result['currencyName'];
       let amount = result['amount'];
   } catch (error: any) {
       //Handle error
   }
   ```

   在 React Native 中，我们对没有参数的 `getCurrencyBalance()` 使用了一个 Promise。这个 Promise 解析后会返回一个包含 `currencyName` 和 `amount` 的字典，若失败则会返回错误。

5. **Adobe Air**

   ```java title="Java"
     // Get currency
     TapjoyAIR.getCurrencyBalance();

     // Setup handlers
     TapjoyAIR.addEventListener(TJCurrencyEvent.GET_CURRENCY_BALANCE_SUCCESS, tapjoyCurrencyEventHandler);
     TapjoyAIR.addEventListener(TJCurrencyEvent.GET_CURRENCY_BALANCE_FAILURE, tapjoyCurrencyEventHandler);

     private function tapjoyCurrencyEvents(event:TJCurrencyEvent):void {
       trace("Tapjoy sample event listener for " + event.type + ", " + event.balance + ", " + event.currencyName);
     }
   ```

   您将在指定的 `TJCurrencyEvent.GET_CURRENCY_BALANCE_SUCCESS` 处理程序中收到货币余额通知，该处理程序将传递 `TJCurrencyEvent` 对象。此对象包含 `currencyName` 和 `balance` 属性。您将在 `TJCurrencyEvent.GET_CURRENCY_BALANCE_FAILURE` 处理程序中收到错误通知。

## 检查用户是否已获得货币##checking-if-the-user-has-earned-currency

当用户自上次检查余额以来获得货币时，通知用户。请参阅以下各节中每个平台的说明以完成通知设置。

1. **iOS**

   为 iOS 设备添加通知观察器以检测获得的货币：

   ```objective-c title="Objective-C"
   // Set the notification observer for earned-currency-notification.It's recommended that this be placed within the applicationDidBecomeActive method.
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showEarnedCurrencyAlert:) name:TJC_CURRENCY_EARNED_NOTIFICATION object:nil];

   // In the following method, you can set a custom message or use the default UIAlert to inform the user that they just earned some currency.
   - (void)showEarnedCurrencyAlert:(NSNotification*)notifyObj
   {
     NSNumber *currencyEarned = notifyObj.object;
     int earnedNum = [currencyEarned intValue];

     NSLog(@"Currency earned: %d", earnedNum);

     // Pops up a UIAlert notifying the user that they have successfully earned some currency.
     // This is the default alert, so you may place a custom alert here if you choose to do so.
     [Tapjoy showDefaultEarnedCurrencyAlert];

     // This is a good place to remove this notification since it is undesirable to have a pop-up alert more than once per app run.
     [[NSNotificationCenter defaultCenter] removeObserver:self name:TJC_CURRENCY_EARNED_NOTIFICATION object:nil];
   }
   ```

2. **Android**

   为了在用户获得虚拟货币（例如通过完成任务）时收到通知，请使用以下方法来设置货币收入监听器：

   ```java title="Java"
     // Get notifications whenever Tapjoy currency is earned.
     Tapjoy.setEarnedCurrencyListener(new TJEarnedCurrencyListener() {
       @Override
       public void onEarnedCurrency(String currencyName, int amount) {
         Log.i("Tapjoy", "You've just earned " + amount + " " + currencyName);
       }
     });
   ```

   您将在 `TJEarnedCurrencyListener` 内的 `onEarnedCurrency(String currencyName, int amount)` 回调中收到货币收入通知。例如，如果用户的余额为 100，并通过任务获得 25，则下次调用 `getCurrencyBalance()` 时将以金额 25 触发 `onEarnedCurrency`。

3. **Unity**

   ```csharp title="C#"
   // on enable, add delegates
   void OnEnable() {
     Tapjoy.OnEarnedCurrency += HandleEarnedCurrency;
   }

   // on disable, remove delegates
   void OnDisable() {
     Tapjoy.OnEarnedCurrency -= HandleEarnedCurrency;
   }

   public void HandleEarnedCurrency(string currencyName, int amount) {
     Debug.Log("C#: HandleEarnedCurrency: currencyName: " + currencyName + ", amount: " + amount);
   }
   ```

   您将在指定的 `OnEarnedCurrency` 处理程序中收到货币收入通知，该处理程序将传递 `currencyName` 和收入 `amount` 参数。

4. **Adobe Air**

   ```java title="Java"
     TapjoyAIR.addEventListener(TJEarnedCurrencyEvent.EARNED_CURRENCY, tapjoyEarnedCurrencyEventHandler);

     private function tapjoyEarnedCurrencyEventHandler(event:TJEarnedCurrencyEvent):void
     {
       trace("You can notify user's here that they've just earned " + event.amount + " " + event.currencyName);
     }
   ```

   您将在指定的 `earned in the TJEarnedCurrencyEvent.EARNED_CURRENCY` 处理程序中收到货币收入通知，该处理程序将传递 `TJEarnedCurrencyEvent object`。此对象包含 `currencyName` 和 `amount` 属性。

## 花费 Tapjoy 托管货币##spend-tapjoy-managed-currency

要花费用户的一些虚拟货币，请调用以下各节所述特定于平台的方法。

1. **iOS**

   ```objective-c title="Objective-C"
   // This method call will deduct 10 virtual currencies from the user's total.
   [Tapjoy spendCurrency:10 completion:^(NSDictionary *parameters, NSError *error) {
     if (error) {
       NSLog(@"spendCurrency error: %@", [error localizedDescription]);
     } else {
       NSLog(@"spendCurrency returned %@: %d", parameters[@"currencyName"], [parameters[@"amount"] intValue]);
     }
   }];
   ```

   您将在 completion 代码块中获知货币余额，其中的参数 `currencyName` 提供货币名称，`amount` 提供用户的余额。

2. **Android**

   ```java title="Java"
     Tapjoy.spendCurrency(10, new TJSpendCurrencyListener() {
       @Override
       public void onSpendCurrencyResponse(String currencyName, int balance) {
         Log.i("Tapjoy", currencyName + ":" + balance);
       }

       @Override
       public void onSpendCurrencyResponseFailure(String error) {
         Log.i("Tapjoy", "spendCurrency error: " + error);
       }
     });
   ```

   您将在指定的 `TJSpendCurrencyListener` 中的 `onSpendCurrencyResponse(String currencyName, int balance)` 回调方法中收到货币余额通知。您将在 `onSpendCurrencyResponseFailure(String error)` 方法中收到错误通知。

3. **Unity**

   ```csharp title="C#"
   // Spend currency
   Tapjoy.SpendCurrency(10);

   // on enable, add delegates
   void OnEnable() {
     Tapjoy.OnSpendCurrencyResponse += HandleSpendCurrencyResponse;
     Tapjoy.OnSpendCurrencyResponseFailure += HandleSpendCurrencyResponseFailure;
   }

   // on disable, remove delegates
   void OnDisable() {
     Tapjoy.OnSpendCurrencyResponse -= HandleSpendCurrencyResponse;
     Tapjoy.OnSpendCurrencyResponseFailure -= HandleSpendCurrencyResponseFailure;
   }

   public void HandleSpendCurrencyResponse(string currencyName, int balance) {
     Debug.Log("C#: HandleSpendCurrencyResponse: currencyName: " + currencyName + ", balance: " + balance);
   }
     
   public void HandleSpendCurrencyResponseFailure(string error) {
     Debug.Log("C#: HandleSpendCurrencyResponseFailure: " + error);
   }
   ```

   您将在指定的 `OnSpendCurrencyResponse` 处理程序中收到货币余额通知，该处理程序将传递 `currencyName` 和 `balance` 参数。您将在 `OnSpendCurrencyResponseFailure` 处理程序中收到错误通知。

4. **React Native**

   ```javascript title="JavaScript"
   try {
     let result = await Tapjoy.spendCurrency(10);
       let currencyName = result['currencyName'];
       let amount = result['amount'];
   } catch (error: any) {
       //Handle error
   }
   ```

   我们在 React Native 中使用一个 Promise 来处理 `spendCurrency(),`，该方法以 `amount` 为参数。这个 Promise 会返回一个字典或一个错误（错误应被捕获）。字典的键 `currencyName` 包含一个字符串以及货币金额。

5. **Adobe Air**

   ```java title="Java"
     // Spend currency
     TapjoyAIR.spendCurrency(10);

     // Setup handlers
     TapjoyAIR.addEventListener(TJCurrencyEvent.SPEND_CURRENCY_SUCCESS, tapjoyCurrencyEventHandler);
     TapjoyAIR.addEventListener(TJCurrencyEvent.SPEND_CURRENCY_FAILURE, tapjoyCurrencyEventHandler);

     private function tapjoyCurrencyEventHandler(event:TJCurrencyEvent):void {
       trace("Tapjoy sample event listener for " + event.type + ", " + event.balance + ", " + event.currencyName);
     }
   ```

   您将在指定的 `TJCurrencyEvent.SPEND_CURRENCY_SUCCESS` 处理程序中收到货币余额通知，该处理程序将传递 `TJCurrencyEvent` 对象。此对象包含 `currencyName` 和 `balance` 属性。您将在 `TJCurrencyEvent.SPEND_CURRENCY_FAILURE` 处理程序中收到错误通知。

## 奖励 Tapjoy 托管货币##award-tapjoy-managed-currency

> **Warning:**
>
> 要在新应用中使用此功能，请联系您的客户经理获取批准。

要向用户发放奖励的虚拟货币，请使用以下各节所述特定于平台的方法。

1. **iOS**

   ```objective-c title="Objective-C"
   // This method call will award 10 virtual currencies to the user's total.
   [Tapjoy awardCurrency:10 completion:^(NSDictionary *parameters, NSError *error) {
     if (error) {
       NSLog(@"awardCurrency error: %@", [error localizedDescription]);
     } else {
       NSLog(@"awardCurrency returned %@: %d", parameters[@"currencyName"], [parameters[@"amount"] intValue]);
     }
   }];
   ```

   您将在 `completion` 代码块中获知货币余额，其中的参数 `currencyName` 提供货币名称，`amount` 提供用户的余额。

2. **Android**

   ```java title="Java"
     Tapjoy.awardCurrency(10, new TJAwardCurrencyListener() {
       @Override
       public void onAwardCurrencyResponseFailure(String error) {
         Log.i("Tapjoy", "awardCurrency error: " + error);					}

       @Override
       public void onAwardCurrencyResponse(String currencyName, int balance) {
         Log.i("Tapjoy", currencyName + ": " + balance);
       }
     });
   ```

   您将在指定的 `TJAwardCurrencyListener` 中的 `onAwardCurrencyResponse(String currencyName, int balance)` 回调方法中收到货币余额通知。

3. **Unity**

   ```csharp title="C#"
   // Award currency
   Tapjoy.AwardCurrency(10);

   // on enable, add delegates
   void OnEnable() {
     Tapjoy.OnAwardCurrencyResponse += HandleAwardCurrencyResponse;
     Tapjoy.OnAwardCurrencyResponseFailure += HandleAwardCurrencyResponseFailure;
   }

   // on disable, remove delegates
   void OnDisable() {
     Tapjoy.OnAwardCurrencyResponse -= HandleAwardCurrencyResponse;
     Tapjoy.OnAwardCurrencyResponseFailure -= HandleAwardCurrencyResponseFailure;
   }

   public void HandleAwardCurrencyResponse(string currencyName, int balance) {
     Debug.Log("C#: HandleAwardCurrencySucceeded: currencyName: " + currencyName + ", balance: " + balance);
   }
     
   public void HandleAwardCurrencyResponseFailure(string error) {
     Debug.Log("C#: HandleAwardCurrencyResponseFailure: " + error);
   }
   ```

   您将在指定的 `OnAwardCurrencyResponse` 处理程序中收到货币余额通知，该处理程序将传递 `currencyName` 和 `balance` 参数。您将在 `OnAwardCurrencyResponseFailure` 处理程序中收到错误通知。

4. **React Native**

   ```javascript title="JavaScript"
   try {
     let result = await Tapjoy.awardCurrency(10);
       let currencyName = result['currencyName'];
       let amount = result['amount'];
   } catch (error: any) {
       //Handle error
   }
   ```

   我们在 React Native 中使用一个 Promise 来处理 `awardCurrency()`，该方法以 `amount` 为参数。这个 Promise 会返回一个字典或一个错误（错误应被捕获）。字典的键 `currencyName` 包含一个字符串以及货币金额。

5. **Adobe Air**

   ```java title="Java"
   // Award currency
   TapjoyAIR.awardCurrency(10);

   // Setup handlers
   TapjoyAIR.addEventListener(TJCurrencyEvent.AWARD_CURRENCY_SUCCESS, tapjoyCurrencyEventHandler);
   TapjoyAIR.addEventListener(TJCurrencyEvent.AWARD_CURRENCY_FAILED, tapjoyCurrencyEventHandler);

   private function tapjoyCurrencyEventHandler(event:TJCurrencyEvent):void {
     trace("Tapjoy sample event listener for " + event.type + ", " + event.balance + ", " + event.currencyName);
   }
   ```

   您将在指定的 `TJCurrencyEvent.AWARD_CURRENCY_SUCCESS` 处理程序中收到货币余额通知，该处理程序将传递 `TJCurrencyEvent` 对象。此对象包含 `currencyName` 和 `balance` 属性。您将在 `TJCurrencyEvent.AWARD_CURRENCY_FAILURE` 处理程序中收到错误通知。

## 测试 Tapjoy 托管货币##test-tapjoy-managed-currency

要测试 Offerwall 中的任务，请向您的应用程序添加测试设备。这样可确保测试任务会出现在 Offerwall 顶部以便进行验证。

## 最佳实践和其他信息##best-practices-and-additional-information

* 务必验证 `awardCurrency` 和 `spendCurrency` 调用，仅在这些调用成功时才解锁内容。如果这些调用失败，可能会影响设备上的余额。
* 不要仅依赖本地存储的货币值；还应使用 Tapjoy 服务器以确保数据准确。
* 仅在扣除货币以解锁内容时才调用 spendCurrency。
* 托管货币仅支持每个 App ID 绑定一种货币；如需多种货币，请使用自管货币。
* Tapjoy 按设备和应用来存储货币余额，以防止不同设备间共享余额。
* 虽然 Tapjoy 致力于快速发放奖励，但有多种因素可能导致货币奖励延迟。应在关键应用事件后定期检查余额，并提醒用户可能出现延迟。
