avatar
morethan-log

iOS 저전력 모드에서 safari 비디오 자동재생 되지 않는 이슈 대응하기

iOS 저전력모드에서 비디오가 자동재생 되지 않는 경우에 대한 생각과 여러 해결방안을 공유합니다.
safariReactios
23 days ago
·
6 min read

웹뷰 페이지를 만들다보면 종종 비디오를 배경으로 사용하는 경우들이 존재했었다.

그런 경우 보통 비디오를 absolute로 뒤에 깔아주고, 그 위에 컨텐츠를 표시하는 방식으로 구현하곤 했었다. (아래는 예시코드입니다.)

const Header: FC = () => {
  return (
    <section css={wrapperStyle}>
      <video
        css={backgroundStyle}
        autoPlay
        src={headerBg}
        poster={headerBgPoster}
        playsInline
        muted
      />
      <div css={contentStyle}>
        {/* 컨텐츠 영역 */}
      </div>
    </section>
  );
};

export default Header;

const backgroundStyle = css`
  position: absolute;
  inset: 0;
  z-index: -1;

  width: 100%;
  height: 100%;

  object-fit: cover;
  object-position: center;
`;

실제 크롬에서도 정상동작하고 모바일기기에서 테스트했을 때에도 잘 동작해서 아무런 문제가 없을 줄 알았다.

문제 상황

...하지만 iOS기기에서 저전력모드가 활성화 되어있는 경우 배터리 소모에 영향을 줄수 있는 이유로 비디오 자동재생을 막아두었다.

때문에 비디오는 자동재생되지 않고 재생버튼을 표시하게 되는데, 이때 뒷배경에 비디오를 깔아두게 되면 재생버튼을 누를 수도 없는 상황이 발생하게 되었다.

2377

해결방안

위 이슈를 대응하면서 고민했던 여러 해결방안을 정리해보려고한다. 이 글을 보고 계신분들도 상황에 맞는 적절한 방법으로 해결하길 바란다.

강제로 자동재생 시키기

우선 iOS 정책을 우회할 수 있는 방법이 있는지 찾아보았다.

여러 방법을 찾아본 결과, 컨텐츠가 렌더링 되자마자 아무런 인터렉션도 없이 자동재생하도록 우회하는것은 불가능하다는 결론이였다.

또한 이러한 방법이 가능하더라도 저전력 모드 유저에게 비디오를 강제로 재생하는 방법이 좋은 경험일지도 충분히 고려해봐야 할 것이다.

비디오 대신 GIF, lottie 등으로 변경하기

위 케이스에서는 많은 용량을 차지하고있는 에셋이여서 패스했다. 하지만 이런 방법도 상황에 따라 나쁘지 않은 방법이니 한번 고려해보는것도 나쁘지 않을 것이다.

유저가 클릭하면 재생할 수 있도록 대응하기

위 케이스에서도 css를 수정하여 비디오를 클릭해 재생할 수 있도록 수정할 수 있지만, 배경 이미지 처럼 동작하기를 기대했던 영역을 클릭해서 재생하는 것은 기획자의 의도에 맞지도 않고, 유저 경험도 어색할 것이라고 생각했다.

배경으로서 역할을 하는 비디오 컨텐츠가 아니라면 가장 저전력모드의 의도에 맞는 방법일 것이다.

저전력 모드인 경우, 비디오 대신 이미지로 대체하기

배경의 역할을 하는것이니, 재생할 수 없는 환경인 경우에는 이미지로 대체할 수 있도록 대응하는 방법이다.

실제로 재생이 가능한지를 확인하는 방법은 다양하겠지만, 우선 비디오 뒤에 동일한 이미지를 깔아두고 비디오가 재생을 트리거 했을 때, 재생이 불가능한 환경인 경우 에러를 뱉는걸을 활용해 이미지를 표시할 수 있도록 display: none 으로 변경해주었다.

const Header: FC = () => {

  return (
    <section css={wrapperStyle}>
      <img css={backgroundStyle} src={headerBgPoster} />
      <video
        ref={(el) => {
          void el?.play().catch(() => {
            el.style.display = "none";
          });
        }}
        css={backgroundStyle}
        autoPlay
        src={headerBg}
        poster={headerBgPoster}
        playsInline
        muted
      />
      <div css={contentStyle}>
        {/* 컨텐츠 영역 */}
      </div>
    </section>
  );
};

export default Header;

const backgroundStyle = css`
  position: absolute;
  inset: 0;
  z-index: -1;

  width: 100%;
  height: 100%;

  object-fit: cover;
  object-position: center;
`;

이제 아래사진처럼 이미지로 대체할 수 있게 되었다.

2378

이런 이슈를 대응하는 것에 정답은 없지만, 유저의 경험을 해치지 않으면서 기획의 의도를 잘 지킬 수 있는 방법을 항상 고민하고 생각해봐야겠다고 느꼈다.

이글을 보고 계신 분들에게도 도움이 되었으면 좋겠습니다. 감사합니다!


- 컬렉션 아티클






몰댄민입니다