可以在Safari中的iOS上播放视频:NotalloedError:在当前上下文中,用户代理不允许请求

发布于 2025-02-01 19:26:32 字数 3874 浏览 2 评论 0原文

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

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

我在Internet上进行了搜索,似乎这个问题已经存在很长时间了,但是没有明确的解决方案。

这是我的代码。除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>
  );
};

如何避免此错误?为什么会发生?

When I click a play button on an iPhone in Safari, I get the following error:

NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.

I searched on the internet and it seems that this issue has been around for a long time but there is no clear solution to it.

Here is my code. It works everywhere except 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>
  );
};

How can I avoid this error? And why is it happening?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧人哭 2025-02-08 19:26:32

您需要在视频上设置PlayaySinline才能使其在iPhone上工作。

例如,在videoref.current.setAttribute('muted',''');::::

 videoRef.current.playsInline = true;

You need to set the playsinline on video to be true for it to work on iPhone.

e.g. add below line after videoRef.current.setAttribute('muted', ''); :

 videoRef.current.playsInline = true;
小情绪 2025-02-08 19:26:32

解决方案是将静态属性添加到将传递到视频的组件中。不幸的是,这导致视频被静音。就我而言,我拥有&lt; homepage /&gt; < /code>组件,然后将其传递给&lt; video /&gt; < /code> component。

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

The solution was to add muted property to the component which will be passed down to the video. Unfortunately it resulted in video being muted. In my case, I had <HomePage /> component and I passed muted down to the <Video /> component.

Possible solutions: add controllers or bind sound onto the play button (the latter might be not the best one).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文