네이티브 연동

SauceLive_iOS는 iOS 애플리케이션 내에서 웹 콘텐츠를 향상시키기 위해 설계된 iOS SDK입니다. JavaScript 지원, PIP(화면 속 화면) 모드 지원 및 웹 콘텐츠 상호 작용에 대한 다양한 콜백을 제공합니다.

UIKit과 WebKit을 기반으로 구축되었으며, 웹 콘텐츠와의 상호작용을 위한 다양한 메시지 핸들러와 이벤트를 지원합니다.

예제

예제 프로젝트를 실행하려면, 레포를 클론하고, Example 디렉토리에서 pod install을 실행하여 필요한 종속성을 설치한 후 예제 프로젝트를 열어보세요.


시스템 요구 사항

  • iOS 11.0 이상
  • Xcode 11.0 이상
  • Swift 5 이상

설치

CocoaPods

SauceLive_iOS는 CocoaPods을 통해 사용할 수 있습니다. Podfile에 다음 라인을 추가하여 설치하세요.

pod 'SauceLive_iOS'

Swift Package Manager

SauceLive_iOS는 Swift Package Manager를 통해서도 설치할 수 있습니다. Xcode에서 프로젝트를 열고, File > Swift Packages > Add Package Dependency...를 선택 후 레포지토리 URL을 입력하세요.

https://github.com/mobidoo-official/SauceLive_iOS.git

그 다음, 원하는 버전의 SDK를 선택하고 프로젝트에 추가합니다.


기본 설정

SauceLive_iOS SDK를 사용하는 애플리케이션에서 오디오 세션을 올바르게 설정하는 것은 중요합니다. 특히, 앱이 백그라운드 상태로 전환될 때 오디오 재생을 계속 유지하려면, 다음과 같이 AppDelegate.swift 파일에 오디오 세션 설정 코드를 추가해야 합니다. 설정 방법은 아래와 같습니다.

AppDelegate 클래스에 다음의 setupAudioSession 메서드를 추가합니다. 이 메서드는 애플리케이션의 오디오 세션을 구성하여 백그라운드에서도 오디오 재생이 가능하게 합니다.

import AVFoundation

private func setupAudioSession() {
    do {
        try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
        try AVAudioSession.sharedInstance().setActive(true)
    } catch {
        print("Failed to set up audio session: \(error)")
    }
}

이 메서드를 애플리케이션 시작 시점에 호출하기 위해서는, application(_:didFinishLaunchingWithOptions:) 메서드 내에서 setupAudioSession 메서드를 호출해야 합니다.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    setupAudioSession()
    return true
}


사용 방법

기본 설정 방법

  1. SauceLive_iOS를 UIViewController에 Import 합니다.
    화면 전환은 아래 코드를 참고해주세요.

    import UIKit
    import WebKit
    import SauceLive_iOS
    
    ...
    
    // 화면 전환 시
    let myCustomViewController = MyCustomViewController()            
    PIPKit.show(with: myCustomViewController)
    
  2. SauceLiveViewController의 서브클래스를 생성하여 동작을 커스터마이징합니다.

    class MyCustomViewController: SauceLiveViewController {
        
    }
    
  3. SauceLiveDelegate를 구현하여 웹 상호작용을 처리합니다.

extension MyCustomViewController: SauceLiveDelegate {
    func sauceLiveManager(_ manager: SauceLiveViewController, didReceiveEnterMessage message: WKScriptMessage) {
        // 입장 메시지 처리
    }
}
  1. MyCustomViewController 화면 전환시 컨피그 설정으로 구성합니다. 메시지 핸들러와 PiP 기본 설정을 포함합니다.
import SauceLive_iOS

   class MyCustomViewController: SauceLiveViewController {  
          override func viewDidLoad() {  
              super.viewDidLoad()  
                let config = SauceViewControllerConfig(
                   isEnterEnabled: true, /* 라이브 입장 시 실행할 작업 */
                   isExitEnabled: true, /* 라이브 종료 버튼 클릭 시 실행할 작업 */
                   isLoginEnabled: true, /* 로그인 시도 시 실행할 작업 */
                   isProductEnabled: true, /* 제품 이동 시 실행할 작업 */
                   isBannerEnabled: true, /* 배너 클릭 시 실행할 작업 */
                   isShareEnabled: true, /* 공유하기 시 실행할 작업 */ 
                   isPictureInPictureEnabled: true, /* PIP 모드 활성화 시 실행할 작업 */
                   isReloadingEnabled: true, /* 웹뷰 리로딩 시 실행할 작업 */
                   isRewardEnabled: true, /* 리워드 시 실행할 작업 */
                   isPIPActive: true, /* PIP 화면으로 진입, pipMode: .internalMode로 지원  */
                   pipSize: CGSize(width: 100, height: 200), /* PIP 크기 설정 */
                   pipMode: .internalMode,  /* PIP 내부, 외부(백그라운드 지원)설정 */
                   delegate: self
                 )
               configure(with: config)  
          }  
   }
  1. 플레이어 설정 회원 정보 연동하여 URL 을 로드합니다.
    accessToken 을 setMemberObject 함수를 통해 발급 받아 동작하는 방법과 setMemberToken 함수를 이용하여 직접 입력하여 동작시키는 방법이 있습니다.
let sauceLiveLib = SauceLiveLib()
sauceLiveLib.viewController = self
sauceLiveLib.setInit("your broadcastId")
// accessToken을 발급 하는 경우 
sauceLiveLib.setMemberObject(
            memberId: "멤버ID",
            nickName: "닉네임",
            age: "나이",
            gender: "성별") { success, error in
                if success {
                    sauceLiveLib.load()
                } else {
                    sauceLiveLib.load() // 게스트 로그인
                    print(error?.localizedDescription ?? "An unknown error occurred")
                }
            };
// accessToken을 입력할 경우
sauceLiveLib.setMemberToken("your user access token")
sauceLiveLib.load()

그 밖의 기능

Picture-in-Picture (PIP) 모드

SauceLiveViewController는 Picture-in-Picture (PiP) 기능을 지원하여 사용자가 앱 내 다른 작업을 하면서도 비디오 콘텐츠를 계속 시청할 수 있게 합니다. PiP 모드를 활성화하고 창의 크기를 조정하는 방법은 다음과 같습니다.
SauceViewControllerConfig의 isPictureInPictureEnabled 값을 true로 해야 합니다.

 SauceViewControllerConfig (
   ...
    isPictureInPictureEnabled: true,
   ...
 )

PIP 창 크기 설정

PiP 창의 크기를 사용자가 원하는 대로 설정할 수 있습니다. pipSize 속성을 사용하여 크기를 CGSize로 지정합니다. 이 설정은 내부 PiP 모드에서 유용하게 사용됩니다.

SauceViewControllerConfig (
   ...
    pipSize: CGSize(width: 100, height: 200),
   ...
 )

SauceLiveDelegate 사용 방법

SauceLiveDelegateSauceLiveViewController와의 상호작용을 위한 프로토콜입니다.

SauceViewControllerConfig에 true 값으로 변경한 속성값에 한해 웹 콘텐츠로부터 전송되는 다양한 메시지를 처리할 수 있습니다.

SauceLiveDelegate에서 지원하는 주요 Delegate 메서드는 다음과 같습니다.

  • sauceLiveManager(_:setOnEnterListener:):
    사용자가 특정 페이지에 진입했음을 알리는 메시지를 받았을 때 호출됩니다.
  • sauceLiveManager(_:setOnMoveExitListener:):
    사용자가 페이지를 떠나려고 할 때 호출됩니다.
  • sauceLiveManager(_:setOnMoveLoginListener:):
    로그인 페이지로의 이동을 요청하는 메시지를 받았을 때 호출됩니다.
  • sauceLiveManager(_:setOnMoveProductListener:):
    특정 상품 페이지로 이동을 요청하는 메시지를 받았을 때 호출됩니다.
  • sauceLiveManager(_:setOnMoveBannerListener:):
    배너 클릭에 의한 이동 메시지를 받았을 때 호출됩니다.
  • sauceLiveManager(_:setOnShareListener:):
    콘텐츠 공유 요청 메시지를 받았을 때 호출됩니다.
  • sauceLiveManager(_:setOnPictureInPictureListener:):
    PIP 전환 버튼을 눌렀을때 호출됩니다.
  • sauceLiveManager(_:setOnMoveRewardListener:):
    리워드 메시지를 받았을 때 호출됩니다.
  • sauceLiveManager(_:setOnWebviewReloadingListener:):
    리로드 메시지를 받았을 때 호출됩니다.

위와 같은 메서드들을 구현함으로써, SauceLiveViewController에서 발생하는 다양한 이벤트에 대응하며 사용자 정의 동작을 수행할 수 있습니다. message.body 값을 통해 특정 상품 페이지로 이동하거나, 사용자에게 쿠폰을 발급하는 등의 기능을 쉽게 구현할 수 있습니다.

메시지 처리

SauceLive_iOS SDK를 사용하면 웹 콘텐츠로부터 전달 받은 메시지를 JSON 형태로 처리할 수 있습니다. 각 메시지의 data 필드는 message.body를 통해 정보를 확인할 수 있으며, 이벤트의 종류는 다음과 같습니다

라이브 입장

  • 페이지 진입 시 자동으로 호출됩니다.
  • 이벤트 데이터:
    {
        "params": null
    }
    

라이브 종료

  • 이벤트 데이터:
    {
        "params": null
    }
    

로그인 시도

  • 이벤트 데이터:
    {
        "params": null
    }
    

상품 클릭

  • 상품 상세 정보 페이지로 이동합니다.
  • 이벤트 데이터:
    {
        "params": {
            "linkUrl": "String | null", // 상품 상세 정보의 URL
            "broadcastIdx": "String"    // 방송 번호
        }
    }
    

공유하기

  • 이벤트 데이터:
    {
        "params": {
            "linkUrl": "String", // 공유된 주소
            "shortUrl": "String" // short url
        }
    }
    

배너 클릭

  • 배너에 등록된 URL로 이동합니다.
  • 이벤트 데이터:
    {
        "params": {
            "bannerId": "String", // 배너 고유 아이디
            "linkUrl": "String", // 배너에 등록된 URL
            "broadcastIdx": "String" // 방송 번호
        }
    }
    

이러한 메시지 처리 방식을 통해 개발자는 웹 콘텐츠와의 상호작용을 통해 얻은 데이터를 앱 내에서 유용하게 활용할 수 있습니다.

SauceLiveDelegate 예제

SauceLiveDelegate를 사용하는 간단한 예제는 다음과 같습니다.

extension MyCustomViewController: SauceLiveDelegate {
    func sauceLiveManager(_ manager: SauceLiveViewController, didReceiveEnterMessage message: WKScriptMessage) {
        print("사용자가 페이지에 진입했습니다. 메시지 내용: \(message.body)")
        // message.body 값을 사용하여 필요한 로직을 구현하세요. 예를 들어, 사용자에게 알림을 보내거나 특정 UI 업데이트를 할 수 있습니다.
    }
    
    func sauceLiveManager(_ manager: SauceLiveViewController, didReceiveMoveProductMessage message: WKScriptMessage) {
        print("상품 페이지로 이동 요청. 메시지 내용: \(message.body)")
        // message.body를 사용하여 상품 페이지로 이동하는 로직을 구현하세요. 예를 들어, 상품 URL 를 추출하여 해당 상품의 상세 페이지로 사용자를 안내할 수 있습니다.
    }
}