플레이 화면 녹화 및 공유하기

# 학습 과정 소개

메이플스토리 월드에서는 `ScreenRecordService`를 활용하여 플레이 화면을 녹화하고 파일로 저장할 수 있습니다. 또한 `MobileShareService`를 활용하여 모바일에서 녹화한 영상을 손쉽게 공유할 수도 있습니다. 이번 시간에는 예제를 통해 `ScreenRecordService` 및 `MobileShareService`의 활용 방법을 알아보겠습니다.

##### 참고 API Reference

[ScreenRecordService](/apiReference/Services/ScreenRecordService) [MobileShareService](/apiReference/Services/MobileShareService)

# 녹화 모드

`ScreenRecordService`에서는 아래 4가지 녹화 모드(ScreenRecordMode)를 제공합니다. 각 플랫폼별 제약이 있어 일부 녹화 모드는 모든 플랫폼에서 동작하지 않는 경우도 있습니다. 자세한 내용은 아래 표를 참고해 주시기 바랍니다.

[{"녹화 모드":"ScreenOnly","설명":"화면만 녹화","Windows\/macOS":"O","iOS":"O","Android":"O"},{"녹화 모드":"ScreenAndGameAudio","설명":"화면 + 게임 소리 녹화","Windows\/macOS":"O","iOS":"O","Android":"O"},{"녹화 모드":"ScreenAndMic","설명":"화면 + 마이크 녹화","Windows\/macOS":"O","iOS":"O","Android":"X (ScreenAndGameAudioAndMic로 대체)"},{"녹화 모드":"ScreenAndGameAudioAndMic","설명":"화면 + 게임 소리 + 마이크 녹화","Windows\/macOS":"X(ScreenAndMic로 대체)","iOS":"O","Android":"O"}]

> 더 알아보기
> 
>   * Image, Audio 코덱이 정상적으로 지원되지 않는 기기에서는 녹화할 수 없습니다.
>   * 이런 경우에는 `StartRecordToFileAndWait()`, `StartRecordToPhotoLibraryAndWait()` 함수에서 ScreenRecordStartResult.DeviceNotSupported 반환 값을 받습니다.
> 


# 플레이 영상 녹화하기

`ScreenRecordService`를 활용하여 영상을 녹화하는 예제를 살펴봅시다. [Record] 버튼을 누르면 녹화를 시작하고, [Stop] 버튼을 누르면 녹화를 종료하고 파일을 저장하겠습니다.

  1. UI 에디터로 들어가서 RecordGroup이란 이름으로 새로운 UIGroup을 추가합니다. [png](1678416050163b3c472a5574e427ab4c6c79e5be50684)   
그리고 RecordGroup의 DefaultShow를 true로 설정합니다. [png](1678423634296cf0cab991d24471889baefac1f5ee4b5)   

  2. 버튼을 하나 추가한 뒤 이름을 Btn_Record로 변경합니다.   

  3. Btn_Record에 TextComponent를 추가하고 아래와 같이 프로퍼티를 수정합니다. 

[{"컴포넌트":"TextComponent","프로퍼티":"Text","값":"Record"},{"컴포넌트":"TextComponent","프로퍼티":"FontColor","값":"#FFFFFF"}]

  

  4. Btn_Record 버튼의 콘텍스트 메뉴에서 Duplicate 버튼을 눌러 버튼을 복제합니다.   

  5. 복제한 버튼의 이름을 Btn_Stop으로 변경하고, Text에는 Stop을 입력합니다. [png](16784163562145cecc803405a4a1aa358ed0dc4280deb)   

  6. Workspace - MyDesk의 콘텍스트 메뉴에서 Create Scripts - Create Logic을 클릭해 새로운 로직을 생성합니다. 이름은 ScreenRecordServiceTest로 변경합니다. [png](1678416161538b4fd072b7b974d418fb80474e83e816a)   

  7. 스크립트 에디터에서 ScreenRecordServiceTest를 엽니다.   

  8. Property에 아래 내용을 추가합니다. 
         
         @Component
         script PathRecorder extends Component
         property string LastRecordedPath = ""
         end
         



    
    
          
    
    9.  `Record()` 함수를 추가하고 내용을 작성합니다.
        ```lua
    @Component
    script ScreenRecorder extends Component
        method void Record()
           _UIPopup:Open("Do you want to start recording?", function()
            -- recordMode는 ScreenOnly로, excludeSystemUI 옵션은 false로 설정)
            local result = _ScreenRecordService:StartRecordToFileAndWait(ScreenRecordMode.ScreenOnly, false)
            if result == ScreenRecordStartResult.Success then
        	    _UIToast:ShowMessage("Start recording")
            else
        	    _UIToast:ShowMessage("Failed : "..tostring(result))	
            end
        end, function()
        	_UIToast:ShowMessage("Canceled")
        end)
        end
    end
    
    
    
    영상을 녹화할 때는 `StartRecordToFileAndWait()` 또는 `StartRecordToPhotoLibraryAndWait()` 함수를 사용할 수 있습니다.
    이때 사용한 함수에 따라 플랫폼 별로 영상 저장 경로가 달라집니다.
    
    | 플랫폼 | StartRecordToFileAndWait() 함수 사용 시 저장 경로 | StartRecordToPhotoLibraryAndWait() 함수 사용 시 저장 경로 |
    | :---: | :---: | :---: |
    | Windows | @cols=2:@rows=1:내 PC > 동영상 > MapleStory Worlds > 월드 ID > MapleStory Worlds_*.mp4 | 
    | macOS  | @cols=2:@rows=1: 홈 > 비디오 > MapleStory Worlds > 월드 ID > MapleStory Worlds_*.mp4 | 
    | iOS | 내 파일 > 나의 iPhone > MaplestoryWorlds > MapleStory Worlds > 월드 ID > MapleStory Worlds_*.mp4 | @cols=1:@rows=2:사진 / 갤러리 |
    | Android | 내장 메모리 > Android > data > com.nexon.mod > files > MapleStory Worlds > 월드 ID > MapleStoryWorlds_*.mp4 | 
      
    
    

  10. Btn_Record 버튼을 눌러 녹화를 시작할 수 있도록 이벤트 핸들러에 `ButtonClickEvent`를 추가합니다. 이벤트 센더를 아래와 같이 Entity로 설정합니다. [png](1678417754286bb465689e3e44568a5cc351a0e7688c6)   
이후 아래와 같이 내용을 작성합니다. 
         
         @Component
         script ButtonRecorder extends Component
         @EventSender("Self")
         handler HandleButtonClickEvent(ButtonClickEvent event)
         --------------- Native Event Sender Info ----------------
         -- Sender: ButtonComponent
         -- Space: Client
         ---------------------------------------------------------
         
         -- Parameters
         local Entity = event.Entity
         ---------------------------------------------------------
         self:Record()
         end
         end
         



    
    
          
    
    11. `Finish()` 함수를 추가하고 내용을 작성합니다.
        녹화를 종료할 때는 `FinishRecordAndWait()` 함수를 사용합니다. 녹화 파일이 생성되면 저장 경로를 반환합니다.
        ```lua
    @Component
    script ScreenRecordingFinisher extends Component
        method void Finish()
        _UIToast:ShowMessage("End recording")
        self.LastRecordedPath = _ScreenRecordService:FinishRecordAndWait()
        log("Output : ", self.LastRecordedPath)
        end
    end
    
    
    
    > **더 알아보기**
    > 단, 윈도우 환경에서는 공유 기능이 없어 `StartRecordToFileAndWait()` 함수를 사용하면  `StartRecordToPhotoLibraryAndWait()` 함수로 대체하여 호출합니다. `StartRecordToPhotoLibraryAndWait()`로 녹화 시작 및 종료했다면, 저장 경로로 빈 값이 반환됩니다.
      
    
    

  12. Btn_Stop 버튼을 눌러 녹화를 종료할 수 있도록 이벤트 핸들러에 `ButtonClickEvent`를 아래와 같이 추가합니다. 이벤트 센더를 아래와 같이 Entity로 설정합니다. [png](1678417899020da7233c0e9a64655bbfe9fa5cecbfc0e)   
이후 아래와 같이 내용을 작성합니다. 
         
         @Component
         script ActionFinisher extends Component
         @EventSender("Self")
         handler HandleButtonClickEvent(ButtonClickEvent event)
         --------------- Native Event Sender Info ----------------
         -- Sender: ButtonComponent
         -- Space: Client
         ---------------------------------------------------------
         
         -- Parameters
         local Entity = event.Entity
         ---------------------------------------------------------
         self:Finish()
         end
         end
         



    
    
             
    
    13.  **[시작]** 버튼을 누른 뒤 테스트해 봅시다. 
        **[Record]** 버튼을 누르면 화면 녹화가 시작되고, **[Stop]** 버튼을 누르면 녹화가 종료되며 파일이 저장됩니다.
        [gif](1678424192506294a4b8f784946a8aa06241618708fc2)
        [png](1678424210461bbb4c320b08348fab23a6029336dd50a)
    
    # UI 가리고 영상 녹화하기
    
    UI를 가리고 영상을 녹화하는 방법을 살펴봅시다.
    
    1. UI 에디터로 들어가서 **DefaultGroup**에 **UIText**를 하나 추가하고 프로퍼티를 아래와 같이 설정합니다.
        [png](1678430164183080b4d5df681412da8450337321bb50d)
        | 프로퍼티 | 값 |
        | --- | --- |
        | RectSize | X = 700, Y = 100 |
        | Text | ScreenRecordService TEST |
        | FontSize | 50 |
        | ImageRUID | b9ab8455d5737bf4cb21433f00fdc19d |
        | Color | A = 100%, #FFFFFF |
            
    
    2. 스크립트 에디터에서 **ScreenRecordServiceTest**를 엽니다. 
            
    
    3. **Property**에 아래와 같이 내용을 작성합니다.
        ```lua
    @Component
    script DefaultUiGroupInitializer extends Component
        property EntityRef DefaultGroup = "/ui/DefaultGroup"
    end
    
    
    
        
    
    

  4. `Record()` 함수를 아래와 같이 수정합니다. 
         
         @Component
         script ScreenRecorder extends Component
         method void Record()
           _UIPopup:Open("Do you want to start recording?", function()
         -- 가리려는 UIGroup의 visible을 false로 변경
         self.DefaultGroup.Visible = false
         -- 우측 상단 기본 UI를 숨기기 위해 excludeSystemUI 옵션을 true로 변경
         local result = _ScreenRecordService:StartRecordToFileAndWait(ScreenRecordMode.ScreenOnly, true)
         if result == ScreenRecordStartResult.Success then
             _UIToast:ShowMessage("Start recording")
         else
             _UIToast:ShowMessage("Failed : "..tostring(result))	
         end
         end, function()
         _UIToast:ShowMessage("Canceled")
         end)
         end
         end
         



    
    
            
    
    5. `Finish()` 함수를 아래와 같이 수정합니다.
        ```lua
    @Component
    script ScreenRecordFinisher extends Component
        method void Finish()
        _UIToast:ShowMessage("End recording")
        self.LastRecordedPath = _ScreenRecordService:FinishRecordAndWait()
        -- 녹화 종료 후 UI가 다시 보이도록 아래 내용 추가
        self.DefaultGroup.Visible = true
        log("Output : ", self.LastRecordedPath)
        end
    end
    
    
    
      
    
    

  6.  [시작] 버튼을 누른 뒤 테스트해 봅시다. [Record] 버튼을 누르면 UI를 숨기고 영상을 녹화할 수 있습니다. 녹화가 종료되면 다시 UI가 보입니다. [gif](167843224107397026e661dfd4bdeb1e578fabfac9229)



# 모바일에서 녹화 영상 공유하기

`MobileShareService`를 사용하면 녹화한 영상을 모바일에서 공유할 수 있습니다. 공유할 영상은 `StartRecordToFileAndWait()` 함수를 사용해 녹화해야 합니다. 단, 녹화 시간은 최대 2분으로 제한됩니다. 예제를 통해 모바일에서 녹화 영상을 공유하는 방법을 살펴봅시다.

  1. Btn_Record 버튼의 콘텍스트 메뉴에서 Duplicate 버튼을 눌러 버튼을 복제합니다.   

  2. 복제한 버튼의 이름을 Btn_Share으로 변경하고, Text에는 Share을 입력합니다. [png](1678757498013b1075f65b0e44c508965220c93cbddda)   

  3. 스크립트 에디터에서 ScreenRecordServiceTest를 엽니다.   

  4. `ShareVideo()` 함수를 추가하고 내용을 작성합니다. 
         
         @Component
         script VideoSharer extends Component
         method void ShareVideo()
         if self.LastRecordedPath ~= "" then
             log("FilePath: ", self.LastRecordedPath)
             local shared = _MobileShareService:ShareFileAndWait(self.LastRecordedPath)
             if shared then
                 _UIToast:ShowMessage("Share success")
             else
                 _UIToast:ShowMessage("Share Failed")
             end
         end
         end
         end
         



    
    
          
    
    5. **Btn_Share** 버튼을 눌러 녹화한 영상을 공유할 수 있도록 이벤트 핸들러에 `ButtonClickEvent`를 추가합니다.
        이벤트 센더를 아래와 같이 **Entity**로 설정합니다.
        [png](1678757658575e7b78c6fa2f843b2ac8e70e29a8e911d)
          
    
        이후 아래와 같이 내용을 작성합니다.
        ```lua
    @Component
    script ShareVideoHandler extends Component
        @EventSender("Self")
        handler HandleButtonClickEvent(ButtonClickEvent event)
        --------------- Native Event Sender Info ----------------
        -- Sender: ButtonComponent
        -- Space: Client
        ---------------------------------------------------------
    
        -- Parameters
        local Entity = event.Entity
        ---------------------------------------------------------
        self:ShareVideo()
        end
    end
    
    
    
      
    
    

  6. 출시한 뒤 모바일에서 의도한 대로 동작하는지 확인합니다. [Record] 버튼을 눌러 녹화를 시작한 뒤, [Stop] 버튼을 눌러 녹화를 종료하고 [Share] 버튼을 눌러 영상을 공유할 수 있습니다. [gif](167877261209707c7dda7630d4754b846c68e6b21d002)



# 주의사항

  * 마이크가 여러 개라면 사용자에게 마이크 선택권을 제공해야 할 수 있습니다. 그럴 때는 `GetMicrophoneDevicesAndWait()` 함수를 사용해 사용자가 어떤 마이크를 입력할지 선택할 수 있도록 합니다.
  * iOS: 설정 - MapleStoryWorlds - 사진 - 사진만 추가 권한이 있어야 녹화를 진행할 수 있습니다.
  * AOS: Android 10 미만을 실행하는 기기에서는 애플리케이션 정보 - MapleStory Worlds - 저장 공간 권한이 허용되어야 녹화를 진행할 수 있습니다.