스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
사용 중단: 배터리 소비 개선
전원 사용을 제한하고 사용자가 앱의 효율성을 높이도록 하는 방법을 확인하세요. 코드에 네 가지 핵심 변경 사항을 적용하여 앱의 배터리 소모를 줄이는 방법을 보여드리겠습니다. 앱에 다크 모드를 추가하고 OLED 디스플레이의 이점을 활용하며, 보조 애니메이션의 프레임 비율을 감사하고, 백그라운드 데이터 처리를 제한하며, 장기 실행 작업을 늦추는 방법을 알아보세요.
리소스
관련 비디오
WWDC22
WWDC21
WWDC19
-
다운로드
♪ ♪ 안녕하세요 저는 Vaibhav Gautam입니다 소프트웨어 전력팀의 엔지니어죠 앱은 삶을 풍족하게 합니다 하루 내내 중요한 기능을 다양하게 제공하죠 하지만 앱 사용은 대가가 따릅니다 배터리 전력이 소모되죠 따라서 앱의 배터리 수명을 개선하는 것에 관심을 두는 것이 중요합니다 그래야 사용자가 기기와 앱을 오래 쓸 수 있으니까요 우리는 전력 소비를 이해하기 위해 다양한 시스템 요소를 깊이 연구합니다 이 세션은 우리가 발견한 4개의 핵심 조치를 여러분께 공유하여 앱의 배터리 수명을 개선할 수 있도록 하겠습니다 4개의 핵심 조치는 앱의 다크 모드 적용 프레임률 검사 백그라운드 시간의 제한 앱의 작동 지연입니다
먼저 다크 모드에 관해 말씀드리죠 다크 모드는 iOS 13부터 도입됐으며 사용자가 기기 화면을 어둡게 설정하는 걸 허용합니다 다크 모드를 통한 개인화의 이점도 있지만 배터리 수명에도 큰 영향을 주죠
iPhone 13과 13 Pro처럼 OLED 디스플레이를 사용하는 기기는 어두운 콘텐츠가 밝은 콘텐츠보다 전력을 적게 소비하기 때문입니다 OLED 화면은 픽셀 단위로 전력을 소비하는데 어두운 색상은 픽셀을 밝히는데 드는 전력이 적죠 시스템의 모든 요소 중에서 디스플레이가 전력 소비의 주요 원인입니다 통상적인 유스 케이스에서 디스플레이가 배터리 소모의 가장 큰 원인이죠 여러분은 디스플레이의 전력 소모에 영향을 줄 수 있으며 그 방법의 하나가 다크 모드 채택입니다 그러면 우리 팀에서 작업 중인 '푸드 트럭' 앱을 예로 들어 보죠 이 앱의 배경색은 또렷합니다 화면의 공간도 많이 차지하죠 다크 모드로 바꿨을 때 배경색이 라이트 모드에 비해 훨씬 어두워져서 배터리를 많이 절약합니다 이 경우 디스플레이 전력을 70%까지 절약할 수 있죠 이는 엄청난 절약입니다 또한 화면 밝기가 밝을 때는 배터리를 더 많이 절약할 수 있죠 다크 모드를 선호하는 사용자에게 배터리 소모를 막을 수 있는 좋은 기회이며 열부하도 줄일 수 있습니다 다크 모드를 적용하기 전에 앱이 어떤 모습을 바뀌는지 미리 검토하세요 앱의 어떤 요소를 업데이트해야 시스템 UI에 잘 적용될지 살펴보십시오 Xcode 빌드 시 외형 기능으로 쉽게 확인할 수 있습니다
라이트 모드만 지원하는 앱은 하드 코딩된 색상이 있을 수 있죠 Xcode의 동적 색상을 이용하여 배경색, 이미지와 텍스트의 라이트와 다크 모드를 지원하세요 시스템에서 자동으로 정확한 색상 값을 사용하여 모드가 바뀔 때 업데이트합니다
앱의 이미지도 라이트와 다크 모드를 지원해야 하죠 다크 모드 적용에 관해 궁금하신 분은 'iOS에서 다크 모드 적용하기' WWDC 2019 영상을 살펴보세요
앱에 다크 모드를 적용하는 법을 아셨으니 웹 콘텐츠에 다크 모드를 적용하는 것도 생각해 보십시오 사파리는 모든 웹 콘텐츠를 자동으로 어둡게 하지 않으므로 웹 콘텐츠에도 다크 모드를 적용하시기 바랍니다
웹사이트 스타일시트에 color-scheme 속성을 적용하세요
이를 통해 웹페이지의 기본 텍스트와 배경색을 현재 시스템 외형과 표준 양식 컨트롤, 스크롤바에 맞출 수 있죠 다른 시스템의 색상도 라이트와 다크 모드에 따라 색상과 외형이 바뀝니다 스타일시트 변수들을 색상을 참조하는 곳에 사용하세요 그러면 기기가 라이트와 다크 모드를 전환할 때 웹 콘텐츠도 색상을 업데이트합니다 웹페이지 이미지와 다른 미디어도 같은 논리를 적용하여 각 모드에 다른 형식을 적용하십시오 웹 콘텐츠에 다크 모드를 적용하는 것이 궁금하시면 WWDC 2019의 세션인 '웹 콘텐츠에 다크 모드 지원'을 찾아보시기를 바랍니다 전력 소비를 낮추는 다른 방법은 프레임률을 검토하는 거죠 ProMotion 디스플레이가 적용된 기기는 주사율이 전력 소비에 영향을 줍니다 주사율이 높을수록 전력 소모가 많죠 여러분의 앱 내의 애니메이션 프레임률은 디스플레이의 주사율을 결정합니다 앱에서 사용하는 주요 콘텐츠의 프레임률을 파악하십시오 모든 콘텐츠의 프레임률이 높을 필요는 없으니까요 디스플레이의 주사율은 프레임률이 가장 높은 애니메이션에 의해 결정됩니다 부수적인 앱 요소의 주사율이 필요 이상으로 높으면 앱이 예상보다 배터리를 많이 소비할 수 있죠
이번에도 푸드 트럭 앱을 예로 들겠습니다 주요 콘텐츠인 트럭 애니메이션은 초당 30프레임으로 렌더링하죠 트럭 아래에는 '푸드 트럭' 텍스트가 좌우로 움직입니다 이 부수적인 텍스트는 초당 60프레임으로 렌더링하죠 그 결과 화면 전체가 초당 60프레임으로 렌더링합니다 텍스트 애니메이션을 30fps로 바꾸면 전체 화면이 30fps로 렌더링하여 배터리 소모의 20%를 줄일 수 있죠 놀랍습니다 디버그를 통한 프레임률 정보를 더 알고 싶으시면 Instruments를 사용하십시오 CoreAnimation FPS 도구를 사용하여 앱의 시간별 프레임률을 파악할 수 있습니다 먼저 주 사용자 시나리오부터 검토하십시오 예상 범위에서 프레임을 렌더링하는지 알아보려면 화면의 부수적인 요소가 주요소의 프레임률보다 높은지 살펴보세요
iOS의 CoreAnimation에서 제공하는 CADisplayLink를 사용하여 커스텀 애니메이션과 렌더 루핑을 돌리고 있을 수도 있습니다 CADisplayLink는 주사율과 동기화된 타이머죠 여러분 앱의 타이밍 정보를 제공하여 커스텀 그림이 재생 이벤트를 알 수 있게 합니다 앱은 CADisplayLink 객체에 목표 주사율에 관한 정보를 제공하죠 CADisplayLink의 preferredFrameRateRange 설정으로 최소, 최대, 선호 프레임률을 지정하십시오
화면 링크가 시스템에서 감당할 수 있는 수준을 파악하여 선호 수치에 근접한 프레임률을 선택합니다 해당 수치에 맞출 수 없으면 지정한 범위 안에서 머물려고 노력하죠 화면 링크를 구성하려면 목표 및 선택자와 함께 초기화하십시오 제공된 선택자를 이용하여 커스텀 애니메이션을 재생하고 다음에 어떤 영상 프레임을 보여 줄지 계산합니다 화면 링크가 초기화되면 선호 프레임률 범위를 설정하세요 이 예시에서는 선호 프레임률이 30이지만 10~60 사이의 모든 프레임률을 처리할 수 있습니다 마지막으로 화면 링크를 현재 런 루프에 추가하세요
배터리 소비를 고려할 때 주사율을 염두에 두십시오 동적인 주사율을 지원하는 ProMotion 디스플레이 기기에 특히 중요한 사항입니다 Instruments로 앱의 프레임률을 점검하여 앱 출시 전에 문제를 발견하세요 마지막으로 CADisplayLink로 시스템에 정보를 제공하여 앱 내 콘텐츠의 주사율을 제한하십시오
프레임률 최적화에 관해 더 알고 싶으시면 WWDC 2021의 영상인 '가변적 주사율의 디스플레이 최적화'를 참고하세요 이제 여러분의 앱이 백그라운드에서 실행될 때 전력을 아끼는 법을 살펴보죠 사용자가 여러분의 앱에서 다른 앱으로 전환하면 여러분의 앱은 백그라운드 실행 API에 의존하여 백그라운드에서 계속 실행됩니다 백그라운드에서 실행될 때 일반적 서비스인 위치나 오디오를 계속 사용하고 있을 수 있죠 이런 서비스를 오래 실행하면 배터리가 소모되므로 앱이 백그라운드에서 이런 서비스를 실행한다면 특히 더 주의하셔야 합니다 이런 모드를 이용할 때 전력 손실을 줄이는 법을 살펴보죠 위치 서비스는 기기를 계속 깨워 위치를 계속 스트리밍합니다 비록 사용자에게는 앱이 보이지 않지만 백그라운드에서 위치를 계속 스트리밍하면서 필요 이상으로 배터리를 낭비하죠 앱의 백그라운드 위치 세션 런타임에 관해 파악하는 것이 중요합니다 세션이 더는 필요하지 않을 때 앱에서 stopUpdatingLocation()를 호출하여 세션을 멈추십시오 앱을 개발하는 여러 단계에서 예상치 못한 백그라운드 위치 사용을 파악하는 여러 도구가 있습니다 앱을 빌드하고 테스트할 때 Xcode 게이지로 시스템의 에너지 사용량을 알 수 있고 백그라운드 위치 사용량도 알 수 있습니다 출시 전에 앱을 테스트할 때 MetricKit를 이용하여 일일 사용 진단 정보를 수집하세요 iOS 16의 제어 센터에서도 위치 사용량을 파악할 수 있습니다 Xcode 게이지는 CPU, 네트워크, 위치 사용량 등의 시스템 사용량에 관한 정보를 제공하죠 Xcode 게이지의 타임라인은 위치 사용량이 앱에 미치는 에너지 영향을 보여 줍니다 타임라인의 형태로 확인하면 원하는 시점에 위치 런타임이 멈추는지 확인할 수 있죠 Metric Kit를 사용하여 앱을 테스트할 수도 있습니다 cumulativeBackgroundLocationTime 속성을 사용하여 백그라운드에서 위치 서비스를 얼마나 오래 사용했는지 보십시오
iOS 16부터 제어 센터를 통해 어떤 앱이 위치 서비스를 이용하는지 알 수 있습니다 사용자는 위쪽의 텍스트를 탭 하여 위치를 사용하는 앱을 자세하게 볼 수 있죠 이 기능을 이용하여 위치 런타임에 관한 정보를 얻으십시오 예상하지 않은 상황에서 여러분의 앱이 목록에 나타나면 위치 스트리밍 세션이 활성화 중이라는 의미입니다 오디오 세션에도 같은 원칙을 적용할 수 있죠 특정 음악 앱이 오디오 플레이어를 사용하여 일부 파일을 재생하는데 사용자가 재생을 멈췄다고 합시다 그러면 앱은 사운드를 일시 정지하거나 멈추고 오디오 엔진도 일시 정지하거나 멈춰서 유휴 상태에서의 앱 실행을 막아야 하죠 자동 셧다운 모드가 유용한데 AVAudioEngine 클래스의 autoShutdownEnabled 속성을 설정하여 사용할 수 있습니다 이 모드에서 오디오 엔진은 특정 기간 동안 유휴 상태인지 확인하고 감지하죠 유휴 상태 시 엔진이 오디오 하드웨어를 중단합니다 나중에 다른 소스가 다시 활성화되면 동적으로 오디오 하드웨어를 시작하죠 이런 모든 동작이 알아서 진행됩니다 watchOS는 자동 셧다운 모드가 기본으로 동작하죠 사용하지 않을 때 오디오 엔진을 멈춰서 전력을 아끼십시오 백그라운드 런타임을 제한하는 것의 핵심은 시스템에 종료 사실을 통보하는 것입니다 배터리 수명을 개선하는 마지막 방법은 작업 지연이죠 여러분의 앱은 온종일 다양한 일과 데이터를 처리합니다 일부 작업은 사용자가 원할 때 즉시 작동해야 하죠 사용자가 선택한 콘텐츠를 화면에 렌더링하거나 오디오나 영상을 재생하는 작업이 그 예입니다
하지만 머신 러닝 작업이나 애널리틱스 업로드와 백업은 바로 진행하지 않아도 되죠 급하지 않은 작업은 배터리를 충전할 때처럼 더 적당한 시간으로 미루면 배터리를 아낄 수 있고 즉시 수행해야 하는 작업과 동시에 구동하지 않아도 됩니다 이를 달성할 수 있는 3개의 API에 관해 얘기해 보죠 오래 걸리는 작업을 미룰 때는 BGProcessingTask가 좋습니다 자유재량의 URLSession은 네트워킹 작업을 지연하기에 적합하죠 푸시에 우선순위를 줘서 적당한 시점에 푸시를 보낼 수도 있습니다 각 항목을 자세히 살펴보죠 먼저 BGProcessingTask입니다 BGProcessingTask는 오래 걸리는 작업을 기기를 충전하는 시간 등으로 유예하죠 데이터베이스 정화 작업이나 백업 생성, 머신 러닝 훈련 실행에 적합합니다 BGProcessingTaskRequest API로 요청을 만들어 앱 식별자를 제공하면 사용할 수 있죠 작업에 외부 전력이나 네트워크가 필요한지에 관한 정보도 추가로 제공하세요 정보를 제공하면 더 적절한 시간대에 작업을 계획할 수 있습니다 시스템은 적절한 시간대에 앱을 백그라운드에서 실행하여 유예한 작업을 완료하도록 몇 분의 런타임을 제공하죠 다음은 자유재량의 URLSession입니다 앱에서 Background URLSessions를 일반 네트워킹에서 사용할 수도 있죠 Background URLSessions는 자유재량일 때 더 좋습니다 자유재량 플래그의 URLSessions는 시스템으로 네트워크 처리 작업을 넘겨 적절한 시간대에 네트워크 기능을 수행하죠 기기를 충전할 때나 와이파이에 연결됐을 때입니다 자유재량 플래그는 사용자가 주도하지 않은 장시간 네트워킹에 좋은데 텔레메트리 수집이나 TV 시리즈의 다음 편 다운로드 등이 그 예죠 네트워크 작업을 넘김으로써 네트워크 송수신이 끝날 때까지 앱을 실행할 필요가 없습니다 자유재량의 URLSessions를 사용하려면 백그라운드 URL 세션을 설정하고 isDiscretionary를 true로 설정하십시오 더 많은 정보를 제공하면 시스템에서 다운로드 시점을 계획할 수 있습니다 타임아웃 간격을 제공하여 다운로드를 무한으로 시도하다가 배터리가 닳지 않도록 하십시오
미래의 특정 시점까지 데이터의 업로드와 다운로드를 원하지 않으면 가장 빠른 시작 시점을 제공하세요 마지막으로 예상되는 작업량을 제공하여 시스템이 다양한 다운로드 작업 사이에서 부하의 균형을 맞출 수 있게 하십시오
BGProcessingTask와 자유재량의 URL 세션으로 특정 작업의 즉시성을 제어할 수 있는 것처럼 푸시 전달 시점의 즉시성도 다양한 푸시 우선순위로 제어할 수 있습니다 푸시 우선순위는 얼마나 긴급하게 푸시를 전달할지 결정합니다 우선순위가 높은 푸시는 서버가 즉시 기기로 푸시를 전달하여 기기를 깨워 배터리를 소모하게 하죠 우선순위가 낮은 푸시는 서버가 적절한 시점까지 푸시 전달을 미루어 기기가 깨어날 때까지 기다리거나 우선순위가 높은 푸시를 전달할 때까지 기다립니다 기상 경보 등 긴급 메시지에는 우선순위가 높은 푸시가 좋고 미뤄도 상관없는 수동적인 알림 사항은 우선순위가 낮은 푸시에 좋죠 우선순위가 낮은 푸시의 전달을 늦춤으로써 기기가 계속 깨지 않아 배터리를 절약할 수 있습니다 우선순위가 낮은 푸시를 설정하려면 푸시 페이로드에서 apns-priority를 5로 설정하세요 나머지 작업은 서버가 알아서 진행하며 사용자는 배터리를 아낄 수 있어서 좋죠 그러면 마무리로 정리하고 다음 단계를 알아봅시다 앱에 다크 모드 옵션을 제공하세요 사용자가 다크 모드를 선택하면 배터리를 아낄 수 있습니다 애니메이션을 검토하여 적절한 프레임률로 감소할 수 있는지 살펴보세요 작은 애니메이션이 큰 영향을 줄 수 있죠 백그라운드 런타임을 주시하여 작업이 종료됐음을 시스템에 알리십시오 마지막으로 장기간 백그라운드 작업을 기기 충전 시간처럼 적당한 시간대로 미루세요 이 모든 걸 실천한다면 앱의 전력을 낮출 수 있습니다 감사합니다
-
-
8:02 - Create a CADisplayLink
// Create a display link func createDisplayLink() { let displayLink = CADisplayLink(target: self, selector: #selector(step)) // Configure your desired refresh rate by calling preferredFrameRateRange displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 10, maximum: 60, preferred: 30) // then activate your CADisplayLink by adding it to the main runloop. displayLink.add(to: .current, forMode: .defaultRunLoopMode) }
-
16:03 - Discretionary URLSession
// Set up background URL session let config = URLSessionConfiguration.background(withIdentifier: "com.app.attachments") let session = URLSession(configuration: config, delegate: ..., delegateQueue: ...) // Set discretionary config.isDiscretionary = true // Set timeout intervals config.timeoutIntervalForResource = 24 * 60 * 60 config.timeoutIntervalForRequest = 60 // Create request and task var request = URLRequest(url: url) request.addValue("...", forHTTPHeaderField: "...") let task = session.downloadTask(with: request) // Set time window of two hours task.earliestBeginDate = Date(timeIntervalSinceNow: 2 * 60 * 60) // Set workload size task.countOfBytesClientExpectsToSend = 160 task.countOfBytesClientExpectsToReceive = 4096 task.resume()
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.