使用 IMA SDK for Android 自定义广告播放

在 IMA v3.30.0 及更低版本中,IMA SDK 可以处理所有广告播放逻辑, 而应用专注于播放内容视频。这种方法称为 “SDK 自有广告播放”。

如果您希望在视频播放器中播放广告,请使用 SDK 并为此提供了一个接口我们将此方法称为“自定义 广告播放”本指南的其余部分会介绍具体的实现方法

前提条件

  • 基本的 IMA 集成。

我们建议您参阅 高级示例 如果您还没有基本的 IMA 集成。此示例已实现了自定义广告播放。剩余部分 本指南将会介绍通过 Google Cloud 控制台自定义广告播放 IMA 广告。

VideoAdPlayer 接口

自定义广告播放要求您的应用实现 VideoAdPlayer 界面。SDK 使用此接口通知您的应用播放广告 视频。您的应用还会使用此接口向 SDK 告知主要视频广告 事件。请按照以下步骤实现该接口。

创建 VideoAdPlayer

第一步是创建一个匿名 VideoAdPlayer 类 在 requestAds() 中:

private VideoAdPlayer videoAdPlayer;
...

private void requestAds(String adTagUrl) {
    videoAdPlayer = new VideoAdPlayer() {
    };
}

添加视频方法

接下来,添加指示视频播放器播放、加载、停止和暂停广告的方法 视频。我们还在此处添加了释放播放器并获取音量的方法:

videoAdPlayer = new VideoAdPlayer() {
        @Override
        public void playAd() {
            if (mIsAdDisplayed) {
                videoPlayer.resume();
            } else {
                isAdDisplayed = true;
                videoPlayer.play();
            }
        }

        @Override
        public void loadAd(String url) {
            isAdDisplayed = true;
            videoPlayer.setVideoPath(url);
        }
        @Override
        public void stopAd() {
            videoPlayer.stopPlayback();
        }
        @Override
        public void pauseAd() {
            videoPlayer.pause();
        }

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

        @Override
        public int getVolume() {
            return videoPlayer.getVolume();
        }
};

这些方法是视频播放器自身类似于 方法。请注意,这些方法会设置一个内部变量 来跟踪广告是否展示。在自定义广告播放中, 视频播放器会同时播放内容视频和视频广告,因此您需要确保 当前显示的曲目

广告播放进度

VideoAdPlayer 接口实现了另一个接口, AdProgressProvider,因此您还必须实现它。它只有 一种方法,即 getAdProgress(),SDK 使用该方法来获取 。将其添加到您的匿名 VideoAdPlayer 类放在其他方法之后:

VideoAdPlayer videoAdPlayer = new VideoAdPlayer() {
        ...
        @Override
        public VideoProgressUpdate getAdProgress() {
            if (!isAdDisplayed || videoPlayer.getDuration() <= 0) {
                return VideoProgressUpdate.VIDEO_TIME_NOT_READY;
            }
            return new VideoProgressUpdate(videoPlayer.getCurrentPosition(),
                    videoPlayer.getDuration());
        }
};

getAdProgress() 会返回一个 VideoProgressUpdate 类型,该类型 必须包含视频的当前位置和时长。如果播放器 未播放广告,或广告时长不可用,请将其返回 VideoProgressUpdate.VIDEO_TIME_NOT_READY,如示例中所示。

管理视频回调

自定义广告播放要求您的应用向 SDK 告知主要 视频事件。从 SDK 的角度来看,这些是 由 VideoAdPlayer.VideoAdPlayerCallback 接口描述。 在进入回调方法本身之前,您需要 能够应 SDK 的请求添加和移除回调。这是 使用 addCallback()removeCallback()VideoAdPlayer 中完成以下操作:

private List<VideoAdPlayerCallback> adCallbacks = new ArrayList<>(1);

VideoAdPlayer videoAdPlayer = new VideoAdPlayer() {
        ...
        @Override
        public void addCallback(VideoAdPlayerCallback videoAdPlayerCallback) {
            adCallbacks.add(videoAdPlayerCallback);
        }

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

此实现为要调用的回调使用 List<> List<>.add()remove() 方法。

调用回调

现在,SDK 已经可以指示应用添加和移除回调, 定义调用回调的位置。您的应用需要调用 在发生主要视频事件(例如播放、暂停)时, 或继续播放视频,或者视频完整播放或出错时。

为此,请展开 SampleVideoPlayer 以获取这些对象的监听器 从 VideoFragment 添加的视频事件。让 在 SampleVideoPlayer 中使用单独的监听器来调用这些广告回调 因为SampleVideoPlayer对广告一无所知, 因此您必须将其视频事件转发到可以处理广告的设备。

public interface OnVideoEventsListener {
    void onPlay();
    void onResume();
    void onPause();
    void onError();
}

private final List<OnVideoEventsListener> onVideoEventsListeners = new ArrayList<>(1);

public void addVideoEventsListener(OnVideoEventsListener listener) {
    onVideoEventsListeners.add(listener);
}

启动、暂停和恢复

创建新的枚举以跟踪播放状态并添加新的替换项 对于 SampleVideoPlayer 中的 start()pause() 方法:

private enum PlaybackState {
    STOPPED, PAUSED, PLAYING
}

private PlaybackState playbackState = PlaybackState.STOPPED;

@Override
public void start() {
    super.start();
    switch (playbackState) {
        case STOPPED:
            for (OnVideoEventsListener listener : onVideoEventsListeners) {
                listener.onPlay();
            }
            break;
        case PAUSED:
            for (OnVideoEventsListener listener : onVideoEventsListeners) {
                listener.onResume();
            }
            break;
        default:
            // Already playing; do nothing.
            break;
    }
    playbackState = PlaybackState.PLAYING;
}

@Override
public void pause() {
    super.pause();
    playbackState = PlaybackState.PAUSED;
    for (OnVideoEventsListener listener : onVideoEventsListeners) {
        listener.onPause();
    }
}

处理错误

替换您在 init() 中设置的视频播放器匿名错误监听器:

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
    playbackState = PlaybackState.STOPPED;
    for (OnVideoEventsListener listener : onVideoEventsListeners) {
        listener.onError();
    }

    // Returning true signals to MediaPlayer that the error was handled.
    // This  prevents the completion handler from being called.
    return true;
}

实现监听器

返回 VideoFragment 并添加匿名 OnVideoEventsListener 添加到您的 SampleVideoPlayer 实例:

mVideoPlayer.addVideoEventsListener(new OnVideoEventsListener() {
    @Override
    public void onPlay() {
        if (isAdDisplayed) {
            for (VideoAdPlayerCallback callback : adCallbacks) {
                callback.onPlay();
            }
        }
    }

    @Override
    public void onResume() {
        if (isAdDisplayed) {
            for (VideoAdPlayerCallback callback : adCallbacks) {
                callback.onResume();
            }
        }
    }

    @Override
    public void onPause() {
        if (isAdDisplayed) {
            for (VideoAdPlayerCallback callback : adCallbacks) {
                callback.onPause();
            }
        }
    }

    @Override
    public void onError() {
        if (isAdDisplayed) {
            for (VideoAdPlayerCallback callback : adCallbacks) {
                callback.onError();
            }
        }
    }
});

更改 OnVideoCompletedListeneronVideoCompleted() 方法 来处理广告视频完整播放的情况:

public void onVideoCompleted() {
    // Handle completed event for playing post-rolls.
    if (isAdDisplayed) {
        for (VideoAdPlayerCallback callback : adCallbacks) {
            callback.onEnded();
        }
    } else {
        if (adsLoader != null) {
            adsLoader.contentComplete();
    }
}

在内容和广告之间切换

此示例使用同一个视频播放器实例来同时播放 因此您需要添加一些逻辑 内容和广告。然后,您可以重新加载 内容视频返回到广告开始播放的位置。添加两项 函数:

private int savedContentPosition = 0;

private void pauseContent() {
    savedContentPosition = videoPlayer.getCurrentPosition();
    videoPlayer.stopPlayback();
    isAdDisplayed = true;
}

private void resumeContent() {
    videoPlayer.setVideoPath(getString(R.string.content_url));
    videoPlayer.seekTo(mSavedContentPosition);
    videoPlayer.play();
    isAdDisplayed = false;
}

CONTENT_PAUSE_REQUESTED 和 在以下位置收到了 CONTENT_RESUME_REQUESTED 个事件: VideoFragment.onAdEvent()

case CONTENT_PAUSE_REQUESTED:
    pauseContent();
    break;
case CONTENT_RESUME_REQUESTED:
    resumeContent();
    break;

启用自定义广告播放功能

最后一步是告知 SDK 您要使用自定义广告播放功能。 为此,请将 VideoAdPlayer 传递给 AdDisplayContainer

adDisplayContainer.setPlayer(videoAdPlayer);

有必要将播放器传递给 setPlayer()。否则, SDK 使用 SDK 拥有的播放机制。

大功告成。以上就是将自定义广告播放添加到 IMA 实现。您可以将自己的实现与 高级示例