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 />
组件。
可能的解决方案:添加控制器或将声音绑定到播放按钮上(后者可能不是最好的)。
当我在 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 />
组件。
可能的解决方案:添加控制器或将声音绑定到播放按钮上(后者可能不是最好的)。