1. 목표
: iframe에서 반복재생(Loop)기능과 연속재생(Autoplay)기능을 구현하고자한다.
2. 실험시작
시도 1 :
공식문서에서 제공하는 iframe의 props인 loop와 autoplay를 사용해봤으나, 안된다.
나만 그런게 아니고 모두가 안된다.
공식문서상의 방법은 다음과 같다.
먼저 loop의 경우,initialPlayerParams안에 속해앴는 props로 default값은 false로 되어있으니, true로 할당하라한다.
autoplay의 경우 0이 연속재생true, 1이 연속재생false 값이라고 한다.
initialPlayerParams를 제외하고 loop를 할당해보기도 하고, boolen으로 할당되어있던 타입스크립트도 교정하여 0으로 할당해보기도 했다.
autoplay도 밖에 opts에 포함한 props형식으로도 사용해보고 boolen형식도 사용해보았다.
안된다. 먹히질 않는다.
강제력을 주기위해 forceAndroidAutoplay로 할당도 해보았으나, 영향이 없다.
이게 iframe이 웹뷰형식으로 할당되어 있기 때문에, 모바일 환경에서는 안먹히는거라고 하는데, 비단 그 문제만은 아닌거 같다.
<YoutubePlayer
...
initialPlayerParams={{loop: true}}
autoplay={0}
...
/>
시도 2 :
이번엔 모듈 자체를 바꿔봤다.
react-native-youtube-iframe이라는 모듈을 사용중이므로, 해당 모듈안에 loop의 설정 자체를 바꿔보았다.
해당 코드는 scr => PlayerScript.js에서 찾아볼 수 있다.
default값이 false이기에 자동 정지하므로, 이를 true로 할당해보았다.
역시 씨알도 안먹힌다. 왜일까..
그래서 웹뷰의 문제인가 싶어, CUSTOM_USER_AGENT의 할당값을 바꿔보았다.
아래는 기존값과 변화값이다.
하이브리드 앱 자체적 결점인가 싶어 교체해 주었으나, 이것도 영향이 없다.
export const CUSTOM_USER_AGENT =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36';
'Mozilla/5.0 (Linux; Android 6.0.1; RedMi Note 5 Build/RB3N5C; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.91 Mobile Safari/537.36'
playerVars={{
autoplay: 1,
controls: 0,
showinfo: 1,
modestbranding: 1,
loop: 1,
fs: 0,
cc_load_policy: 0,
iv_load_policy: 3,
autohide: 1,
playsinline: 1,
}}
frameborder="0"
allow="autoplay"
allowfullscreen
이 과정에서 html을 이용할 땐, autoplay적용시, mute로 소리 조건도 함께 설정해줘야 한다는 것을 알게되었다.
이 경우엔 내가 사용하는 videoId={ videoID } 방식이 아닌 scr = { url } 방식을 이용한다.
즉, scr={ url + ?autoplay=1&mute=1 ) 방식을 사용하는데, 이 방법을 사용할 때, allow = 'autoplay'도 넣어줘야한다.
<iframe src="https://www.youtube.com/embed/VIDEO_ID?autoplay=1" allow='autoplay'></iframe>
시도 4 :
playing에 대한 useState와 useCallback을 교정해보려한다.
즉, 영상이 종료되는 지점에서 다음 영상을 onLoad하여 playing(true)와같은 값을 실행해볼까한다.
현재 시도해보고자 하는 것은
- iframe내 play props에 삼항연산자를 사용하는 방법
- useState를 통해 loop 코드를 직접 작성하는 것
- useCallback문에 있는 if문에 else문을 추가하여 조건을 더 걸어주는 것
을 시도해보려 한다.
단, 여기서 가장 큰 문제점은 할당할 값을 어떻게 loop 혹은 랜덤리스트항목에 할당해주는 방식이다.
1) 우선, useCallbak Hook 내에 else문을 넣어 보려고 했다.
else문이 작동하기 위한 변수로 iframe내에 선언한 상태변수인 아래코드 부분에 상태 변수를 추가해주었다.(constants.js)
이후 기존에 if 문에 state에 대한 상태 확인 변수인 ended를 ===로 비교해주는 것과 같이,
else문ㅇ도 적용하려 했으나, 오류가 발생하며, syntax오류가 난다. 이 방법은 youtube에서 제공하는 조건까지 건드려야 하므로, 건드릴 수 없는 영역에 걸쳐 보류하기로 한다.
export const PLAYER_STATES_NAMES = {
UNSTARTED: 'unstarted',
ENDED: 'ended',
PLAYING: 'playing',
PAUSED: 'paused',
BUFFERING: 'buffering',
VIDEO_CUED: 'video cued',
AUTO: 'Autoplay' <= 이 부분을 추가함
};
export const PLAYER_STATES = {
'-1': PLAYER_STATES_NAMES.UNSTARTED,
0: PLAYER_STATES_NAMES.ENDED,
1: PLAYER_STATES_NAMES.PLAYING,
2: PLAYER_STATES_NAMES.PAUSED,
3: PLAYER_STATES_NAMES.BUFFERING,
5: PLAYER_STATES_NAMES.VIDEO_CUED,
6: PLAYER_STATES_NAMES.Auto, <= 이 부분 추가함
};
2) useState를 통해 loop 코드를 직접 작성하는 것을 하려했으나, 이것은 어차피 iframe내 autoplay에 관한 함수고 동작하지 않으면 의미가 없다.
3) iframe내 play props에 삼항연산자를 사용하는 방법역시 트리거만 될 뿐이지, 중요한 iframe내 기능이 동작하지 않으면 의미가 없으므로 패스
시도 5. videoId={ cardID } 에 대입되는 cardID를 재생이 끝나는 순간 다음 videoId로 자동 변경해주기.
1) 기존의 cardID는 item이라고 realtime database에서 받은 items란 json데이터 내에 있는 videoId를 받는 변수이다.
또한 이는 useState를 통해 상태값이 변할수 있게끔 되어있다.
2) 기존 동영상 재생은 iframe API에 따라 play= { playing }으로 되어있으며, playing이란 변수는 useState를 통해
상태변화하는 변수이다. 여기서 playing이 true일 때 재생, false일때 중지이다.
3) 따라서, playing이 false가 되면 => items 내 (index값+1) = index 를 주어 => +1 이 된 index값에 대한 videoID를
=> cardID로 받아 => videoId에 대입해주고 => playing이 다시 true가 되도록 함수를 정의하고자 한다.
4) 새로 작성한 코드를 몇가지 변형하여 시도해보았으나 모두 적용이 되지 않는다.
기존 코드(onPress시 자동 재생이 되도록 설정 되어있다.)
const [playing, setPlaying] = useState(true);
...
const onStateChange = useCallback((state) => {
if (state === "ended") {
setPlaying(true);
}
}, []);
...
const onPress = ({ item }) => {
return (
setCardID(item.id.videoId)
)
}
...
return (
...
<View>
<YoutubePlayer
height={200}
play={playing}
videoId={cardID}
onChangeState={onStateChange}
opts={{
playerVars: {
autoplay: 1,
rel: 0,
modestbranding: 1
}
}}
/>
</View>
새로 추가한 함수
...
function Next ({item}) {
if (playing == false) {
Object.keys(item) == (Object.keys(item) + 1);
return(
setCardID(item.id.videoId)
)
}
}
const onStateChange = useCallback((state) => {
if (state === "ended") {
<Next/>
setPlaying(true);
}
}, []);
시도 5. 원인 발견
: 왜 왜 stackoverflow나 구글링으로 찾은 해답들이 안먹히는지 알았다.
내가 쓰는 모듈은 react-native-iframe으로 최근에 react-native 전용으로 나온 모듈이다.
그러나 여태 적용해 본 해답들은 react-youtube, iframe, youtube 등의 다른 모듈이라,
그 옵션들의 사용 명칭과 경로가 달랐던 것이다.(모듈의 스크립트를 전부 뜯어보고 알게된...나는 바보...)
그래서 결론은 react-native-iframe에 맞는 options에서 loop를 적용한 방법을 찾아야 한다.
그리고 autoplay는 아래와 같은 명령어를 입력하면 된다.
<iframe
...
forceAndroidAutoplay
...
/>
다만, 이미 react-native-iframe는 연속재생(autoplay)이 적용되있는것 같다.(입력 안해도 자동재생이 된다)
여태 자동 재생이 안된 이유는 현재 재생중인 videoId 다음에 que되는 videoId가 지정되있지 않았기 때문이다.
str으로 videoId를 따로 입력해주니 정상작동한다.
이는 아래의 위치에 해줬다. 상태 변화에 따른 반응을 하는 onStateChange 함수 안이다.
참고로 setPlaying을 true로 해줄 경우 flatlist에서 누른 카드가 onPress시 바로 재생된다. (재생버튼 안눌러도댐)
const onStateChange = useCallback((state) => {
if (state === "ended") {
setCardID("Video_Id를_입력하시오")
setPlaying(true)
//외부 function은 안먹힘
//setState( )안에 function은 먹힘
//console.log는 먹힘
//즉, 내부에서 선언하는 것은 먹힌다는 소리
//useState는 먹힘
}
}, []);
시도 6. 진행과정
: 우선 상단의 setCardID( 여기 ) 부분에 따로 선언해둔 함수를 통한 return값을 넣어줄 수 있다는 것을 알게되었다.
그래서 함수이름을 여기 부분에 넣고, 외부에 함수를 하나 const해주려 한다.
우선 함수를 구성해주기에 앞서, item의 값이 온전히 들어오는지 확인해야했다.
원래 희망하던 방법은 realtime database에 있는 array상위에 키값으로 0부터 시작한숫자로 되어있기에,
이 값을 index라 하고 index변화에 따른 함수를 정의해주려 했다.
그러나 Object.keys(item)으로 console.log 해본 결과, 키값을 index가 아닌 index하위 키값을 키값으로 받아와진다.
즉, 상위 키로 존재하는 숫자는 사용 불가.
Object.keys(state)로 console.log 찍어본 결과 숫자가 모두 나오는걸로 봐서,
flatlist에 state 데이터가 입력되는 순간 상위 딕셔너리의 키값을 제거되고, 그 하위 array값만 반환되는 듯하다.
다행이 내 json데이터에는 타임스탬프가 존재한다.
즉, 업로드 시간이다.
우선 onPress를 통해 값이 나오나 확인. 잘 나온다.
이제 타임스탬프로 할 방법을 찾던가, 인덱스를 auto로 부여하는 방법을 찾던가 해야겠다.
const onPress = ({ item }) => {
console.log(item.snippet.publishedAt)
return (
setCardID(item.id.videoId)
)
}
그 뒤로 index부여는 했지만, index랑 item의 키값이 따로 놀기때문에 방법을 강구해야할듯하다.
우선 인덱스 부여는 flatlist의 props에 index선언 후 index라는 props를 태그를 통해 외부 함수로 전달해준다.
그리고 추후에 인덱스 확인을 위해 onPress에서 index를 외부로 전달해준다.
<FlatList
data={state}
keyExtractor={(item, index) => index}
renderItem={({ item, index }) => (
...
//renderItem의 { index } 부분에 선언
...
<View style={styles.cardContainer}>
<TouchableOpacity style={styles.card} onPress={() => onPress({ item, index })}>
<Image style={styles.cardImage} source={{ uri: item.snippet.thumbnails.medium.url }} />
<View style={styles.cardText}>
...
<Text style={styles.cardDate} >{test(index = { index })}</Text>
//test라는 함수에 index라는 props를 index라고 해서 전달
//나중에 index는 이 위치에 Text로 찍힐 것이다.
이제 onPress로 console.log찍어본다. 결과로는 Object.keys로 키값은 index라고 반환되며, values로 숫자가 반환된다.
const onPress = ({ item, index }) => {
console.log(Object.values(index))
return (
setCardID(item.id.videoId)
)
}
'React-native > 실패일지' 카테고리의 다른 글
[실패일지] 유튜브 API Search 연동하기 (0) | 2022.06.20 |
---|---|
[실패일지] favorite(좋아요) 구현하기 (0) | 2022.05.31 |
[실패일지] realtime database에 여러 파일 올려 관리하기 (0) | 2022.05.27 |
[실패일지] Search bar 연동 중 쿼리문제 (0) | 2022.05.24 |
[실패일지] FlatList에 iframe 적용하기 (성공완료) (0) | 2022.05.23 |