Настройка IMA SDK

Выберите платформу: HTML5 Android iOS tvOS

Пакеты IMA SDK упрощают интеграцию мультимедийной рекламы в ваши веб-сайты и приложения. Пакеты IMA SDK могут запрашивать рекламу с любого рекламного сервера , совместимого с VAST, и управлять её воспроизведением в ваших приложениях. Клиентские пакеты IMA SDK позволяют вам контролировать воспроизведение видеоконтента, в то время как SDK управляет воспроизведением рекламы. Реклама воспроизводится в отдельном видеоплеере, расположенном поверх видеоплеера приложения.

В этом руководстве показано, как интегрировать IMA SDK в пустой проект Android Studio, используя Android VideoView для отображения контента и рекламы. Чтобы ознакомиться с готовым примером интеграции, скачайте BasicExample с GitHub.

Обзор клиентской части IMA

Реализация IMA на стороне клиента включает четыре основных компонента SDK, которые продемонстрированы в этом руководстве:

  • AdDisplayContainer : объект-контейнер, который указывает, где IMA отображает элементы пользовательского интерфейса рекламы и измеряет видимость, включая Active View и Open Measurement .
  • AdsLoader — объект, который запрашивает рекламу и обрабатывает события, возникающие при ответах на запросы рекламы. Необходимо создать только один экземпляр загрузчика рекламы, который можно использовать повторно на протяжении всего жизненного цикла приложения.
  • AdsRequest : объект, определяющий запрос на рекламу. Запросы на рекламу содержат URL-адрес тега VAST, а также дополнительные параметры, такие как размеры объявления.
  • AdsManager : объект, который содержит ответ на запрос рекламы, управляет воспроизведением рекламы и прослушивает события рекламы, запускаемые SDK.

Предпосылки

1. Создайте новый проект Android Studio.

Чтобы создать свой проект Android Studio, выполните следующие шаги:

  1. Запустите Android Studio.
  2. Выберите Начать новый проект Android Studio .
  3. На странице «Выберите свой проект» выберите шаблон «Пустая деятельность» .
  4. Нажмите кнопку «Далее» .
  5. На странице «Настройка проекта» дайте проекту имя и выберите Java в качестве языка.
  6. Нажмите кнопку Готово .

2. Добавьте IMA SDK в свой проект.

Сначала в файле build.gradle уровня приложения добавьте импорты для IMA SDK в раздел dependencies. В связи с размером IMA SDK, реализуйте и включите multidex здесь. Это необходимо для приложений, у которых minSdkVersion установлен на 20 или ниже. Также добавьте новый compileOptions для указания информации о совместимости версий Java и включения десахаринга библиотек.

Для работы IMA SDK требуется включить дешугаринг библиотек. Для этого установите значение coreLibraryDesugaringEnabled true и добавьте coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' в качестве зависимости в файле build.gradle . Подробнее см. в разделе API Java 11+, доступные через дешугаринг с помощью спецификации nio .

apply plugin: 'com.android.application'

android {
    namespace 'com.google.ads.interactivemedia.v3.samples.videoplayerapp'
    compileSdk 36

    // Java 17 required by Gradle 8+
    compileOptions {
        // Required by IMA SDK v3.37.0+
        coreLibraryDesugaringEnabled true

        // Java 17 required by Gradle 8+
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

    defaultConfig {
        applicationId "com.google.ads.interactivemedia.v3.samples.videoplayerapp"
        minSdkVersion 21
        targetSdkVersion 36
        multiDexEnabled true
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

repositories {
    google()
    mavenCentral()
}

dependencies {
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
    implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
    implementation 'androidx.appcompat:appcompat:1.7.1'
    implementation 'androidx.browser:browser:1.9.0'
    implementation 'androidx.media:media:1.7.0'
    implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.37.0'
}

3. Обновите макет приложения.

Обновите макет приложения, включив в него VideoView для воспроизведения как контента, так и рекламы:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MyActivity"
    tools:ignore="MergeRootFrame">

    <RelativeLayout
        android:background="#000000"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.4"
        android:orientation="vertical"
        android:id="@+id/videoPlayerContainer" >

        <VideoView
            android:id="@+id/videoView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <ImageButton
            android:id="@+id/playButton"
            android:contentDescription="@string/play_description"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/ic_action_play_over_video"
            android:background="@null" />

    </RelativeLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.6"
        android:id="@+id/videoDescription" >

        <TextView
            android:id="@+id/playerDescription"
            android:text="@string/app_name"
            android:textAlignment="center"
            android:gravity="center_horizontal"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingVertical="@dimen/font_size"
            android:textSize="@dimen/font_size" />
    </FrameLayout>

</LinearLayout>

4. Импортируйте IMA в основную деятельность

Добавьте операторы импорта для IMA SDK:

import android.content.Context;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.MediaController;
import android.widget.VideoView;
import androidx.appcompat.app.AppCompatActivity;
import com.google.ads.interactivemedia.v3.api.AdDisplayContainer;
import com.google.ads.interactivemedia.v3.api.AdErrorEvent;
import com.google.ads.interactivemedia.v3.api.AdEvent;
import com.google.ads.interactivemedia.v3.api.AdsLoader;
import com.google.ads.interactivemedia.v3.api.AdsManager;
import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings;
import com.google.ads.interactivemedia.v3.api.AdsRequest;
import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
import java.util.Arrays;

Обновите класс MyActivity , чтобы расширить AppCompatActivity . Класс AppCompatActivity обеспечивает поддержку новых функций платформы на старых устройствах Android. Затем добавьте набор приватных переменных, которые будут использоваться в приложении:

/** Main activity. */
public class MyActivity extends AppCompatActivity {

  private static final String LOGTAG = "IMABasicSample";
  private static final String SAMPLE_VIDEO_URL =
      "https://storage.googleapis.com/gvabox/media/samples/stock.mp4";

  /**
   * IMA sample tag for a single skippable inline video ad. See more IMA sample tags at
   * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags
   */
  private static final String SAMPLE_VAST_TAG_URL =
      "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/"
          + "single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast"
          + "&unviewed_position_start=1&env=vp&correlator=";

  // Factory class for creating SDK objects.
  private ImaSdkFactory sdkFactory;

  // The AdsLoader instance exposes the requestAds method.
  private AdsLoader adsLoader;

  // AdsManager exposes methods to control ad playback and listen to ad events.
  private AdsManager adsManager;

  // The saved content position, used to resumed content following an ad break.
  private int savedPosition = 0;

  // This sample uses a VideoView for content and ad playback. For production
  // apps, Android's Exoplayer offers a more fully featured player compared to
  // the VideoView.
  private VideoView videoPlayer;
  private MediaController mediaController;
  private VideoAdPlayerAdapter videoAdPlayerAdapter;
  private ImaSdkSettings imaSdkSettings;

5. Создайте класс VideoAdPlayerAdapter

Создайте класс VideoAdPlayerAdapter с VideoView и адаптируйте его к интерфейсу VideoAdPlayer IMA. Этот класс будет обрабатывать воспроизведение контента и рекламы, а также содержать набор методов, которые должен реализовать видеоплеер для использования в IMA SDK:

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.Log;
import android.widget.VideoView;
import com.google.ads.interactivemedia.v3.api.AdPodInfo;
import com.google.ads.interactivemedia.v3.api.player.AdMediaInfo;
import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/** Example implementation of IMA's VideoAdPlayer interface. */
public class VideoAdPlayerAdapter implements VideoAdPlayer {

  private static final String LOGTAG = "IMABasicSample";
  private static final long POLLING_TIME_MS = 250;
  private static final long INITIAL_DELAY_MS = 250;
  private final VideoView videoPlayer;
  private final AudioManager audioManager;
  private final List<VideoAdPlayerCallback> videoAdPlayerCallbacks = new ArrayList<>();
  private Timer timer;
  private int adDuration;

  // The saved ad position, used to resumed ad playback following an ad click-through.
  private int savedAdPosition;
  private AdMediaInfo loadedAdMediaInfo;

  public VideoAdPlayerAdapter(VideoView videoPlayer, AudioManager audioManager) {
    this.videoPlayer = videoPlayer;
    this.videoPlayer.setOnCompletionListener(
        (MediaPlayer mediaPlayer) -> notifyImaOnContentCompleted());
    this.audioManager = audioManager;
  }

6. Переопределите методы VideoAdPlayer

Переопределите следующие методы VideoAdPlayer :

Метод playAd() устанавливает URL-адрес контента или рекламы и настраивает прослушиватель на запуск воспроизведения после загрузки мультимедиа.

@Override
public void addCallback(VideoAdPlayerCallback videoAdPlayerCallback) {
  videoAdPlayerCallbacks.add(videoAdPlayerCallback);
}

@Override
public void loadAd(AdMediaInfo adMediaInfo, AdPodInfo adPodInfo) {
  // This simple ad loading logic works because preloading is disabled. To support
  // preloading ads your app must maintain state for the currently playing ad
  // while handling upcoming ad downloading and buffering at the same time.
  // See the IMA Android preloading guide for more info:
  // https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/preload
  loadedAdMediaInfo = adMediaInfo;
}

@Override
public void pauseAd(AdMediaInfo adMediaInfo) {
  Log.i(LOGTAG, "pauseAd");
  savedAdPosition = videoPlayer.getCurrentPosition();
  stopAdTracking();
}

@Override
public void playAd(AdMediaInfo adMediaInfo) {
  videoPlayer.setVideoURI(Uri.parse(adMediaInfo.getUrl()));

  videoPlayer.setOnPreparedListener(
      mediaPlayer -> {
        adDuration = mediaPlayer.getDuration();
        if (savedAdPosition > 0) {
          mediaPlayer.seekTo(savedAdPosition);
        }
        mediaPlayer.start();
        startAdTracking();
      });
  videoPlayer.setOnErrorListener(
      (mediaPlayer, errorType, extra) -> notifyImaSdkAboutAdError(errorType));
  videoPlayer.setOnCompletionListener(
      mediaPlayer -> {
        savedAdPosition = 0;
        notifyImaSdkAboutAdEnded();
      });
}

@Override
public void release() {
  // any clean up that needs to be done.
}

@Override
public void removeCallback(VideoAdPlayerCallback videoAdPlayerCallback) {
  videoAdPlayerCallbacks.remove(videoAdPlayerCallback);
}

@Override
public void stopAd(AdMediaInfo adMediaInfo) {
  Log.i(LOGTAG, "stopAd");
  stopAdTracking();
}

/** Returns current volume as a percent of max volume. */
@Override
public int getVolume() {
  return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
      / audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
}

7. Настройте отслеживание рекламы

Для регистрации событий рекламы необходимо вызывать VideoAdPlayerCallback.onAdProgress по мере продвижения контента и рекламы. Для этого настройте таймер для вызова onAdProgress() с заданным интервалом.

private void startAdTracking() {
  Log.i(LOGTAG, "startAdTracking");
  if (timer != null) {
    return;
  }
  timer = new Timer();
  TimerTask updateTimerTask =
      new TimerTask() {
        @Override
        public void run() {
          VideoProgressUpdate progressUpdate = getAdProgress();
          notifyImaSdkAboutAdProgress(progressUpdate);
        }
      };
  timer.schedule(updateTimerTask, POLLING_TIME_MS, INITIAL_DELAY_MS);
}

private void notifyImaSdkAboutAdEnded() {
  Log.i(LOGTAG, "notifyImaSdkAboutAdEnded");
  savedAdPosition = 0;
  for (VideoAdPlayer.VideoAdPlayerCallback callback : videoAdPlayerCallbacks) {
    callback.onEnded(loadedAdMediaInfo);
  }
}

private void notifyImaSdkAboutAdProgress(VideoProgressUpdate adProgress) {
  for (VideoAdPlayer.VideoAdPlayerCallback callback : videoAdPlayerCallbacks) {
    callback.onAdProgress(loadedAdMediaInfo, adProgress);
  }
}

/**
 * @param errorType Media player's error type as defined at
 *     https://cs.android.com/android/platform/superproject/+/master:frameworks/base/media/java/android/media/MediaPlayer.java;l=4335
 * @return True to stop the current ad playback.
 */
private boolean notifyImaSdkAboutAdError(int errorType) {
  Log.i(LOGTAG, "notifyImaSdkAboutAdError");

  switch (errorType) {
    case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
      Log.e(LOGTAG, "notifyImaSdkAboutAdError: MEDIA_ERROR_UNSUPPORTED");
      break;
    case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
      Log.e(LOGTAG, "notifyImaSdkAboutAdError: MEDIA_ERROR_TIMED_OUT");
      break;
    default:
      break;
  }
  for (VideoAdPlayer.VideoAdPlayerCallback callback : videoAdPlayerCallbacks) {
    callback.onError(loadedAdMediaInfo);
  }
  return true;
}

public void notifyImaOnContentCompleted() {
  Log.i(LOGTAG, "notifyImaOnContentCompleted");
  for (VideoAdPlayer.VideoAdPlayerCallback callback : videoAdPlayerCallbacks) {
    callback.onContentComplete();
  }
}

private void stopAdTracking() {
  Log.i(LOGTAG, "stopAdTracking");
  if (timer != null) {
    timer.cancel();
    timer = null;
  }
}

@Override
public VideoProgressUpdate getAdProgress() {
  long adPosition = videoPlayer.getCurrentPosition();
  return new VideoProgressUpdate(adPosition, adDuration);
}

8. Инициируйте IMA в методе onCreate

Перепишите метод onCreate и добавьте необходимые назначения переменных для запуска IMA. На этом этапе создайте экземпляры следующих объектов:

  • ImaSdkSettings
  • AdsLoader
  • VideoAdPlayerAdapter
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_my);

  // Initialize the IMA SDK as early as possible when the app starts. If your app already
  // overrides Application.onCreate(), call this method inside the onCreate() method.
  // https://developer.android.com/topic/performance/vitals/launch-time#app-creation
  sdkFactory = ImaSdkFactory.getInstance();
  sdkFactory.initialize(this, getImaSdkSettings());

  // Create the UI for controlling the video view.
  mediaController = new MediaController(this);
  videoPlayer = findViewById(R.id.videoView);
  mediaController.setAnchorView(videoPlayer);
  videoPlayer.setMediaController(mediaController);

  // Create an ad display container that uses a ViewGroup to listen to taps.
  AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  videoAdPlayerAdapter = new VideoAdPlayerAdapter(videoPlayer, audioManager);

  AdDisplayContainer adDisplayContainer =
      ImaSdkFactory.createAdDisplayContainer(
          findViewById(R.id.videoPlayerContainer), videoAdPlayerAdapter);

  // Create an AdsLoader.
  adsLoader = sdkFactory.createAdsLoader(this, getImaSdkSettings(), adDisplayContainer);

Настройте кнопку воспроизведения для запроса рекламы, а затем скрывайте ее при нажатии:

// When the play button is clicked, request ads and hide the button.
View playButton = findViewById(R.id.playButton);
playButton.setOnClickListener(
    view -> {
      videoPlayer.setVideoPath(SAMPLE_VIDEO_URL);
      requestAds(SAMPLE_VAST_TAG_URL);
      view.setVisibility(View.GONE);
    });
Наконец, добавьте вспомогательный метод для получения ImaSdkSettings :
private ImaSdkSettings getImaSdkSettings() {
  if (imaSdkSettings == null) {
    imaSdkSettings = ImaSdkFactory.getInstance().createImaSdkSettings();
    // Set any IMA SDK settings here.
  }
  return imaSdkSettings;
}

9. Добавьте прослушиватели AdsLoader

Добавьте прослушиватели для addAdErrorListener и addAdsLoadedListener . В AdsLoadedListener создайте AdsManager и настройте прослушиватель ошибок AdsManager :

// Add listeners for when ads are loaded and for errors.
adsLoader.addAdErrorListener(
    new AdErrorEvent.AdErrorListener() {
      /** An event raised when there is an error loading or playing ads. */
      @Override
      public void onAdError(AdErrorEvent adErrorEvent) {
        Log.i(LOGTAG, "Ad Error: " + adErrorEvent.getError().getMessage());
        resumeContent();
      }
    });
adsLoader.addAdsLoadedListener(
    adsManagerLoadedEvent -> {
      // Ads were successfully loaded, so get the AdsManager instance. AdsManager has
      // events for ad playback and errors.
      adsManager = adsManagerLoadedEvent.getAdsManager();

      // Attach event and error event listeners.
      adsManager.addAdErrorListener(
          new AdErrorEvent.AdErrorListener() {
            /** An event raised when there is an error loading or playing ads. */
            @Override
            public void onAdError(AdErrorEvent adErrorEvent) {
              Log.e(LOGTAG, "Ad Error: " + adErrorEvent.getError().getMessage());
              String universalAdIds =
                  Arrays.toString(adsManager.getCurrentAd().getUniversalAdIds());
              Log.i(
                  LOGTAG,
                  "Discarding the current ad break with universal "
                      + "ad Ids: "
                      + universalAdIds);
              adsManager.discardAdBreak();
            }
          });

10. Обработка событий рекламы IMA

Отслеживайте события рекламы IMA с помощью AdsManager.addAdEventListener . Используя оператор switch, настройте действия для следующих событий IMA:

Фрагмент кода содержит комментарии с дополнительной информацией об использовании событий. После настройки событий вызовите AdsManager.init() :

  adsManager.addAdEventListener(
      new AdEvent.AdEventListener() {
        /** Responds to AdEvents. */
        @Override
        public void onAdEvent(AdEvent adEvent) {
          if (adEvent.getType() != AdEvent.AdEventType.AD_PROGRESS) {
            Log.i(LOGTAG, "Event: " + adEvent.getType());
          }
          // These are the suggested event types to handle. For full list of
          // all ad event types, see AdEvent.AdEventType documentation.
          switch (adEvent.getType()) {
            case LOADED ->
                // AdEventType.LOADED is fired when ads are ready to play.
                // This sample app uses the sample tag
                // single_preroll_skippable_ad_tag_url that requires calling
                // AdsManager.start() to start ad playback.
                // If you use a different ad tag URL that returns a VMAP or
                // an ad rules playlist, the adsManager.init() function will
                // trigger ad playback automatically and the IMA SDK will
                // ignore the adsManager.start().
                // It is safe to always call adsManager.start() in the
                // LOADED event.
                adsManager.start();
            case CONTENT_PAUSE_REQUESTED ->
                // AdEventType.CONTENT_PAUSE_REQUESTED is fired when you
                // should pause your content and start playing an ad.
                pauseContentForAds();
            case CONTENT_RESUME_REQUESTED ->
                // AdEventType.CONTENT_RESUME_REQUESTED is fired when the ad
                // you should play your content.
                resumeContent();
            case ALL_ADS_COMPLETED -> {
              // Calling adsManager.destroy() triggers the function
              // VideoAdPlayer.release().
              adsManager.destroy();
              adsManager = null;
            }
            case CLICKED -> {
              // When the user clicks on the Learn More button, the IMA SDK fires
              // this event, pauses the ad, and opens the ad's click-through URL.
              // When the user returns to the app, the IMA SDK calls the
              // VideoAdPlayer.playAd() function automatically.
            }
            default -> {}
          }
        }
      });
  AdsRenderingSettings adsRenderingSettings =
      ImaSdkFactory.getInstance().createAdsRenderingSettings();
  // Add any ads rendering settings here.
  // This init() only loads the UI rendering settings locally.
  adsManager.init(adsRenderingSettings);
});

11. Управление переключением между рекламой и контентом

В этом разделе создайте методы pauseContentForAds и resumeContent , упомянутые в предыдущих шагах. Эти методы будут повторно использовать плеер для воспроизведения как контента, так и рекламы. Вам потребуется отслеживать положение контента, чтобы возобновить воспроизведение после рекламной паузы.

private void pauseContentForAds() {
  Log.i(LOGTAG, "pauseContentForAds");
  savedPosition = videoPlayer.getCurrentPosition();
  videoPlayer.stopPlayback();
  // Hide the buttons and seek bar controlling the video view.
  videoPlayer.setMediaController(null);
}

private void resumeContent() {
  Log.i(LOGTAG, "resumeContent");

  // Show the buttons and seek bar controlling the video view.
  videoPlayer.setVideoPath(SAMPLE_VIDEO_URL);
  videoPlayer.setMediaController(mediaController);
  videoPlayer.setOnPreparedListener(
      mediaPlayer -> {
        if (savedPosition > 0) {
          mediaPlayer.seekTo(savedPosition);
        }
        mediaPlayer.start();
      });
  videoPlayer.setOnCompletionListener(
      mediaPlayer -> videoAdPlayerAdapter.notifyImaOnContentCompleted());
}

12. Запрос рекламы

Теперь добавьте метод requestAds для создания AdsRequest и используйте его для вызова AdsLoader.requestAds() :

private void requestAds(String adTagUrl) {
  // Create the ads request.
  AdsRequest request = sdkFactory.createAdsRequest();
  request.setAdTagUrl(adTagUrl);
  request.setContentProgressProvider(
      () -> {
        if (videoPlayer.getDuration() <= 0) {
          return VideoProgressUpdate.VIDEO_TIME_NOT_READY;
        }
        return new VideoProgressUpdate(
            videoPlayer.getCurrentPosition(), videoPlayer.getDuration());
      });

  // Request the ad. After the ad is loaded, onAdsManagerLoaded() will be called.
  adsLoader.requestAds(request);
}

Теперь вы успешно запрашиваете и показываете рекламу с помощью IMA SDK. Чтобы узнать о более продвинутых функциях, изучите другие руководства или примеры на GitHub .