오늘은 안드로이드 스튜디오에서 ExoPlayer를 이용해 간단하게 mp3와 동영상을 재생하는 예제를 먼저 작성하고 커스텀 해 볼 예정이다.
나처럼 간단한 것도 오래 봐야지 아는 사람을 위해(사실은 까먹을 수 있는 나를 위해...) ExoPlyaer 기본 사용법부터 자세하게 작성해보겠다.
ExoPlayer는 구글에서 만든 미디어 재생 라이브러리로 다양한 종류의 미디어 파일을 쉽게 재생할 수 있도록 도와준다.
Android 프레임워크의 일부가 아니며 AndroidSDK와 별도로 배포되는 오픈 소스 프로젝트이다.
MediaPlayer API와 달리 ExoPlayer는 사용자 지정 및 확장이 쉽고 Play Store 애플리케이션 업데이트를 통해 업데이트할 수 있다.
별다른 설정 없이도 네트워크로부터 미디어를 스트리밍 형태로 불러와 재생할 수도 있고, 다양한 포맷들을 지원하며 커스터마이징도 지원한다.
ExoPlayer를 사용한 대표적인 서비스에는 Youtube가 있다!! 자세한 내용은 개발자 가이드 참조
JellyBean(4.1) 이상
을 사용하는 Android 기기Nougat(7.1) 이상
을 사용하는 기기((코드 가져와서 사용하기)) ExoPlayer를 사용한 미디어 스트리밍 링크를 통해 코드를 가져와 실행할 수 있다.
implementation 'com.google.android.exoplayer:exoplayer:X.X.X'
위와 같이 앱 모듈의 build.gradle 파일에 ExoPlayer module dependencies를 추가할 수 있다.
🖐🏻 ExoPlayer 라이브러리는 모듈로 분할되어 필요한 기능만 가져올 수 있기때문에 사용 목적에 따라 필요한 라이브러리만 추가해줘야 한다.
이를 구분하지 않으면 많은 확장함수들을 다운로드 받기 때문에 앱의 성능을 떨어뜨릴 수 있다.
github 문서에 있는 라이브러리에 대한 설명
아래와 같이 가져왔다.
dependencies {
...
implementation 'com.google.android.exoplayer:exoplayer-core:2.18.2'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.18.2'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.18.2'
}
자세한 내용은 모듈 추가 참고!!
다음은 XML 파일에 PlayerView를 추가하고 id를 다음과 같이 player_view
라고 지정
<com.google.android.exoplayer2.ui.StyledPlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
PlayerView deprecated ➜ StyledPlayerView
private ExoPlayer player;
private StyledPlayerView videoView;
[...]
videoView = findViewById(R.id.video_view);
player = new ExoPlayer.Builder(this).build();
videoView.setPlayer(player);
SimpleExoPlayer deprecated ➜ ExoPlayer
MediaItem
을 만들어 player
에 재생할 콘텐츠를 생성할 예정으로 MP3 파일용 항목을 만들어보자.
MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3));
player.setMediaItem(mediaItem);
R.string.media_url_mp3는 strings.xml에서 https://storage.googleapis.com/exoplayer-test-media-0/play.mp3로 정의함.
4가지 메서드 onStart
, onResume
, onPause
, onStop
을 재정의하여 사용하자.
자세한 내용은 앱의 수명 주기 참고!!
먼저 아래 사진과 같이 Code menu > Override methods를 클릭하여 onStart, onResume, onPause, onStop을 선택한다.
그 다음 API 수준에 따라 onStart 또는 onResume 콜백에서 플레이어를 초기화 해준다.
@Override
protected void onStart() {
super.onStart();
if (Util.SDK_INT >= 24) {
initializePlayer();
}
}
@Override
protected void onResume() {
super.onResume();
hideSystemUi();
if (Util.SDK_INT < 24 || player == null) {
initializePlayer();
}
}
Android API 수준 24 이하에서는 리소스를 포착할 때까지 최대한 오래 대기해야 하므로 onResume까지 기다린 후에 플레이어를 초기화
Android API 수준 24 이상에서는자세한 내용은 멀티 윈도우를 지원한다.. 앱이 표시되지만 분할 윈도우 모드로 활성화되지는 않으므로 onStart에서 플레이어를 초기화
initializePlayer()는 아래에서 설명할 예정이다....
private void hideSystemUi() {
videoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
releasePlayer()를 사용해 리소스 해제하기
@Override
protected void onStop() {
super.onStop();
if (Util.SDK_INT >= 24) {
releasePlayer();
}
}
@Override
protected void onPause() {
super.onPause();
if (Util.SDK_INT < 24) {
releasePlayer();
}
}
releasePlayer()
에 작성한 코드, releasePlayer 메서드에 필요한 변수 선언
private Boolean playWhenReady = true; // 재생,일시정지 정보
private int currentWindow = 0; // 현재 윈도우 지수
private Long playbackPosition = 0L; // 현재 재생 위치
플레이어를 해제하고 제거하기 전에 다음 정보를 저장한다.
private void releasePlayer() {
playbackPosition = player.getCurrentPosition();
currentWindow = player.getCurrentMediaItemIndex();
playWhenReady = player.getPlayWhenReady();
player.release();
player = null;
}
이제 releasePlayer()
에 저장한 상태 정보를 초기화 할 때 플레이어에게 제공하면 끝난다!!
그러기 위해 초기화 부분을 initializePlayer()
를 사용해 정리하였다.
private void initializePlayer() {
if (player == null) {
player = new ExoPlayer.Builder(this).build();
videoView.setPlayer(player);
MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3));
player.setMediaItem(mediaItem);
}
// releasePlayer에 저장한 상태 정보를 초기화 중에 플레이어에게 제공하는 부분
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);
player.prepare();
}
true
이므로 앱이 처음 실행될 때 재생이 자동으로 시작된다.currentWindow
와 playbackPosition
이 모두 0으로 초기화된다.MP3 예제 끝~~!
mp3 재생하는 간단한 예제를 해보았는데 동영상도 간단하다!!
처음에 설정했던 미디어 항목 URI를 MP4 파일로 수정하면 끝난다...
private fun initializePlayer() {
[...]
val mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp4));
[...]
}
R.string.media_url_mp4는 strings.xml에서 https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4로 정의함.
이렇게 바꾸면 된다.....
나만 에러 나는거야 ....
혼자 무료 URI를 통해 ExoPlayer를 구현할때 간혹 URI 주소가 https가 아닌 http로 되어있을 때가 있다. http를 사용하게 되면 CleartextNotPermittedException
에러가 발생하는데 ..
에러 메시지를 확인해보면.... 문제 원인은 안드로이드에서 기본적으로 Http 접근을 허용하지 않는다는 것이다.
물론 Https로 접근을 하면 문제가 없지만 해당 사이트가 Https로 지원하지 않는 등의 이유로 Http접근을 해야한다면 예외처리를 해야한다.
Android Developer의 Opt out of cleartext traffic을 보면 안드로이드 Pie(API28)부터 cleartext HTTP
를 비활성화한다고 한다. 따라서 API28 이후에서 Http에 접근하려면 cleartext HTTP
를 활성화 시켜야 한다.
AndroidManifest의 application 태그에서 android:usesCleartextTraffic
를 true 로 설정하시면 모든 Http 주소에 접근할 수 있다.
<application
android:label="@string/app_name"
...
android:usesCleartextTraffic="true">
android:usesCleartextTraffic
는 모든 Http 사이트에 대한 접근을 허용한다. 만약 몇몇 사이트에 대한 접근만 허용하려면 /res/xml/network_security_config.xml
파일을 생성하고 예외 항목들을 추가해야 한다.
다음과 같이 입력하면 secure.example.com에 대한 접근만 허용 된다.
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">secure.example.com</domain>
</domain-config>
</network-security-config>
리스트를 모두 작성했다면 AndroidManifest에 android:networkSecurityConfig
속성으로 예외 리스트 파일을 설정한다.
<application
android:label="@string/app_name"
...
android:networkSecurityConfig="@xml/network_security_config"
다음엔 커스텀 ExoPlayer로 돌아오겠다.....
안녕하세요 글 잘봤습니다. 혹 google cloud api 키는 따로 발급을 해야하는건가요?>