تشغيل الإعلانات المخصّصة باستخدام حزمة تطوير البرامج لإعلانات الوسائط التفاعلية لنظام التشغيل Android

تتمثل الطريقة الأسرع والأكثر سهولة لدمج أداة تطوير البرامج لإعلانات الوسائط التفاعلية لنظام التشغيل Android في تطبيقك في جعل حزمة تطوير البرامج (SDK) تتعامل مع جميع منطق تشغيل الإعلان، في حين يركز التطبيق على تشغيل فيديو المحتوى. يُعرَف هذا الأسلوب باسم "تشغيل الإعلانات المملوك لحزمة SDK" وهو الخيار التلقائي في البدء.

ومع ذلك، إذا كنت تريد أيضًا عرض الإعلانات في مشغّل الفيديو، توفّر حزمة تطوير البرامج (SDK) واجهة لذلك. نشير إلى هذا المنهج باسم "تشغيل الإعلان المخصص" ونتناول بقية هذا الدليل في عملية تنفيذه.

المتطلبات الأساسية

  • وهو التكامل الأساسي لإعلانات الوسائط التفاعلية.

ننصحك بالاطّلاع على المثال المتقدم على github كنقطة بداية إذا لم تتوفّر لديك حاليًا عملية دمج أساسية لإعلانات الوسائط التفاعلية. ينفّذ هذا المثال حاليًا تشغيل إعلان مخصّصًا. سيوضّح الجزء المتبقي من هذا الدليل الميزات اللازمة لتشغيل الإعلان المخصّص باستخدام إعلانات الوسائط التفاعلية (IMA).

واجهة باستخدام VideoAdPlayer

ولتشغيل الإعلان المخصّص، يجب أن ينفّذ تطبيقك واجهة VideoAdPlayer. تستخدم حزمة تطوير البرامج (SDK) هذه الواجهة لإرسال إشعارات إلى تطبيقك لتشغيل الفيديوهات الإعلانية. يستخدم تطبيقك أيضًا هذه الواجهة لإبلاغ حزمة تطوير البرامج (SDK) بأحداث إعلانات الفيديو الرئيسية. اتّبِع الخطوات التالية لاستخدام الواجهة.

إنشاء مشغّل فيديو

تتمثل الخطوة الأولى في إنشاء صف 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. يتم ذلك داخل VideoAdPlayer باستخدام addCallback() وremoveCallback():

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);
}

تشغيل الجهاز وإيقافه مؤقتًا واستئناف تشغيله

يمكنك إنشاء تعداد جديد لتتبُّع حالة التشغيل وإضافة عمليات إلغاء جديدة للطريقتَين start() وpause() في SampleVideoPlayer:

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();
            }
        }
    }
});

غيِّر طريقة onVideoCompleted() في OnVideoCompletedListener للتعامل مع حالة انتهاء الفيديو الإعلاني:

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.

وهذا كل ما في الأمر. هذه هي كل الخطوات اللازمة لإضافة تشغيل إعلان مخصص إلى تنفيذ إعلانات الوسائط التفاعلية. يمكنك مقارنة عملية التنفيذ التي تجريها باستخدام المثال المتقدم على github إذا واجهتك مشكلة.