Can't play video on iOS in Safari: NotAllowedError: The request is not allowed by the user agent or the platform in the current context

Can't play video on iOS in Safari: NotAllowedError: The request is not allowed by the user agent or the platform in the current context

当我在 Safari 中单击 iPhone 上的播放按钮时,出现以下错误:

NotAllowedError: 当前上下文中的用户代理或平台不允许请求,可能是因为用户拒绝了权限。

上网查了下好像这个问题很久了,但是一直没有明确的解决办法

这是我的代码。它适用于除 iOS Safari 之外的任何地方。

import { Box } from '@chakra-ui/react';
import { useTranslation } from 'libs/i18next';
import React, { useEffect, useRef, useState } from 'react';
import { PauseIcon, PlayIcon } from 'theme/icons';
import { visuallyHiddenCss } from 'utils/style-utils';

import {
  buttonHoverArea,
  playButtonCss,
  playIconStyles,
  videoContainerCss,
  videoCss,
} from './Video.styles';

export interface Video extends React.HTMLProps<HTMLVideoElement> {
  src: string;
  noVideoText?: string;
  className?: string;
  isEnabled?: boolean;
  coversParent?: boolean;
  handlePlayPress?: (videoPlaying: boolean) => void;
}

/**
 * Default HTML5 video player with a play button and a preview thumbnail image.
 */
export const Video = ({
  src,
  noVideoText,
  className,
  loop = false,
  autoPlay = false, // AutoPlay doesn't work currently
  isEnabled = true,
  coversParent = false,
  handlePlayPress,
  ...props
}: Video): React.ReactElement => {
  const [t] = useTranslation(['common']);
  const videoRef = useRef<HTMLVideoElement>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  // use videoStarted state to hide the play button once it has been started
  const [videoPlaying, setVideoPlaying] = useState<boolean>(false);

  const pauseVideo = () => {
    setVideoPlaying(false);
  };

  const toggleVideo = () => {
    if (handlePlayPress) {
      handlePlayPress(!videoPlaying);
    }
    setVideoPlaying(!videoPlaying);
  };

  const defaultProps: Partial<Video> = {
    width: '100%',
    height: '100%',
    preload: 'none',
    onClick: pauseVideo,
    tabIndex: -1,
  };
  const videoProps = Object.assign(defaultProps, props);

  useEffect(() => {
    if (videoRef.current && props.muted) {
      // force muted prop
      // https://github.com/facebook/react/issues/10389#issuecomment-605689475
      videoRef.current.setAttribute('muted', '');
      videoRef.current.defaultMuted = true;
    }
  }, [props.muted, videoRef]);

  useEffect(() => {
    if (isEnabled && videoPlaying) {
      videoRef.current?.play();
      buttonRef.current?.blur();
      videoRef.current?.focus();
    } else {
      videoRef.current?.pause();
    }
  }, [isEnabled, videoPlaying, videoRef]);

  const PlayPauseIcon = videoPlaying ? PauseIcon : PlayIcon;

  return (
    <Box
      css={[
        videoContainerCss.base,
        coversParent ? videoContainerCss.cover : undefined,
      ]}
      className={className}
    >
      {/* eslint-disable-next-line jsx-a11y/media-has-caption */}
      <video
        ref={videoRef}
        css={videoCss}
        {...videoProps}
        autoPlay={autoPlay}
        loop={loop}
      >
        <source src={src} type={'video/mp4'} />
        {noVideoText}
      </video>
      {isEnabled && (
        <div
          css={[buttonHoverArea.base, videoPlaying && buttonHoverArea.playing]}
        >
          <button
            type="button"
            ref={buttonRef}
            css={playButtonCss}
            onClick={toggleVideo}
            // prevent hidden elements from being focused
          >
            <span css={visuallyHiddenCss}>
              {videoPlaying ? t('common:video.pause') : t('common:video.play')}
            </span>
            <PlayPauseIcon
              css={!videoPlaying && playIconStyles}
              boxSize={'6rem'}
              aria-hidden
            />
          </button>
        </div>
      )}
    </Box>
  );
};

如何避免这个错误?为什么会这样?

解决方案是向将传递到视频的组件添加静音 属性。不幸的是,它导致视频被静音。在我的例子中,我有 <HomePage /> 组件,我将静音传递给 <Video /> 组件。

可能的解决方案:添加控制器或将声音绑定到播放按钮上(后者可能不是最好的)。