Detect if ios11 device is in low power mode to prevent bad UX on normally correctly autoplaying video
Asked Answered
M

5

8

I am running into a huge issue with autoplaying videos on iOS11 devices (at least tested on iphone 7 ios 11.2.5 safari ).

When the change in policy about autoplaying videos arrived, our autoplaying videos stopped working. Our app heavily depend on videos.

We deeply changed all the steps for users to interact with videos to make sure they're not blocked and they're now muted by default and autoplay is triggered after user gesture. so videos DO autoplay muted and we thought we were doing after already days of work.

But there's an issue: Last week, I was testing on my girklfriend 11.2 iphone the website and boum...videos were blocked. I did not understand why... Found out the reason was... I was using her phone while it was charging the battery!

Indeed on ios11, when you put to charge the phone, it automatically gets in "low power mode" hehe...thus blocking autoplay videos. If you go into Settings > itune & apple store and go to the "autoplay video" setting you'll see (while it's charging in low power mode) :

"autoplay video are not available while low power mode is on"....

So basically thousands of users across the world who will connect to our website while charging will have a broken experience and no video loading ! (we rely heavily on autoplaying videos even if muted before user activates the sound)

How can we detect this and at least give an explainer message to user in that case such as "our videos can't be played while low power mode (or charging your phone).

I understand apple thrives to protect users form autoplay bad experience but here we made all the efforts to change our codebase to comply with their new policies but we see nowhere in their documentation how our web app (javascript) can detect the low power mode 'or the phone charging status). It's not fair: if they change the behavior in certain cases such as low power mode, they should play by their own rule and let us create a compliant but quality experience by letting us detect this device status. So that we could have a sort of plan B or fallback for users.

Any idea how to detect that an iphone is charging or in low power mode in javascript for a web app ? or how to deal with this ?

Musical answered 17/5, 2018 at 21:41 Comment(1)
I have answered a solution to this issue here: #43570960Honegger
M
4

Came across this too, and found that iOS uses the suspend event (https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/suspend_event) on low-power-mode. This event actually occurs after the video has loaded the few frames and emmited some on load events.

Using this suspend event we're able to show a fallback UI. For safe measure we can revert this UI if the video ever plays again, say on user interaction.

const videoElement = document.getElementById('myVideo');

videoElement.addEventListener('suspend', () => {
  // suspended loading. Show play UI (or fallback image)..
});

videoElement.addEventListener('play', () => {
  // remove play UI
});
Moria answered 4/7, 2020 at 1:11 Comment(1)
this is always called in chrome browsers, happens to videos that are cached in the browser.Debit
K
1

I think the settings property you mentioned only applies to video previews in the App Store, not to any WebViews. In fact, I've tried this W3 Demo on my phone right now and it autoplays fine if I add either muted or inline to the video tag. (So it would look like this: <video width="320" height="240" controls autoplay muted inline>).

Note: My phone is currently at 17%, it works whether I'm charging or not, and Low Power Mode seems to have no influence either. I'm on iOS 11.4 Beta.

What's important are these additional tags which are documented in this WebKit Blogpost.

Ku answered 17/5, 2018 at 22:11 Comment(15)
That's weird: here with youtube videos (that's what we use and they do have autoplay, and playsinline too), it's working when NOt in lower power mode, and not working when in low power mode. Other people experienced the same thing: #47655577 or #43570960Musical
thanks for the webkit link , this is our "basic" guide when we made our codebase changes. but nothing aboiut low battery mode on it. We do respect all those new policies and before changing our codebase, the new policies were blocking our autoplay videos but now they're working. at least in NOT low power mode:)Musical
my tests were on ios 11.2 ...maybe they fixed it in 11.4 beta:)Musical
I am trying to find a public url to test and maybe give you so we can compare. btw i am testing on safari, not chrome.Musical
On second note, when loading this link with Low Power Mode enabled, the first moving image does not, in fact, autoplay.Ku
here's a link to test: radiantmediaplayer.com/docs/latest/gist/muted-autoplay. on my iphone ios 11.2.5 safari, when not low power mode, it autoplays; when low power mode is on, it does not.Musical
Yes, I can now see your problem as well. However, I think your assumption that LPM will be enabled automatically while charging is not true. It has to be activated by a user, either through the control center or through the low battery alerts which are presented at 20% and 10%. It will then be automatically disabled when the battery reaches 80% of charge.Ku
Agreed but still it is suggested by the phone and non techie like my friend always accept. that's a lot of user-charging time if I may say where people will see a broken experience. I just wish that I could show a fallback/explainer mesage in that case. Especially as we use youtube Hide Controls wo they won't see any indication that there is a video actually if it does not autoplayMusical
Also what about people choosing on purpose "block autoplay videos" in ios11, shouldn't we be able to knwo they chose this setting to adjust the experience and the codebase and provide a explainer message?Musical
Interesting read and experiments: radiantmediaplayer.com/docs/latest/autoplay-support.html. Especially "According to our testing when an iOS 11+ device is in low power mode autoplay even muted is forbidden by the OS"Musical
I see your case. But as far as I know there is no way of getting the info on charge or LPM from the system unless you're in a native app. And also, when in low power mode, from a user perspective, I would prefer the system not to autoplay videos.Ku
So probably an option would be to adjust the video playback controls to be more user-friendly for when there is no autoplay available. You mentioned you use Youtube controls, maybe you can adjust that somehow.Ku
sure, we don't want to. but given our specific context, users when in low pwoer mode should get at least an explainer message to tell them to remove low power mode to be able to fully get the full experience. if not they will see a very negative situation with no clear indication that there is a video that is stopped/not started. Just wanted to have a detection to give a explainer message, we did not want to force autostart for low power mode people.Musical
Here is the key: when you say "So probably an option would be to adjust the video playback controls to be more user-friendly for when there is no autoplay available" . the issue is we can't detect that in low power mode autoplay is not available. Usual javascript promises to test autoplay gives us a false positive for low-power mode users. It tells us autoplay work but in practice it won't be working.Musical
looking now how i could hack this by detecting some css side-effects low power mode has: such as #47930254. maybe these weird side effects on css when low power mode is on could help me detect it:) but this one in the SO link would force me to create another video element in the dom:(Musical
D
0

My strategy is to also have a backup image using the same aspect ratio of the video and placing them on top of each other (video on top of image) with some css grid magic. The page loads with the image visible and the video set to opacity: 0. My script listens for the video play event triggered by it's autoplay attribute and if heard, sets the video to opacity: 1 with a css opacity fade transition so it's not so abrupt.

I also make sure that the script will always listen to the load event by making the script inject the video into the DOM as opposed to rendering it directly through the html.

In low battery-modes or browser's that cannot autoplay, your users will only see the backup image.

  const $videos = document.querySelectorAll('.js-videos');

  if ($videos.length) {
    $videos.forEach(function($video) {
      const $videoContainer = $video.parentElement;
      const videoUrl = $video.dataset.url;
      const videoType = $video.dataset.type;
      // poster is never seen but adding it just in case
      const videoPoster = $video.dataset.poster; 

      if (!videoUrl) { return; }

      let videoLoaded = false;

      const $videoEl = document.createElement('video');
      const $sourceEl = document.createElement('source');

      $sourceEl.src = videoUrl;
      $sourceEl.type = videoType;
      $videoEl.appendChild($sourceEl);

      $videoEl.autoplay = true;
      $videoEl.playsInline = true;
      $videoEl.controls = false;
      $videoEl.loop = true;
      $videoEl.muted = true;
      $videoEl.poster = videoPoster;

      const hideVideo = function() {
        $video.style.setProperty('display', 'none');
      }

      $videoEl.addEventListener('abort', hideVideo);
      $videoEl.addEventListener('error', hideVideo);

      // autoplay wasn't blocked by browser, show the video
      $videoEl.addEventListener('play', function() {
        if (!videoLoaded) {
          // video loaded changes opacity of video to 1
          $videoContainer.classList.add('video-loaded'); 
          videoLoaded = true;
        }
      });

      $video.appendChild($videoEl);
    });
  }

<div class="js-videos" data-url="{{ vid_url }}" data-type="{{ vid_type }}" data-poster="{{ img_url }}"></div>
Debit answered 23/2, 2023 at 17:55 Comment(0)
M
-1

This event handler can be used.

jwplayer().on('autostartNotAllowed')

Fired when the player is configured to autostart but the browser's settings are preventing it.

const videoElement = document.getElementById('myVideo');

videoElement.addEventListener('autostartNotAllowed', (e) => {
  console.log(e)
  // message: "The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission."
  // name: "NotAllowedError"
  // reason: "autoplayDisabled"
});

videoElement.addEventListener('play', () => {
  // remove play UI
});
Maragaret answered 19/7, 2020 at 23:4 Comment(0)
P
-2

I find the best option is just to simply convert the video into a gif using "" not that best solution in the world, but it works

Phillips answered 4/10, 2019 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.