广告网络中介适配器开发

本指南适用于要构建中介适配器的广告联盟。如果您是发布商,请参阅发布商中介说明

广告联盟适配器是广告联盟与 Google 移动广告中介之间的通信层。

适配器负责实现 MediationBannerAdapter(用于支持横幅广告)和 MediationInterstitialAdapter(用于支持插页式广告)。此外,它还必须在适当的时间调用 MediationBannerListenerMediationInterstitialListener 中的回调,将这些事件通知 Google 移动广告中介,这些事件也可以转发给开发者。

示例广告联盟

本指南演示了如何为示例广告联盟构建适配器。示例广告联盟包含以下大多数广告联盟都会提供的一些典型的类:

class SampleAdView {
    public SampleAdView(Context context);
    public void setSize(SampleAdSize size);
    public void setAdUnit(String sampleAdUnit);
    public void setAdListener(SampleAdListener listener);
    public void fetchAd(SampleAdRequest request);
    public void destroy();
}

class SampleAdSize {
    public SampleAdSize(int width, int height);
    public int getWidth();
    public int getHeight();
}

class SampleAdRequest {
    public SampleAdRequest();
    public void setKeywords(Set<String> keywords);
    public void setTestMode(boolean useTesting);
}

class SampleAdListener {
    public void onAdFetchSucceeded();
    public void onAdFetchFailed(SampleErrorCode code);
    public void onAdFullScreen();
    public void onAdClosed();
}

enum SampleErrorCode {
    UNKNOWN,
    BAD_REQUEST,
    NETWORK_ERROR,
    NO_INVENTORY
}

class SampleInterstitial {
    public SampleInterstitial(Context context);
    public void setAdUnit(String sampleAdUnit);
    public void setAdListener(SampleAdListener listener);
    public void fetchAd(SampleAdRequest request);
    public void show();
    public void destroy();
}

如需详细了解这些类,请参阅完整的 SDK 实现

实现横幅广告适配器

如需实现支持横幅广告的适配器,请创建一个实现 MediationBannerAdapter 的类。

public class SampleAdapter implements MediationBannerAdapter {
    @Override
    public void requestBannerAd(
            Context context,
            MediationBannerListener listener,
            Bundle serverParameters,
            AdSize adSize,
            MediationAdRequest mediationAdRequest,
            Bundle mediationExtras) {}

    @Override
    public View getBannerView() {}

    @Override
    public void onDestroy() {}

    @Override
    public void onPause() {}

    @Override
    public void onResume() {}
}

在深入了解如何实现 MediationBannerAdapter 之前,我们先来介绍一下服务器参数和中介额外信息 (extras),以及如何将这些值传递给适配器。

服务器参数

您的广告网络可能需要使用一些标识符来识别发布商。例如,示例广告联盟只需要一个广告单元。requestBannerAd() 内的 serverParameters 软件包中为您提供了这些必需参数。在开发期间,您可以假设该 bundle 中已经填充了您需要的键:

private static final String SAMPLE_AD_UNIT_KEY = "ad_unit";

@Override
public void requestBannerAd(
        Context context,
        MediationBannerListener listener,
        Bundle serverParameters,
        AdSize adSize,
        MediationAdRequest mediationAdRequest,
        Bundle mediationExtras) {
    String adUnit = serverParameters.getString(SAMPLE_AD_UNIT_KEY);
    ...
}

AdMob 会向您发送一份调查问卷,询问您需要从发布商处获取哪些服务器参数才能请求和投放广告。AdMob 将根据输入的内容在 AdMob 界面中配置您的广告网络。下面的屏幕截图显示 Millennial Media 需要 APID,InMobi 需要 App ID

AdMob 将在实例化适配器时使用此信息来填充 serverParameters bundle。

如需详细了解发布商如何配置中介广告联盟,请参阅这篇文章

其他定位参数

MediationAdRequest 包含一些可用于广告定位的常用定位信息,例如:

中介额外信息 (extras)

如果您的广告网络支持 MediationAdRequest 未提供的定位信息,应用开发者可以将一系列 mediationExtras 专门传递到您的广告网络。中介提供了如何传递中介额外信息的示例。

为了让开发者更轻松地选择传递这些信息,您可以在适配器中提供 bundle 构建器类。假设您的网络支持传递收入值。您可以在适配器中添加用于设置收入的构建器类:

public static final class BundleBuilder {
    private int income;

    public BundleBuilder setIncome(int income) {
        this.income = income;
        return this;
    }

    public Bundle build() {
        Bundle bundle = new Bundle();
        bundle.putInt("income", income);
        return bundle;
    }
}

此类将为开发者提供一个干净的 API,用于为您的广告联盟生成 bundle:

Bundle sampleAdapterBundle =
        new SampleAdapter.BundleBuilder().setIncome(100000).build();

requestBannerAd()

现在,您已经了解了服务器参数和中介额外信息 (extras),我们可以使用它们来构建 MediationBannerAdapter

系统会在适配器实例化后立即调用 requestBannerAd() 方法。您应在此处创建广告视图并发出横幅广告请求。

示例广告联盟的 requestBannerAd() 实现如下所示:

public class SampleAdMobAdapter implements MediationBannerAdapter {
    private static final String SAMPLE_AD_UNIT_KEY = "ad_unit";
    private SampleAdView sampleAdView;

    @Override
    public void requestBannerAd(
            Context context, // May be an application context.
            MediationBannerListener listener,
            Bundle serverParameters,
            AdSize adSize,
            MediationAdRequest mediationAdRequest,
            Bundle mediationExtras) {
        sampleAdView = new SampleAdView(context);

        if (serverParameters.containsKey(SAMPLE_AD_UNIT_KEY)) {
            sampleAdView.setAdUnit(serverParameters.getString(SAMPLE_AD_UNIT_KEY));
        } else {
            listener.onAdFailedToLoad(this, AdRequest.ERROR_CODE_INVALID_REQUEST);
        }

        sampleAdView.setSize(
                new SampleAdSize(adSize.getWidth(),adSize.getHeight()));

        sampleAdView.setAdListener(
                new SampleBannerEventForwarder(listener, this));

        SampleAdRequest request = new SampleAdRequest();
        request.setTestMode(mediationAdRequest.isTesting());
        request.setKeywords(mediationAdRequest.getKeywords());
        sampleAdView.fetchAd(request);
    }
}

请勿假设上下文参数的类型为 Activity。根据发布商的实现情况,Google 移动广告中介可能会向您的适配器转发应用上下文。如果您的适配器无法处理应用上下文,建议您使用错误代码 AdRequest.ERROR_CODE_INVALID_REQUEST 调用 onAdFailedToLoad()

MediationBannerListener 回调

您应将提供给您的 MediationBannerListener 保存在 requestBannerAd() 中,以便将广告事件转发回 Google 移动广告中介。每个回调函数均必须在广告生命周期的适当时间调用:

方法 致电时间
onAdLoaded() 横幅广告请求成功。
onAdFailedToLoad() 横幅广告请求失败。
onAdClicked() 用户点击了横幅广告。
onAdOpened() 横幅广告呈现全屏视图时。
onAdClosed() 用户在点击横幅广告后返回应用。
onAdLeftApplication() 横幅广告会导致用户离开应用。

示例广告联盟适配器会创建一个名为 SampleBannerEventForwarder 的类来处理事件转发:

public class SampleBannerEventForwarder extends SampleAdListener {
    private MediationBannerListener mediationListener;
    private SampleAdapter adapter;

    public SampleBannerEventForwarder(
            MediationBannerListener listener, SampleAdapter adapter) {
        this.mediationListener = listener;
        this.adapter = adapter;
    }

    @Override
    public void onAdFetchSucceeded() {
        mediationListener.onAdLoaded(adapter);
    }

    @Override
    public void onAdFetchFailed(SampleErrorCode errorCode) {
        switch(errorCode) {
            case UNKNOWN:
                mediationListener.onAdFailedToLoad(adapter, AdRequest.ERROR_CODE_INTERNAL_ERROR);
                break;
            case BAD_REQUEST:
                mediationListener.onAdFailedToLoad(adapter, AdRequest.ERROR_CODE_INVALID_REQUEST);
                break;
            case NETWORK_ERROR:
                mediationListener.onAdFailedToLoad(adapter, AdRequest.ERROR_CODE_NETWORK_ERROR);
                break;
            case NO_INVENTORY:
                mediationListener.onAdFailedToLoad(adapter, AdRequest.ERROR_CODE_NO_FILL);
                break;
        }
    }

    @Override
    public void onAdFullScreen() {
        mediationListener.onAdClicked(adapter);
        mediationListener.onAdOpened(adapter);
        mediationListener.onAdLeftApplication(adapter);
    }

    @Override
    public void onAdClosed() {
        mediationListener.onAdClosed(adapter);
    }
}

请注意示例广告联盟适配器如何在同一回调中发送 onAdClickedonAdOpenedonAdLeftApplication。虽然您广告联盟的回调可能与 Google 移动广告所需的回调并不完全匹配,但适配器仍负责提供合理的映射。

getBannerView

一旦您调用 MediationBannerListener.onAdLoaded(),中介将会调用 getBannerView(),以便在屏幕上显示您广告联盟的横幅广告视图。只需返回您在 requestBannerAd() 中创建的横幅广告视图即可:

@Override
public View getBannerView() {
    return sampleAdView;
}

activity 生命周期事件

如果应用开发者向中介通知 onPause()onResume() 活动事件,中介会向适配器通知这些事件。为横幅广告执行任何必要的暂停和恢复操作:

@Override
public void onPause() {
}

@Override
public void onResume() {
}

Sample Ad Network 不包括暂停或恢复调用,因此它会提供一个空的实现。

当适配器即将销毁时,中介会尽力尝试调用 onDestroy()。请在此时执行必要的清理:

@Override
public void onDestroy() {
    if (sampleAdView != null) {
        sampleAdView.destroy();
    }
}

智能横幅广告

Google 移动广告 SDK 支持智能横幅广告尺寸,即根据设备尺寸调整高度并采用全宽。

为了准确获取智能横幅广告的广告尺寸,适配器应使用 adSize.getWidthInPixels(context) 获取宽度,使用 adSize.getHeightInPixels(context)(而不是 adSize.getHeight())获取高度。然后,此值应除以设备密度:

int widthInPixels = adSize.getWidthInPixels(context);
int heightInPixels = adSize.getHeightInPixels(context);
DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
int widthInDp = Math.round(widthInPixels / displayMetrics.density);
int heightInDp = Math.round(heightInPixels / displayMetrics.density);

然后,您可以在发出广告请求时使用 widthInDpheightInDp 作为尺寸。

大功告成!现在,您已得到一个适用于横幅广告的有效中介适配器!有关参考信息,请点击此处查看 SampleAdapter 的完整实现。

实现插页式广告适配器

插页式广告的适配器实现与横幅广告的类似。如需实现支持插页式广告的适配器,请创建一个实现 MediationInterstitialAdapter 的类:

public class SampleAdapter implements MediationInterstitialAdapter {
    @Override
    public void requestInterstitialAd(
            Context context,
            MediationInterstitialListener listener,
            Bundle serverParameters,
            MediationAdRequest mediationAdRequest,
            Bundle mediationExtras) {}

    @Override
    public View showInterstitial() {}

    @Override
    public void onDestroy() {}

    @Override
    public void onPause() {}

    @Override
    public void onResume() {}
}

如果您的适配器还支持横幅广告,您可以使用同一适配器类来实现这两种接口。

在继续实现 MediationInterstitialAdapter 之前,请先熟悉服务器参数和中介额外信息 (extras)。

服务器参数(插页式)

请参阅横幅广告服务器参数部分。

其他定位参数(插页式)

请参阅横幅广告其他定位参数部分。

中介额外信息 (extras)(插页式)

请参阅横幅广告中介额外信息 (extras) 部分。

requestInterstitialAd

系统会在适配器实例化后立即调用 requestInterstitialAd() 方法。您应在此处创建插页式广告并发出插页式广告请求。

示例广告联盟的 requestInterstitialAd() 实现将如下所示:

public class SampleAdapter implements MediationBannerAdapter {
    private static final String SAMPLE_AD_UNIT_KEY = "ad_unit";

    private SampleInterstitial sampleInterstitial;

    @Override
    public void requestInterstitialAd(
            Context context, // May be an application context.
            MediationInterstitialListener listener,
            Bundle serverParameters,
            MediationAdRequest mediationAdRequest,
            Bundle mediationExtras) {
        sampleInterstitial = new SampleInterstitial(context);

        if (serverParameters.containsKey(SAMPLE_AD_UNIT_KEY)) {
            sampleInterstitial.setAdUnit(serverParameters.getString(SAMPLE_AD_UNIT_KEY));
        } else {
            listener.onAdFailedToLoad(this, AdRequest.ERROR_CODE_INVALID_REQUEST);
        }

        sampleInterstitial.setAdListener(
                new SampleInterstitialEventForwarder(listener, this));

        // Make an ad request.
        SampleAdRequest request = new SampleAdRequest();
        request.setTestMode(mediationAdRequest.isTesting());
        request.setKeywords(mediationAdRequest.getKeywords());
        sampleInterstitial.fetchAd(request);
    }
}

请勿假设上下文参数的类型为 Activity!Google 移动广告中介会转发应用开发者传递的上下文,而且很有可能传递应用上下文。如果您的适配器无法处理应用上下文,建议您使用错误代码 AdRequest.ERROR_CODE_INVALID_REQUEST 调用 onAdFailedToLoad

MediationInterstitialListener 回调

您应将提供给您的 MediationInterstitialListener 保存在 requestInterstitialAd 中,以便将广告事件转发回 Google 移动广告中介。每个回调函数均必须在广告生命周期的适当时间调用:

方法 致电时间
onAdLoaded 插页式广告请求成功时。
onAdFailedToLoad 插页式广告请求失败。
onAdOpened 插页式广告展示时。
onAdClosed 插页式广告关闭时。
onAdLeftApplication 插页式广告导致用户离开应用时。

showInterstitial

调用 MediationInterstitialListener.onAdLoaded() 后,您应等到调用 showInterstitial() 后再展示插页式广告。插页式广告何时展示,可能需要在请求发出几分钟之后才能展示。

showInterstitial() 的实现非常简单。只需展示您的插页式广告对象即可:

@Override
public void showInterstitial() {
    sampleInterstitial.show();
}

活动生命周期事件(插页式广告)

请参阅横幅广告 activity 生命周期事件部分。

实现活动生命周期事件后,中介适配器就可以处理插页式广告了!有关参考信息,请点击此处查看 SampleAdapter 的完整实现。

常见问题解答

如果我的适配器仅支持横幅广告或插页式广告,而不是同时支持这两种广告,该怎么办?

如果您的适配器仅支持横幅广告,您只需实现 MediationBannerAdapter 接口。如果您的适配器仅支持插页式广告,您只需实现 MediationInterstitialAdapter 接口即可。