# 消息

> 在应用中实现量身定制的消息，引导用户访问 Offerwall 并完成指定的事件。

您可以通过 Message to Earn (M2E) 或深度链接到 Offerwall 的应用内消息来引导用户访问 Offerwall。

下图展示了一个应用内消息示例，告知用户限时完成任务即可获得双倍宝石奖励。用户可以点击 Earn More Now（立即赚取更多）访问 Offerwall 并完成这些任务。

![优惠墙的应用内消息示例。](/api/media?file=/grow/media/images/m2e-landscape.png)

## 消息最佳实践##messaging-best-practices

设置消息时，请牢记以下最佳实践，有助于引导更多用户访问 Offerwall。

### 在消息中推广货币促销##promote-currency-sales-in-messages

使用 M2E 或应用的消息系统提供个性化的货币促销，提升用户对促销活动的认知度。如需了解更多信息，请参阅
“货币促销”文章的[使用消息功能优化货币促销](/grow/offerwall/monetization/dashboard/currency-sales.md#optimizing-currency-sales-with-messaging)一节。

### 利用有效的消息广告位提升 Offerwall 可见性##improve-offerwall-visibility-with-effective-messaging-placements

为了引导更多用户访问 Offerwall，您可以在以下类型的广告位中配置消息：

* 应用加载完成后在主屏幕上
* 货币不足触发的对话框中
* 应用收件箱消息内
* 用户到达某一关卡后
* 用户完成游戏事件后

### 应用用户定向投放##apply-user-targeting

使用个性化消息针对特定用户组进行定向投放。请参阅下列示例，帮助识别关键用户细分段，并为每个细分段创建定制消息：

* 欢迎新用户在限定时间内完成首个任务以获得双倍奖励。
* 鼓励在特定天数内仍未完成任务的用户采取行动。
* 提醒在特定天数内未登录 Offerwall 的用户重新回归。
* 重新吸引参与了 Offerwall 事件但未能完成的用户。

### 评估应用内消息的有效性##evaluate-in-app-message-effectiveness

为优化应用内消息，可进行 A/B 测试，根据使用情况数据确认最有效的消息版本。如需有关 A/B 测试的更多信息，请参阅 [A/B 测试工具](/grow/offerwall/monetization/dashboard/ab-testing-for-marketing-messages.md)。

## 配置 Message to Earn##configure-message-to-earn

Message to Earn (M2E) 作为 Tapjoy 的一项功能，可在游戏过程的特定时间和位置显示可自定义的应用内消息。此功能可向用户展示特定的促销信息，引导用户访问 Offerwall 参与互动。

> **Note:**
>
> 您可以在创建
>
> [内容卡片](/grow/offerwall/monetization/dashboard/content-cards.md)
>
> 时配置 M2E。如需详细了解如何创建内容卡片，请参阅
>
> [创建内容卡片](/grow/offerwall/monetization/dashboard/content-cards.md#create-a-content-card)
>
> 。

要配置 M2E，请按照以下步骤操作：

1. 在 \*\*Content card（内容卡片）\*\*设置中，转到 **Message to Earn** 部分。
2. 启用 **Message to Earn** 切换开关。
3. 上传用于纵向和横向视图的消息图像。
4. 在 \*\*Transition（过渡）\*\*下，选择动画效果以定义应用内消息如何在屏幕上出现。可选择以下选项之一：
   * **Swipe（滑动）**：应用内消息以滑动方式出现。
   * **Tap（点击）**：应用内消息在用户点击屏幕后出现。
   * **Auto (after 5 seconds)（自动（5 秒后））**：应用内消息在用户无操作的情况下 5 秒后自动出现。
5. 输入**消息**。

## 将应用内消息深度链接到 Offerwall##deeplink-in-app-messages-to-offerwall

如果您更倾向于使用应用自身的消息系统，可将应用内消息深度链接到 Offerwall。要根据您的实现方式将应用内消息深度链接到 Offerwall，请参阅以下说明以及各平台的具体操作过程：

1. 在 Tapjoy 后台中，为您的自定义应用内消息创建一个内容相关广告位。
   > **Tip:**
   >
   > 为了便于广告位的管理和归类，请使用清晰的命名方式，指明其用途。例如，广告位名称 `Level_Complete_Popup` 表示该广告位用于展示用户完成游戏关卡后出现的消息。

2. 创建内容卡片以引导用户从您的自定义应用内消息跳转。
   > **Note:**
   >
   > 保持 **Message to Earn** 处于禁用状态，以确保用户只会遇到自定义应用内消息。

3. 要在代码中实现广告位，请将以下代码复制到您的项目中，然后将广告位名称字符串占位符替换为您在步骤 1 中创建的确切广告位名称。

   > **Important:**
   >
   > 请确保文本大小写、空格和特殊字符与后台中的广告位名称完全一致。

1) **Android**

   ```java title="Java"
   TJPlacementListener placementListener = this;
   TJPlacement p = Tapjoy.getPlacement("[PLACEMENT_NAME]", placementListener);

   // Listeners

   public void onRequestSuccess(TJPlacement placement);
   public void onRequestFailure(TJPlacement placement, TJError error);
   public void onContentReady(TJPlacement placement);
   public void onContentShow(TJPlacement placement);
   public void onContentDismiss(TJPlacement placement);
   ```

2) **iOS (Objective-C)**

   ```objc title="Objective-C"
   TJPlacement *p = [TJPlacement placementWithName:@"Main Menu" delegate:self];

   // Callbacks

   - (void)requestDidSucceed:(TJPlacement*)placement{}
   - (void)requestDidFail:(TJPlacement*)placement error:(NSError*)error{}
   - (void)contentIsReady:(TJPlacement*)placement{}
   - (void)contentDidAppear:(TJPlacement*)placement{} 
   - (void)contentDidDisappear:(TJPlacement*)placement{}
   ```

3) **iOS (Swift)**

   ```swift title="Swift"
   let p = TJPlacement(name: "Main Menu", delegate: self)

   // Callbacks

   func requestDidSucceed(_ placement: TJPlacement!) {}
   func requestDidFail(_ placement: TJPlacement!, error: Error!) {}
   func contentIsReady(_ placement: TJPlacement!) {}
   func contentDidAppear(_ placement: TJPlacement!) {}
   func contentDidDisappear(_ placement: TJPlacement!) {}
   ```

4) **Unity**

   ```csharp title="C#"
   TJPlacement p = TJPlacement.CreatePlacement("PLACEMENT_NAME");

   TJPlacement.OnRequestSuccess += HandlePlacementRequestSuccess;
   TJPlacement.OnRequestFailure += HandlePlacementRequestFailure;
   TJPlacement.OnContentReady += HandlePlacementContentReady;
   TJPlacement.OnContentShow += HandlePlacementContentShow;
   TJPlacement.OnContentDismiss += HandlePlacementContentDismiss;
   ```

5) **React Native**

   ```js title="Javascript"
   let placement = new TJPlacement("PLACEMENT_NAME");

   placement.on(TJPlacement.REQUEST_DID_SUCCEED, (placement: TJPlacement) => { });
   placement.on(TJPlacement.REQUEST_DID_FAIL, (placement: TJPlacement) => { });
   placement.on(TJPlacement.CONTENT_IS_READY, (placement: TJPlacement) => { });
   placement.on(TJPlacement.CONTENT_DID_APPEAR, (placement: TJPlacement) => { });
   placement.on(TJPlacement.CONTENT_DID_DISAPPEAR, (placement: TJPlacement) => { });
   ```

> **Important:**
>
> 在请求内容之前，请确认已收到&#x20;
>
> `onConnectSuccess`
>
> &#x20;回调以确保 Tapjoy SDK 已成功连接。收到&#x20;
>
> `onConnectSuccess`
>
> &#x20;回调可以避免过早请求内容而导致错误。

4. 要为广告位请求应用内消息，请将以下代码复制到您的项目中。

1) **Android**

   ```java title="Java"
   if(Tapjoy.isConnected()) {
   p.requestContent();
   } else {
   Log.d("MyApp", "Tapjoy SDK must finish connecting before requesting content.")
   }
   ```

2) **iOS (Objective-C)**

   ```objc title="Objective-C"
   [p requestContent];
   ```

3) **iOS (Swift)**

   ```swift title="Swift"
   p?.requestContent()
   ```

4) **Unity**

   ```csharp title="C#"
   if (Tapjoy.IsConnected()) {
   p.requestContent();
   } else {
       Debug.LogWarning("Tapjoy SDK must be connected before you can request content.");
   }
   ```

5) **React Native**

   ```js title="Javascript"
   placement.requestContent();
   ```

5. 要展示可用的应用内消息，请将以下代码复制到您的项目中。

1) **Android**

   此代码通过 `onContentReady` 监听器方法来展示应用内消息。

   ```java title="Java"
   public void onContentReady(TJPlacement tjPlacement) {
   if(tjPlacement.isContentReady()) {
       p.showContent();
   }
   }
   ```

2) **iOS (Objective-C)**

   ```objc title="Objective-C"
   if (p.isContentReady) {
       [p showContentWithViewController：nil];
   }
   else {
   //handle situation where there is no content to show, or it has not yet downloaded.
   }
   ```

3) **iOS (Swift)**

   ```swift title="Swift"
   if (p.isContentReady) {
   p.showContent(with: nil)
   } else {
   //handle situation where there is no content to show, or it has not yet downloaded.
   }
   ```

4) **Unity**

   ```csharp title="C-Sharp"
   if (p.IsContentReady()) {
   p.ShowContent();
   } else {
       // Code to handle situation where content is not ready goes here
   }
   ```

5) **React Native**

   ```js title="Javascript"
   if (placement.isContentReady()) {
   placement.showContent();
   }
   ```
