두 플랫폼의 프로젝트 요건
개발 견적을 받기 전에 우리 앱의 최소 OS와 빌드 환경이 아래 조건과 맞는지 먼저 봅니다.
| 항목 | Android | iOS |
|---|---|---|
| 최소 OS | API 수준 25(Android 7.1) | Minimum Deployment 13.0 |
| SDK 추가 | Android Studio에서 NPlayerSDK-release.aar와 Media3 등 외부 라이브러리를 의존성에 추가. Java 11, 디슈가링 설정 | Xcode의 Frameworks, Libraries, and Embedded Content에 NPlayerSDK 추가 |
| 콘솔에 등록할 값 | build.gradle.kts의 applicationId | Bundle Identifier |
| 앱 시작 시 호출 | startMediaPlayerService(): 플레이어와 미디어 세션 생성, DRM 기본 설정 |
MediaPlaybackService.initialize(): 오디오 세션 구성, DRM 기본 설정 |
| 권한·기능 | INTERNET, READ_MEDIA_VIDEO, FOREGROUND_SERVICE, FOREGROUND_SERVICE_MEDIA_PLAYBACK | Background Modes의 Audio, AirPlay, and Picture in Picture |
| 다운로드용 설정 | Manifest에 다운로드 완료 수신기(DownloadCompleteReceiver) | AppDelegate의 handleEventsForBackgroundURLSession에 처리 코드 |
단계별 설정 화면은 Android 안내와 iOS 안내에 있습니다.
플레이어를 앱에 붙이는 구성 요소
기본 화면으로 빠르게 출시할지, 우리 앱 화면 안에 넣을지에 따라 쓰는 클래스가 달라집니다.
| 구성 요소 | 플랫폼 | 쓰는 경우 | 설정을 넘기는 곳 |
|---|---|---|---|
| MediaPlayerActivity | Android | presentMediaPlayer() 한 번으로 SDK 기본 화면 실행 |
MediaPlayerActivityConfiguration |
| MediaPlayerBaseFragment | Android | 강의 화면 일부에 플레이어 배치 | Parameters를 FragmentManager.load()로 전달 |
| MediaPlayerBaseView | Android | 컨트롤 UI를 직접 디자인. Fragment의 onCreateView에서 제공 | Fragment와 같음 |
| MediaPlayerViewController | iOS | present(mediaItems:startIndex:configuration:)로 기본 화면과 재생 목록 실행 |
MediaPlayerViewController.Configuration |
| MediaPlayerBaseViewController | iOS | 커스텀 뷰 컨트롤러의 기반 클래스. 구현은 SDK 샘플 참고 | load(mediaItems:startMediaItemIndex:), 화면 방향 속성 |
기반 클래스는 Android 2025년 4월 7일, iOS 2025년 3월 31일 배포본에 추가됐습니다. iOS의 present() 기본 구현은 마지막 영상이 끝나면 화면을 닫고, 오류가 나면 알림을 띄운 뒤 닫기 버튼을 누를 때 화면을 닫습니다. 문서는 이 구현을 참고해 확장하라고 안내합니다.
영상마다 넣는 값
DRM 설정은 빠뜨릴 수 없고, 나머지는 과정별 정책에 따라 켜고 끕니다.
| 설정 | Android | iOS | 업무상 뜻 |
|---|---|---|---|
| DRM | withDrmConfiguration(App ID, 사용자 ID) | DrmConfiguration.Builder(appId:userId:)를 drmConfiguration(_)으로 연결 | 라이선스와 보고의 사용자 기준 |
| 사용자 데이터 | withDrmConfiguration의 userData(Map) | DrmConfiguration.Builder의 userData(_) | Callback 보고로 돌아올 강좌·수강 식별값 |
| 오프라인 기한 | withDrmConfiguration의 offlineAccessPeriod, 기본 null | DrmConfiguration.Builder의 offlineAccessPeriod(_), 기본 nil | 다운로드본을 볼 수 있는 기간 |
| 건너뛰기·배속 제한 | setSeekable(), setDisablePlaybackRate() | seekable(_), disablePlaybackRate(_) | 진도·인정 시간 관리 과정 |
| 북마크 콜백 | setUseBookmarkCallback() | useBookmarkCallback(_) | 북마크를 고객사 DB에 둘지 |
| 자막 | Media3 setSubtitleConfigurations(). WebVTT, SRT, SMI 다중 선택 | SubtitleConfiguration.Builder로 언어, 라벨, 모드 지정. showing이면 두 개 이상 동시 표시 | 다국어·이중 자막 강의 |
| 제목·썸네일 | MediaMetadata | MediaMetadata.Builder | 플레이어와 다운로드 목록 표시 |
원본의 일부 구간만 재생하는 ClippingConfiguration은 iOS SDK 문서에 있습니다. 웹에서 같은 값을 넘기는 방법은 웹 연동 개요에 정리했습니다.
사업 판단에 쓰는 이벤트
두 SDK는 같은 이름의 이벤트를 앱에 알려 줍니다. 질문별로 어떤 이벤트를 받을지 정해 개발 요구서에 적으세요.
| 알고 싶은 것 | 받는 이벤트 | 운영 활용 |
|---|---|---|
| 끝까지 봤는지 | onPlaybackFinish: 멈춘 위치, 영상 길이, 종료 원인(Ended·Error·UserExited) |
완강과 이탈 구분 |
| 로드 전에 닫았는지 | onUnload |
재생 시도 누락 방지 |
| 건너뛴 구간 | onPositionDiscontinuity: 이동 전·후 위치 |
부정 진도 점검 |
| 배속 사용 | onRateChange |
배속 시청 비율 파악 |
| 재생이 막힌 이유 | onError: Android 예외 17종, iOS 오류 18종 |
원인별 안내, 문의 분류 |
| 다운로드 진행 | 다운로드 리스너: 항목이 들어오거나 빠질 때, 상태가 바뀔 때, 받는 중일 때 | 내려받기 목록 화면, 실패 알림 |
Android는 종료 정보를 ACTION_PLAYBACK_FINISHED 브로드캐스트로도 받습니다. iOS SDK 문서에는 자막 문장이 바뀔 때 오는 textCueChange와 화면 속 화면 상태 이벤트가 있습니다. 진도의 공식 기록은 Callback URL 보고 한곳으로 모으고 앱 이벤트는 화면 처리와 보조 분석에 쓰기를 권합니다. 계산 방법은 진도 데이터 설계에 있습니다.
다운로드함을 만드는 다운로드 매니저
두 SDK 모두 DownloadManager.shared 하나로 앱 안 다운로드함을 운영합니다.
-
Queue
대기열과 동시 다운로드
추가한 항목은 동시 다운로드 한도(maxParallelDownloads, 기본 3) 안에서 바로 시작하고 나머지는 기다립니다. 항목별·전체 일시 정지, 재개, 삭제와 완료 항목 정리가 됩니다.
-
Status
상태와 실패 사유
상태는 대기, 다운로드 중, 일시 정지, 완료, 실패 다섯 가지입니다. Android는 실패 사유를 저장 공간 부족, SD 카드 없음, 권한 만료 등 13가지 값으로 나누고, iOS는 실패 사유를 문자열로 줍니다.
-
Network
셀룰러와 백그라운드
항목을 추가할 때 셀룰러 데이터 허용 여부를 정합니다(기본 허용). iOS는 앱을 내려 둔 동안에도 다운로드를 계속하려면 AppDelegate 처리가 필요합니다.
-
Offline
기한과 자막
기한이 지나거나 권한이 없으면 오프라인 권한 만료·없음 오류가 납니다. 2026년 7월 배포본부터 자막도 함께 저장됩니다.
오프라인 학습 운영 기준은 오프라인 학습 가이드에 있습니다.
SDK 업데이트는 앱 출시 일정에 묶입니다
SDK가 앱 안에 들어가므로 새 버전을 반영하려면 앱을 다시 빌드해 스토어에 배포해야 합니다.
-
Release
보안 수정은 다음 출시에
변경 이력에 보안 관련 수정이 올라오면 다음 앱 출시 범위에 넣고, 스토어 심사 기간까지 일정에 잡아 두기를 권합니다.
-
Pinning
검증한 버전 보관
문서 첫 화면 링크는 최신 파일이고, 변경 이력의 날짜 대부분은 해당 버전 파일로 연결됩니다. 시험을 통과한 파일을 내부 저장소에 보관하세요.
-
Dependencies
의존성 변경 확인
Android 문서는 SDK가 새로 나오면 외부 라이브러리 의존성이 달라질 수 있다고 적고 있습니다. 실제로 2026년 1월 30일 버전은 build.gradle에 media3-datasource-okhttp를 더 넣어야 했습니다.
-
Mixed Versions
구버전 앱이 함께 돈다
앱을 업데이트하지 않은 사용자는 이전 SDK로 재생합니다. 2026년 8월 25일 SDK부터는 변화 없는 진행 보고를 건너뛰므로, 서버는 두 동작을 모두 감당해야 합니다.
플랫폼별 변경 요약은 업데이트 기록에 있습니다.
개발 착수 전에 PM이 정할 것
기본값을 그대로 쓸지부터 정하면 회의가 짧아집니다.
| 결정 | 기본값·선택지 | 판단 기준 |
|---|---|---|
| 플레이어 형태 | 기본 화면, Android는 화면 일부 배치, 직접 디자인 | 출시 일정과 디자인 요구 |
| 백그라운드 재생 | 두 플랫폼 모두 기본 꺼짐 | 오디오 위주 과정만 켤지 |
| 앱을 벗어날 때 | Android는 2024년 8월부터 홈 버튼에 화면 속 화면 대신 백그라운드 재생. iOS는 화면 속 화면 자동 시작이 기본 켜짐 | 두 플랫폼 동작을 맞출지 |
| 화면 속 화면 | 기본 허용 | 보안 등급이 높은 과정은 끌지 |
| 셀룰러 데이터 | 재생과 다운로드 각각, 기본 허용 | 대용량 과정, 회사 지급 단말 |
| 차시가 끝났을 때 | Android Fragment는 pauseAtEndOfMediaItems(기본 false). iOS 기본 구현은 마지막 영상 후 화면 닫힘 | 차시마다 멈출지 |
| 루팅·앱 플레이어 감지 | Android에서 감지 메서드를 재정의해 대응 | 재생 중단, 안내, 기록 중 무엇을 할지 |
앱 출시 전 테스트 체크리스트
채널 공통 시나리오에 더해 모바일 앱에서만 생기는 상황을 따로 시험합니다.
-
Install
등록과 기기
- 운영·테스트 빌드 식별자 모두 콘솔 등록
- 미등록 빌드에서 등록되지 않은 앱 오류
- Android 7.1, iOS 13.0 기기 재생
- iOS는 My Mac 대상으로 1차 시험
-
Playback
재생 환경
- 백그라운드 전환과 화면 속 화면 진입
- 재생 중 전화 수신 후 재개
- 화면 회전, 화면 잠금
- 셀룰러 비허용 상태에서 Wi-Fi 끊기
-
Offline · Security
다운로드와 보안
- 다운로드 중 앱을 백그라운드로 전환
- 비행기 모드 재생 후 재연결 시 오프라인 보고
- 저장 공간 부족 안내
- 녹화 시도, Android 루팅 기기
PlaynPlay 도입을 위한
기술적 지원과 서비스를 제공합니다.
제품 문의부터 데모 시연까지, 모든 지원을 위해 세일즈 및 기술 지원 팀이 준비되어 있습니다.
-
제품 및 도입 문의
도입 범위, 일정, 견적을 상담합니다. 서비스 형태와 사용자 규모를 알려주시면 맞는 연동 방식과 보안 설정을 제안합니다.
-
Trial 신청
PlaynPlay의 기능을 먼저 테스트해 보세요. 트라이얼 기간 동안 귀사의 제품과 PlaynPlay를 연동하고 성능과 기능을 직접 검증할 수 있습니다.
-
PlaynPlay 기술 문의
SDK 연동, Callback URL 설계, DRM 패키징 중에 생기는 질문에 기술팀이 답합니다. 공개된 개발 문서와 샘플 프로젝트도 함께 확인하세요.
플랫폼
플랫폼
역할별 안내