vpe-react-native
v2.1.2
Published
VPE React Native SDK for Expo
Readme
VPE React Native SDK V2 for EXPO
React Native를 지원하는 크로스플랫폼 비디오 플레이어 SDK. JSON 레이아웃, 스트리밍 프로토콜, 반응형 디자인을 지원합니다.
개발자 가이드 문서
https://developer.vpe.naverncp.com/docs/rn/intro
데모앱 소스코드
https://github.com/SGRsoft-Dev/vpe-react-native-demoapp
Video Player Enhancement 소개
https://www.ncloud.com/product/media/videoPlayerEnhancement
설명
- 네이버클라우드 플랫폼 제공 Video Player Enhancement 의 React Native SDK
- 해당 SDK는 Standard 요금제를 이용해야 사용 가능합니다.
V2 주요 변경 사항
V2는 layout-driven 컨트롤 시스템을 기반으로 재작성되었습니다. 기존 사용자는 아래 Migration 항목을 참조해 주세요.
| 항목 | 내용 |
|---|---|
| Layout 시스템 | 새 ControlBar가 기존 PlayerControls를 대체. layout prop으로 컨트롤 구성 자유 정의 (pc/mobile/fullscreen × vod/live) |
| 단위 컨트롤 컴포넌트 | PlayBtn, BigPlayBtn, VolumeBtn, FullscreenBtn, SeekBar, SubtitleBtn, SettingBtn, BackBtn, ShareBtn, SkipForwardBtn, SkipBackBtn, NextVideoInfo 등 17개 |
| IconOverrides 확장 | 19개 아이콘 키, 4가지 값 타입 지원 (ReactNode \| string(URL) \| number(require) \| () => ReactNode). props.icon → options.icon으로 위치 이동 |
| NextVideoInfo | 영상 종료 후 다음 영상 카드 (썸네일 + 5초 카운트다운, 자동 재생) — BigPlayBtn에 자동 통합 |
| 제스처 시스템 | 좌/중/우 1/3 영역 분할 더블탭 누적 seek (10초 단위), 방사형 SeekIndicator 애니메이션 |
| fade-in/out 애니메이션 | 컨트롤바 0.3초 부드러운 페이드 |
| Group 알약/원형 디자인 | wrapper: 'Group'이 디폴트로 알약 모양, 단일 자식이면 원형 |
| 음소거 인디케이터 | 컨트롤바 비활성 + 음소거 시 좌측 상단 표시 |
| events.backPress | 백버튼 콜백 (이전 props.backButton 폐지) |
| PlayerContext | 모든 컨트롤이 prop drilling 없이 상태/액션 접근 |
| layout-driven iconSize | layout 단위로 아이콘 디폴트 사이즈 지정 가능, fullscreen 자동 +3 |
설치
yarn add vpe-react-native의존성 설치
yarn add @sgrsoft/react-native-video react-native-svg react-native-capture-protection phosphor-react-native expo-screen-orientation expo-navigation-bar expo-localization expo-application expo-network @miblanchard/react-native-slider개발용 테스트 키 및 테스트용 AppId 설정
- Video Player Enhancement 는 AppId + AccessKey 조합으로 라이선스 체크를 실시합니다.
- Expo GO에서는 정식 AppId를 이용할 수 없어 개발 모드 전용 props 가 존재합니다.
<VpePlayer
devTestAppId={'TEST DEV AppID'} // EXPO GO 대응, 개발 모드에서만 사용됨
accessKey={'VPE ACCESS KEY'} // AppID 와 일치하는 Access Key
/>Expo GO 지원 불가
- VPE RN SDK는 Expo GO 에서 동작하지 않습니다.
- development build 를 이용해주시기 바랍니다.
Quick Start
import { VpePlayer } from 'vpe-react-native';
import { StatusBar } from 'react-native';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import { useState, useRef } from 'react';
import { useNavigation } from '@react-navigation/native';
export default function Player() {
const navigation = useNavigation();
const playerRef = useRef(null);
const [isFullScreen, setIsFullScreen] = useState(false);
return (
<SafeAreaProvider>
<SafeAreaView edges={isFullScreen ? ['none'] : ['top', 'left', 'right']} />
<StatusBar barStyle={'dark-content'} hidden={isFullScreen} />
<VpePlayer
ref={playerRef}
devTestAppId={'TEST DEV AppID'}
accessKey={'VPE ACCESS KEY'}
platform={'pub'} // pub: 민간, gov: 공공
events={{
// V2 신규 — 백버튼 콜백 (이전 backButton prop 대체)
backPress: () => {
if (navigation.canGoBack()) navigation.goBack();
},
ready: () => console.log('player ready'),
fullScreen: (data) => setIsFullScreen(data.isFullScreen),
timeupdate: (data) => {
// duration / currentTime / percent / sourceType
},
nextTrack: (data) => console.log(data),
prevTrack: (data) => console.log(data),
volumechange: (data) => console.log(data),
play: () => console.log('play'),
pause: () => console.log('pause'),
ended: () => console.log('ended'),
controlbarActive: () => console.log('active'),
controlbarDeactive: () => console.log('inactive'),
}}
options={{
playlist: [
{
file: 'https://m4qgahqg2249.edge.naverncp.com/hls/.../master.m3u8',
poster: 'https://2ardrvaj2252.edge.naverncp.com/.../poster.jpg',
description: {
title: '네이버클라우드 소개 영상',
created_at: '2025.08.20',
profile_name: '네이버클라우드',
profile_image: 'https://.../profile.png',
},
vtt: [
{ id: 'ko', file: 'https://.../ko.vtt', label: '한국어', default: true },
{ id: 'en', file: 'https://.../en.vtt', label: 'English' },
],
},
],
autostart: true,
muted: true,
aspectRatio: '16/9',
objectFit: 'contain',
controls: true,
// 음소거 안내 인디케이터 (false → 표시)
startMutedInfoNotVisible: false,
// 컨트롤 버튼 토글
controlBtn: {
play: true,
fullscreen: true,
progressBar: true,
volume: true,
times: true,
pictureInPicture: true,
setting: true,
subtitle: true,
},
progressBarColor: '#ff0000',
controlActiveTime: 3000,
playRateSetting: [0.5, 0.75, 1, 1.5, 2],
playIndex: 0,
descriptionNotVisible: false,
// 리액트 네이티브 전용
screenRecordingPrevention: false,
allowsPictureInPicture: true,
autoPause: false,
modalFullscreen: false,
// V2 신규 — 아이콘 오버라이드 (이전 props.icon → options.icon)
icon: {
// play: <CustomPlayIcon/>, // ReactNode
// bigPlay: 'https://example.com/play.svg', // 원격 URL
// back: require('./assets/back.png'), // 로컬 require
// setting: () => <CustomSettingIcon/>, // 함수형
},
// 자막 환경설정
captionStyle: {
fontSize: 12,
color: '#FFFFFF',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
edgeStyle: 'dropshadow',
},
}}
/>
</SafeAreaProvider>
);
}V2 신규 기능 — Layout 시스템
layout prop으로 ControlBar의 구성을 자유롭게 정의할 수 있습니다. 미지정 시 디폴트 layout(pcLayout/mobileLayout/fullscreenLayout)이 자동 사용됩니다.
기본 사용 (디폴트 layout)
<VpePlayer ... />
// → 자동으로 화면 크기 / 라이브 여부 / 풀스크린 여부에 따라 적절한 디폴트 layout 사용사용자 정의 layout
<VpePlayer
layout={{
pc: {
vod: {
iconSize: 20, // 이 layout의 디폴트 아이콘 크기
order: ['top', 'center', 'lower', 'bottom', 'seekbar'],
top: [
{ items: ['BackBtn'], wrapper: 'Group' },
{ items: ['MetaDesc'], wrapper: 'Blank' },
{ items: ['ShareBtn', 'SettingBtn'], wrapper: 'Group', cap: 2 },
],
center: [{ items: ['BigPlayBtn'], align: 'center' }],
lower: [
{ items: ['TimeBtn'], wrapper: 'Group', align: 'left' },
{ wrapper: 'Blank', align: 'left' },
{ items: ['SubtitleBtn', 'FullscreenBtn'], wrapper: 'Group' },
],
bottom: [],
// 'seekbar' 슬롯이 order에 있으면 화면 하단 풀폭 SeekBar 자동 표시
},
live: { /* live 모드용 */ },
},
mobile: { vod: { /* ... */ }, live: { /* ... */ } },
fullscreen: { vod: { /* ... */ }, live: { /* ... */ } },
breakpoint: 768, // 모바일 판정 기준 (px)
}}
{...rest}
/>사용 가능한 컨트롤 아이템 이름
PlayBtn, BigPlayBtn, VolumeBtn, MuteBtn, TimeBtn, CurrentTimeBtn, DurationBtn, SeekBar, FullscreenBtn, SubtitleBtn, SettingBtn, PrevBtn, NextBtn, NextPrevBtn, MetaDesc, BackBtn, ShareBtn, SkipForwardBtn, SkipBackBtn, NextVideoInfo, Blank
그룹 wrapper
| wrapper | 동작 |
|---|---|
| 'Group' (디폴트) | 알약 모양 (gray 0.4 배경, borderRadius). 단일 자식이면 원형 (TimeBtn 단일은 우회) |
| 'Blank' | spacer 또는 자식 정렬 wrapper. 자식 없으면 flex: 1 |
그룹 옵션
| 옵션 | 설명 |
|---|---|
| items | 컨트롤 이름 배열 또는 ReactNode 배열 |
| wrapper | 'Group' | 'Blank' |
| align | 'left' | 'right' | 'center' |
| cap | 표시할 자식 최대 개수 (초과분 잘림) |
| noPadding | true 시 알약/원형 배경 끔 (단순 row) |
| style | 추가 ViewStyle override |
dev 모드 layout 검증
__DEV__에서 layout 정의가 잘못되면 console.warn 으로 즉시 알림 (알 수 없는 itemName, 잘못된 wrapper/align/order 등).
V2 신규 기능 — IconOverrides
options.icon 객체로 모든 아이콘을 자유롭게 override할 수 있습니다.
키 (총 19개)
bigPlay, play, pause, replay, prev, next,
subtitle, subtitleOff,
fullscreen, fullscreenExit,
volumeFull, volumeMid, volumeMute,
setting,
back, share, skipForward, skipBack값 타입 (4가지)
options={{
icon: {
// 1. ReactNode — JSX 직접
play: <CustomPlayIcon size={28} />,
// 2. string — 원격 이미지 URL
bigPlay: 'https://example.com/play-icon.svg',
// 3. number — require() 결과 (로컬 이미지)
back: require('./assets/back.png'),
// 4. function — 동적 렌더링
setting: () => <DynamicSettingIcon />,
},
}}V2 신규 기능 — events.backPress
이전의 backButton prop은 폐지되고 events.backPress 콜백으로 대체되었습니다. 기본 BackBtn 컴포넌트가 디폴트 layout의 top 최왼쪽에 자동 표시되며, 누르면 events.backPress가 호출됩니다.
events={{
backPress: () => {
if (navigation.canGoBack()) navigation.goBack();
},
}}V1 → V2 Migration
| 항목 | V1 | V2 |
|---|---|---|
| 백버튼 | <VpePlayer backButton={() => <CustomBack/>}/> | <VpePlayer events={{ backPress: () => ... }}/> (BackBtn 자동 렌더) |
| 아이콘 오버라이드 | <VpePlayer icon={{ play: ... }}/> | <VpePlayer options={{ icon: { play: ... } }}/> |
| 컨트롤바 | PlayerControls (제거됨) | ControlBar (자동) — layout prop으로 커스텀 |
| PIP 버튼 | PipBtn 컴포넌트 | 명시적 PIP 버튼 폐지. iOS는 playerRef.current.pip(), Android는 allowsPictureInPicture lifecycle 자동 진입 |
V1에서 V2로 마이그레이션 시:
- 모든
backButtonprop 제거 →events.backPress로 이동 props.icon→options.icon으로 위치 이동 (값 형식은 그대로 호환)- 레이아웃 커스터마이징 시
layoutprop 사용 (선택 사항, 미지정 시 디폴트 자동)
app.json 설정
{
"expo": {
"plugins": [
[
"react-native-capture-protection",
{ "captureType": "fullMediaCapture" }
],
[
"@sgrsoft/react-native-video",
{
"enableAndroidPictureInPicture": true,
"enableNotificationControls": true
}
]
],
"ios": {
"infoPlist": {
"UIBackgroundModes": ["audio", "fetch"]
}
},
"android": {
"edgeToEdgeEnabled": true,
"supportsPictureInPicture": true,
"permissions": [
"android.permission.FOREGROUND_SERVICE"
]
}
}
}iOS Podfile 패치 (newer Xcode 대응)
newer Xcode/Clang 환경에서 fmt 라이브러리의 consteval 빌드 에러가 발생할 수 있습니다. example/ios/Podfile 의 post_install hook에 다음 패치를 추가하세요:
installer.pods_project.targets.each do |target|
if target.name == 'fmt' || target.name == 'RCT-Folly'
target.build_configurations.each do |config|
config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'gnu++17'
defs = config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] || ['$(inherited)']
defs = [defs] unless defs.is_a?(Array)
defs << 'FMT_USE_CONSTEVAL=0' unless defs.include?('FMT_USE_CONSTEVAL=0')
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = defs
end
end
endExample 데모
데모앱에 풍부한 데모 페이지가 있습니다: https://github.com/SGRsoft-Dev/vpe-react-native-demoapp
- BasicDemo — UGC 표준 사용 예
- LayoutDemo — 사용자 정의 layout (pc/mobile/fullscreen × vod/live)
- ControlsShowcase — 모든 컨트롤 컴포넌트를 한 화면에서 디자인 검증
- LiveDemo — LL HLS 라이브
- Drm / NcpDrm — PallyCon / Ncloud DRM
- Pip / Watermark / ScreenRecordingPrevention / FullscreenDemo
- CustomButton / IconChange / Override / ErrorOverride
- PlayerEvent / Method / StartTime
라이선스 / 문의
- 문서: https://developer.vpe.naverncp.com/docs/rn/intro
- 데모앱: https://github.com/SGRsoft-Dev/vpe-react-native-demoapp
- 제품 소개: https://www.ncloud.com/product/media/videoPlayerEnhancement
