# 为 Android 构构建自定义适配器

> 在 Android 平台上为网络开发和集成自定义适配器，包括必要的配置和测试过程。

本文档介绍构建自定义适配器的步骤，并向发布者提供将网络与 ironSource 聚合集成所需的资源。

## 先决条件

1. 填写自定义适配器注册[表](/grow/levelplay/sdk/android/custom-adapters.md.md)
2. 确保您拥有以下可用信息：
   * 适配器软件包称
   * 适配器类名称
   * 网络配置密钥
3. 在[此处](/grow/levelplay/sdk/android/sdk-integration.md.md)下载最新的 LevelPlay SDK
4. 最低要求 LevelPlay SDK 版本为 7.1.13，适用于奖励视频和插页式广告单位。

> **Note:**
>
> 对于 Android 和 Unity 开发的项目，所需的最低 LevelPlay SDK
> 横幅广告单元的版本为 7.3.0

### 重要

* 确保在代码中处理主线程要求
* 确保添加代码保护和异常处理以保护应用程序免受意外故障的影响。

## 如何为网络创建适配器

您的网络适配器将管理网络广告逻辑，允许发布者使用 ironSource 聚合展示来自您的网络的广告服务。

在此过程中，您需要创建一个适配类，称为 BaseAdapter，并为要支持的每个广告单元创建一个额外的类。

BaseAdapter 将帮助您管理网络的 SDK，包括 SDK 初始化过程，并允许您定义在整个会话中可用于所有广告单位的变量和常量。

广告单元类将确定加载、展示和管理广告的逻辑，并将针对瀑布流中的每个广告展示进行实例化。

## 创建网络底部适配器

要实现网络适配器，请通过扩展 ironSource **BaseAdapter** 类在专用软件包中创建一个新类

使用您在自定义适配器注册确认电子邮件中收到的**软件包**和**底部适配器**名称。

```java
软件包 com. ironsource.adapters.custom.<YourNetworkName>;
public class <YourNetworkName>CustomAdapter extends BaseAdapter {
   // Your class implementation
}
```

### 初始化网络 SDK

ironSource 聚合将在聚合中的任何初始化过程中调用底部适配器的初始化 API。因此，可能会多次调用此 API。

作为 init 实现的一部分，确保在时间 NetworkInitializationListener 中定义的初始化回调。

**AdData** 参数将包含发布者提供给 ironSource 的配置数据。在[此处](/grow/levelplay/sdk/android/custom-adapters.md.md)了解有关 AdData 类的更多信息。

```java
void init(@NotNull AdData adData, @NotNull Context context, @Nullable NetworkInitializationListener listener)
{
   ...
   if (init-success-condition) {
      // Initialization completed successfully
      listener.onInitSuccess();
   } else {
     // Initialization failed
     listener.onInitFailed(AdapterErrors.ADAPTER_ERROR_MISSING_PARAMS, error);
   }
}
```

### 提供 SDK 和适配器版本

此信息将指示发布者的 app 上当前实现了哪些 SDK 和适配器版本。在实现 getNetworkSDKVersion 时，我们建议使用 API 而不是硬编码值，以便更灵活地更新适配器和 SDK 支持。

```java
@Nullable 字符串 getNetworkSDKVersion();
@NotNull 字符串 getAdapterVersion();
```

## 添加对插页式广告单元的支持

### 创建插页式广告单元类

创建一个类，通过扩展 **BaseInterstitial** 类\*\*来管理插页式广告单元，\*\*作为网络自定义适配器的同一软件包的一部分。当发布者通过 加载 API 在app程序中触发新的插页式广告时，类将被激活。

在注册过程中使用从 ironSource 收到的软件包和插页类名称。

```java
软件包 com. ironsource.adapters.custom.[YourNetworkName];
public class SampleCustomInterstitial extends BaseInterstitial<SampleCustomAdapter> implements SampleNetworkInterstitialAdListener {
public class <YourNetworkName>CustomInterstitial extends
BaseInterstitial <<YourNetworkNameCustomAdapter>> {
...
}
```

### 实现广告单元构造函数

使用 NetworkSetting 对象实现构造函数。这是在插页式广告单元实现过程中必需的，它将确保您的网络可以添加到瀑布流中。

```java
public <YourNetworkName>CustomInterstitial(NetworkSettings networkSettings) {
   super(networkSettings);
}
```

### 请求插页式广告

覆盖 LoadAd API 以允许发布者从您的网络请求插页广告服务。[AdData](/grow/levelplay/sdk/android/custom-adapters.md.md) 允许您访问发布者的输入并接收广告标识符。

请确保实现 InterstitialAdListener 回调，以便成功加载广告 (onAdLoadSuccess) 和任何类型的失败 (onAdLoadFailed)。如果监听器回调在预定义时间后未触发，则冥想将停止加载，并且网络将无法提供广告。

```java
public void loadAd(AdData adData, Activity activity, InterstitialAdListener listener) {

   // Load your ad
}
```

### 检查广告是否可用

覆盖 isAdAvailable API，允许发布者在尝试向用户展示广告之前检查广告的准备情况。如果成功加载广告，API 应返回 true，如果当前未加载广告，则返回 false。为此，可以使用网络的 is-ad-available 指示（如果网络提供），或者手动管理广告状态作为 LoadAd 和 ShowAd API 的一部分。

```java
public boolean isAdAvailable(AdData adData) {
   return isAdAvailable;
}
```

### 显示插页式广告

成功加载广告后，发布者应该能够显示该广告。在验证 isAdAvailable 为 true 后，可以覆盖 showAd API，从而为发布者提供更好的体验。此方法收到的部分信息是 [AdData](/grow/levelplay/sdk/android/custom-adapters.md.md)。使用此对象时，将允许您展示相关广告。如果无法执行显示，则应返回 onAdShowFailed 回调。

```java
public void showAd(AdData adData, InterstitialAdListener listener) {

   // check your ad load status
   if (isAdLoaded)  {
      // show your ad

   } else {
      listener.onAdShowFailed(adatperErrorCode, adapterErrorMsg);
   }
}
```

### 报告 InterstitialAdListener 回调

确保根据网络的功能覆盖 InterstitialAdListener 的回调。正确报告回调将确保 ironSource 聚合的最佳实践流程，并启用网络性能数据在 ironSource 平台中正确反映。

#### 强制回调

```java
// Indicates that interstitial ad was loaded successfully
void onAdLoadSuccess();

// The interstitial ad failed to load.使用 ironSource ErrorTypes（无填充/其他）
void onAdLoadFailed(@NotNull AdapterErrorType adapterErrorType, int errorCode, @Nullable String errorMessage);

// The interstitial ad is displayed successfully to the user.这表示展示量。
void onAdOpened();

// User closed the interstitial ad
void onAdClosed();

// The ad could not be displayed
void onAdShowFailed(int errorCode, @Nullable String errorMessage);
```

#### 可选回调

```java
// Indicates the network differentiates between show-success and ad-open (impression)
void onAdShowSuccess();

// Indicates an ad was clicked
void onAdClicked();
```

### 如何从底部适配器获取数据（可选）

如果您的底部适配器通过会话管理与广告单位相关的状态或参数，请使用 getNetworkAdapter API。这包括任何定义为底部适配器一部分的对象，这些对象应在广告单元 API 中使用。

```java
// example of data retrieved from your network level adapter
SampleCustomAdapter networkAdapter = getNetworkAdapter();

if (networkAdapter != null) {

   // call network level method
   String extraData = networkAdapter.sampleAppLevelData();

}
```

## 添加对奖励视频广告单元的支持

### 创建奖励视频广告单元类

创建一个类，通过扩展 **BaseRewardedVideo** 类\*\*来管理奖励视频广告单元，\*\*作为网络自定义适配器的同一软件包的一部分。当发布者通过 加载 API 在app中触发新的奖励视频广告时，类将被激活。

使用您在注册过程中从 Ironsource 收到的资源软件包和奖励视类名称。

```java
软件包 com. ironsource.adapters.custom.[YourNetworkName];
import com.ironsource.mediationsdk.adunit.adapter.BaseRewardedVideo;
import com.ironsource.mediationsdk.adunit.adapter.listener.RewardedVideoAdListener;
import com.ironsource.mediationsdk.adunit.adapter.utility.AdData;
import com.ironsource.mediationsdk.adunit.adapter.utility.AdapterErrorType;
import com.ironsource.mediationsdk.adunit.adapter.utility.AdapterErrors;
import com.ironsource.mediationsdk.model.NetworkSettings;
```

```java
public class SampleCustomRewardedVideo extends BaseRewardedVideo<SampleCustomAdapter> implements SampleNetworkRewardedVideoListener {
   // Add your adapter code here
}
```

### 实现广告单元构造函数

使用 NetworkSetting 对象实现构造函数。这是在奖励视频广告单元实现过程中必需的，它将确保您的网络可以添加到瀑布流中。

```java
public <YourCustomNetwork>CustomRewardedVideo(NetworkSettings networkSettings) {
        super(networkSettings);
}
```

### 请求奖励视频广告

覆盖 LoadAd API 可允许发布者从您的网络请求奖励视频广告服务。[AdData](/grow/levelplay/sdk/android/custom-adapters.md.md) 允许您访问发布者的输入并接收广告标识符。

请确保实现 RewardedVideoAdListener 回调，以便成功加载广告 (onAdLoadSuccess) 和任何类型的失败 (onAdLoadFailed)。如果监听器回调在预定义时间后未触发，则冥想将停止加载，并且网络将无法提供广告。

```java
public void loadAd(@NotNull AdData adData, @NotNull Activity activity, @NotNull RewardedVideoAdListener rewardedVideoAdListener) {
   // Load your ad
}
```

### 检查广告是否可用

覆盖 isAdAvailable API，允许发布者在尝试向用户展示广告之前检查广告的准备情况。如果成功加载广告，API 应返回 true，如果当前未加载广告，则返回 false。为此，可以使用网络的 is-ad-available 指示（如果网络提供），或者手动管理广告状态作为 LoadAd 和 ShowAd API 的一部分。

```java
public boolean isAdAvailable(AdData adData) {
   return isAdAvailable;
}
```

### 显示奖励视频广告

成功加载广告后，发布者应该能够显示该广告。在验证 isAdAvailable 为 true 后，可以覆盖 showAd API，从而为发布者提供更好的体验。此方法收到的部分信息是 [AdData](/grow/levelplay/sdk/android/custom-adapters.md.md)。使用此对象时，将允许您展示相关广告。如果无法执行显示，则应返回 onAdShowFailed 回调。

```java
public void showAd(AdData adData, RewardedVideoAdListener rewardedVideoAdListener) {

   // check your ad load status
   if (isAdLoaded)  {
      // show your ad

   } else {
      AdapterErrors adapterErrorCode = AdapterErrors.<ERROR CODE>;
      字符串 adapterErrorMsg = “报错消息”; rewardVideoAdListener.onAdShowFailed(adatperErrorCode, adapterErrorMsg);
   }
}
```

#### 报告 RewardedVideoAdListener 回调

确保根据网络的功能覆盖 RewardedVideoAdListener 的回调。正确报告回调将确保 ironSource 聚合的最佳实践流程，并启用网络性能数据在 ironSource 平台中正确反映。

#### 强制回调

```java
// Indicates that rewarded video ad was loaded successfully
void onAdLoadSuccess();
// The rewarded video ad failed to load.使用 ironSource ErrorTypes（无填充/其他）
void onAdLoadFailed(@NotNull AdapterErrorType adapterErrorType, int errorCode, @Nullable String errorMessage);
// The rewarded video ad is displayed successfully to the user.这表示在 ironSource 平台上的展示量。
void onAdOpened();
// User closed the rewarded video ad
void onAdClosed();
// The ad could not be displayed
void onAdShowFailed(int errorCode, @Nullable String errorMessage);
// The ad was rewarded successfully
void onAdRewarded();

```

#### 可选回调

```java
// Indicates an ad was clicked
void onAdClicked();
// Indicates an ad was displayed on foreground
void onAdVisible();
// Indicates an ad playable started
void onAdStarted();
// Indicates an ad playable ended
void onAdEnded();
```

## 添加对横幅广告单元的支持（仅限 Android 开发的应用程序）

### **步骤 1。创建横幅广告单元类**

创建一个类来管理横幅广告单元，方法是将 **BaseBanner** 类扩展为网络自定义适配器的同一软件包的一部分。当发布者通过 加载 API 在app程序中触发新的横幅广告时，类将被激活。

在注册过程中使用从 ironSource 收到的软件包和横幅类名称。

### 步骤 2.实现广告单元构造函数

使用 NetworkSetting 对象实现构造函数。这是在横幅广告单元实现过程中必需的，它将确保您的网络可以添加到瀑布流中。

```java
public <YourNetworkName>CustomBanner(NetworkSettings networkSettings) {
   super(networkSettings);
}
```

#### 横幅大小

请参阅下表以了解我们支持的横幅大小的详细信息。自定义网络可能支持这些大小的任意组合。横幅大小将作为参数接收，作为 loadAd API 的一部分。

当收到的横幅大小为 \*\*SMART 时，\*\*请确保根据设备屏幕大小将大小更改为 **BANNER** 或 **LEADERBOARD**（请参阅以下说明）。

| **ISBannerSize** | **描述**                       | **尺寸（以 dp（宽高）为单位）**                                               |
| ---------------- | ---------------------------- | ----------------------------------------------------------------- |
| **BANNER**       | 标准横幅                         | 320 x 50                                                          |
| **大**            | 大横幅                          | 320 x 90                                                          |
| **矩形**           | 中等矩形 (MREC)                  | 300 x 250                                                         |
| **SMART**        | Smart Banner（针对移动端和平板电脑进行调整） | 如果 (Screen width ≤ 720) 320 x 50 如果 (Screen width > 720) 728 x 90 |

### 步骤 3.请求横幅广告

实现 loadAd API 可允许发布者从您的网络请求横幅广告服务。[AdData](/grow/levelplay/sdk/android/custom-adapters.md.md) 允许您访问发布者的输入并接收广告标识符，ISBannerSize 将指示请求的横幅大小。

```java
public void loadAd(@NotNull AdData adData, @NotNull Activity activity, @NotNull ISBannerSize bannerSize, @NotNull BannerAdListener bannerAdListener) {
 // Load your ad
}
```

### 步骤 4.销毁横幅

IronSource 要求 app 开发者通过实现以下 destroyAd 方法销毁横幅广告。

```java
 public void destroyAd(@NotNull AdData adData) {
    }
```

> **Note:**
>
> 如果您的网络 SDK 不支持此类 API，则应添加一个空的
> 实现。

### 步骤 5。报告 BannerAdListener 回调

根据网络的功能报告 BannerAdListener 的回调。这将确保网络的性能数据在 IronSource 平台中正确反映。

#### 强制回调

```java
// Indicates that a banner ad was loaded successfully
void onAdLoadSuccess(@NotNull View adView, @NotNull FrameLayout.LayoutParams frameLayoutParams)
// The banner ad failed to load.使用 ironSource ErrorTypes（无填充/其他）
void onAdLoadFailed(@NotNull AdapterErrorType adapterErrorType, int errorCode, @Nullable String errorMessage)
// The banner ad is displayed successfully to the user.这表示在 ironSource 平台上的展示量。
void onAdOpened()
// Indicates an ad was clicked
void onAdClicked()
```

定义由自定义适配器中的网络传递给 onAdLoadSuccess 回调的 LayoutParams 对象的值。下面列出了最佳实践：

* 通道实际横幅大小的宽度和高度。
* 将重力属性定义为重力。CENTER。

#### 可选回调

```java
//Should be invoked after a click, and before the user is taken out of the app
void onAdLeftApplication()
// Should be invoked after the ad view presents fullscreen content
void onAdScreenPresented()
// Should be invoked after the fullscreen content is dismissed
void onAdScreenDismissed()

```

## 使用适配器访问发布者的输入

在自定义适配器注册过程中，您提供了 app 和实例级密钥。

这些键的值将由发布者在 IronSource 平台上定义。通过使用 AdData 对象，这些值将在运行时可用。

AdData 对象包含一个包含配置值的映射，并且是适配器和广告单元类 API 的一部分。此参数在 Init、LoadAd、ShowAd 和 isAdAvailable API 中可用。

您可以使用在注册确认电子邮件中收到的名称访问 AdData 贴图结构中的值。

```java
// Get Publisher setup parameters
final 字符串 appLevelParam1 = adData.getString(<YourAppLevelParam1>);
final String instanceLevelParam1 = adData.getString(<YourInstanceLevelParam1>);
final String instanceLevelParam2 = adData.getString(<YourInstanceLevelParam2>);
```

## 使用 ironSource 报错代码和报错类型

### 报错类型

这与 **onAdLoadFailed** 回调相关。

| 报错类型                          | 描述            |
| ----------------------------- | ------------- |
| `ADAPTER_ERROR_TYPE_NO_FILL`  | 没有可用广告显示时使用   |
| `ADAPTER_ERROR_TYPE_INTERNAL` | 用于网络报告的任何其他原因 |

### 错误代码

这些报错代码与 **onAdLoadFailed** 和 **onAdShowFailed** 回调相关。

| 错误代码                           | 描述                       |
| ------------------------------ | ------------------------ |
| `ADAPTER_ERROR_MISSING_PARAMS` | 操作失败，因为调用 API 时某些所需信息不可用 |
| `ADAPTER_ERROR_AD_EXPIRED`     | 用于指示广告是否已过期              |
| `ADAPTER_ERROR_INTERNAL`       | 用于网络报告的任何其他报错            |

## 调试适配器（可选）

如果选择支持调试日志，请从app程序实现并调用 setAdapterDebug API。这应该作为 BaseAdapter 的一部分来完成。

```java
public class <YourNetworkName>CustomAdapter extends BaseAdapter {
   @Override
   public void setAdapterDebug(boolean adapterDebug) {
      this.adapterDebug = adapterDebug;
   }
}
```
