googleads / videojs-ima

IMA SDK Plugin for Video.js
Apache License 2.0
450 stars 284 forks source link

Can't get Ads properly work on Safari for iOS #1010

Closed ing-norante closed 3 years ago

ing-norante commented 3 years ago

Hello, I'm trying to use the videojs player in a React-based (NextJS) project. I need to serve pre-roll Ads through Google Ad Manager and the Ads are working on desktop and for Androids but aren't for Safari on Apple's mobile devices.

This is the React Video Component:


import "video.js/dist/video-js.css";
import { useCallback, useEffect, useState } from "react";
import videojs from "video.js";
import "videojs-youtube";
import "@videojs/themes/dist/sea/index.css";
import "@devmobiliza/videojs-vimeo/dist/videojs-vimeo.cjs";
import "videojs-contrib-ads";
import "videojs-ima";
import "videojs-ima/dist/videojs.ima.css";

export default function VideoPlayer(props) {
  const [videoEl, setVideoEl] = useState(null);
  const onVideo = useCallback((el) => {
    setVideoEl(el);
  }, []);

  useEffect(() => {
    if (videoEl == null) return;
    const player = videojs(videoEl, props);
    var imaOptions = {
      id: "content_video",
      disableCustomPlaybackForIOS10Plus: true,
      adTagUrl: process.env.NEXT_PUBLIC_IMA_AD_TAG_URL,
    };
    player.ima(imaOptions);

    // Remove controls from the player on iPad to stop native controls from stealing
    // our click
    var contentPlayer = document.getElementById("content_video_youtube_api");
    if (
      (navigator.userAgent.match(/iPad/i) ||
        navigator.userAgent.match(/Android/i)) &&
      contentPlayer.hasAttribute("controls")
    ) {
      contentPlayer.removeAttribute("controls");
    }

    // Initialize the ad container when the video player is clicked, but only the
    // first time it's clicked.
    var initAdDisplayContainer = function () {
      player.ima.initializeAdDisplayContainer();
      wrapperDiv.removeEventListener(startEvent, initAdDisplayContainer);
    };

    var startEvent = "click";
    if (
      navigator.userAgent.match(/iPhone/i) ||
      navigator.userAgent.match(/iPad/i) ||
      navigator.userAgent.match(/Android/i)
    ) {
      startEvent = "touchend";
    }

    var wrapperDiv = document.getElementById("content_video");
    wrapperDiv.addEventListener(startEvent, initAdDisplayContainer);

    return () => {
      player.dispose();
    };
  }, [props, videoEl]);

  return (
    <>
      <div className="space--both-4">
        <div className="article-layout__figure--extra-wrap">
          <div data-vjs-player>
            <video
              id="content_video"
              ref={onVideo}
              className="video-js vjs-theme-sea"
              playsInline
            />
          </div>
        </div>
        <div className="wrap">
          <div className="figure-caption">{props.sectionTitle}</div>
        </div>
      </div>
    </>
  );
}

Please note that process.env.NEXT_PUBLIC_IMA_AD_TAG_URL is an env variable that contains a valid VAST URL generated from the Ad Manager.

This is the section of the page I'm loading the React video component from:

const videoJsOptions = {
  aspectRatio: "16:9",
  height: block.video.height,
  width: block.video.width,
  responsive: true,
  fluid: true,
  techOrder: ["html5", block.video.provider],
  autoplay: false,
  controls: true,
  sources: [
    {
      src: block.video.url,
      type: block.video.mimeType
        ? block.video.mimeType
        : `video/${block.video.provider}`,
    },
  ],
};
<VideoPlayer key={block.id} sectionTitle={block.title} {...videoJsOptions} />;

Please note that this block is an object that comes from the CMS and it hosts a video with its options such as width, height, url, mimeType, etc..

As seen on other issues and comments I've already tried adding disableCustomPlaybackForIOS10Plus: true to the imaOptions hash, my html player has the playsInline attribute and I'm manually calling player.ima.initializeAdDisplayContainer() as the repo examples.

When I try starting the video on an iPhone (iOS 14 Safari) it hangs with this kind of strange video embedded one into the other... see screenshot below:

Schermata 2021-09-13 alle 18 47 01 1

Any help would be super appreciated because I'm really stuck here.

Thanks!

damjan25 commented 3 years ago

Did you try to trigger player.ima.initializeAdDisplayContainer() asynchronously ? :) This might help, I remember I had problems where if I triggered play() or resume() on IOS it would crash the whole player and making it async fixed the issue.

Also try to test on real device (real iphone) because the safari responsive design emulator is weird (I can not see any ads there either, not sure if just videojs-ima does not work there or what :thinking:, but works perfectly on browserstack iphone)

Summary:

Kiro705 commented 3 years ago

Hello @ing-norante ,

We have seen some issue in the past related to React. IMA does not support moving the video player in the DOM after IMA has been initiated. My recommendation would be to ensure all restructuring of the DOM is complete before initiating IMA. There may also be more information on React help forums related to the best way to handle this situation.

Thank you, Jackson IMA SDK team