iOS 10.3 앱 아이콘 동적으로 변경하기

iOS 10.3에 예상치 못한 신규기능중 앱 아이콘을 변경하는 기능이 있습니다. 이번글에서는 이 신규기능을 활용하는 방법과 적용하지 못하는 경우를 적어볼려고 합니다.

MLB At Bat 앱에서 이 기능을 적용했는데요. 자신이 좋아하는 팀 로고로 앱 아이콘을 변경 할 수 있게 했습니다.

앱 아이콘 변경
MLB At Bat 앱 아이콘 변경

이 포스트의 내용은 영상으로도 촬영 했으니 영상도 참고하시면 동작하는 방식을 이해하기 더 쉬우실거에요

기능을 적용하는것은 정말 간단합니다. 우선 기존에 있던 프로젝트에 새로 추가할 앱 아이콘 이미지를 추가합니다. 예시의 경우 [email protected][email protected] 파일을 추가했습니다.

앱 아이콘 추가
앱 아이콘 추가

여기서 이미지를 Assets.xcassets 에 추가하면 안됩니다. 에셋에 추가해서 사용하고 싶어서 시도를 해봤는데 동작하지 않는것을 확인했습니다.

이미지를 추가 했으면 Info.plist 파일에 추가한 아이콘 이미지에 대한 정보를 등록합니다.

Info.plist 파일에 추가할 내용
Info.plist 파일에 추가할 내용

Xcode 의 Property Editor 에서 자동 완성되지 않는 항목들이라 위와 같은 구조로 일일이 입력해줘야 하는 번거로움이 있습니다.

“Icon files (iOS 5)” 키를 추가하고 그 밑에 “CFBundleAlternateIcons”를 “Dicionary” 타입으로 추가합니다. 그리고 나서 앞으로 변경 가능한 앱 아이콘 후보 이름을 적어 주는데요. 위의 경우 “bundang”, “jeongja” 라는 2개의 앱 아이콘 후보를 추가했습니다.

그리고 각각의 앱 아이콘 후보 이름 밑에는 “CFBundleIconFiles” 라는 “Array” 타입의 키를 추가하고 해당 항목 밑에 실제 앱 아이콘 후보의 이미지 파일명을 적으면 됩니다.

여기서 중요한건 실제 추가한 앱의 파일 이름과 소스코드에서 지정할 파일 이름이 달라도 된다는건데요. 위의 경우 실제 추가한 이미지 파일은 [email protected] 인데 이 파일에 해당하는 소스코드에서 참고할 이름은 “jeongja” 입니다.

Info.plist 에 추가한 항목의 XML 소스코드는 다음과 같습니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>CFBundleIcons</key>
   <dict>
     <key>CFBundleAlternateIcons</key>
     <dict>
     <key>bundang</key>
     <dict>
       <key>CFBundleIconFiles</key>
         <array>
           <string>daangn_bundang</string>
           <string>daangn_bundang-72</string>
           <string>daangn_bundang-Small</string>
         </array>
       </dict>
     <key>jeongja</key>
     <dict>
       <key>CFBundleIconFiles</key>
       <array>
         <string>daangn_jeongja</string>
         <string>daangn_jeongja-72</string>
         <string>daangn_jeongja-Small</string>
       </array>
       </dict>
     </dict>
   </dict>
.... 생략

이제 소스코드에서 앱 아이콘을 변경하고자 하는 부분에 아래 코드를 입력합니다

UIApplication.shared.setAlternateIconName("jeongja") { (error) in
    debugPrint("error \(error)")
}

위 코드가 실행되면 앱 아이콘이 변경됩니다. 마지막에 실행되는 코드 블럭은 실행완료후에 호출되는데 error 가 nil 인 경우 성공한것이고 그렇지 않은 경우 변경에 실패한것입니다.

앱 아이콘 변경 확인
앱 아이콘 변경 확인

앱 아이콘 변경코드가 호출되면 위와 같이 사용자에게 알려주는 팝업이 실행되는데요. 이 팝업은 무조건 보여지는 거라 보이지 않도록 할 방법은 없습니다.

앱 아이콘 변경을 하다보면 안되는 경우를 몇가지 발견하게 되는데요.

첫째, 메인스레드에서 코드가 호출되지 않는 경우 앱 아이콘 변경이 되지 않습니다. 메인스레드가 아닌경우 complete 블럭에서 error에 다음과 같은 객체가 전송됩니다.

"Error Domain=NSCocoaErrorDomain Code=3072 \"작업이 취소되었습니다.\""

아이폰 시스템 언어가 영어일 경우 아래 메시지

"Error Domain=NSCocoaErrorDomain Code=3072 \"The operation was cancelled.\""

이때는 메인 스레드에서 실행되도록 다음과 같이 수정합니다.

DispatchQueue.main.async {
  UIApplication.shared.setAlternateIconName("jeongja") { (error) in
    debugPrint("error \(error)")
  }
}

둘째, 앱이 foreground 에서 실행중이지 않을때는 앱 아이콘을 변경할 수 없습니다. 이는 사용자 몰래 앱 아이콘이 변경되는것을 막기위한 조치라고 생각됩니다.

셋째, 에셋으로 이미지 추가가 안되다보니 아이패드를 지원하는 경우 예전에 아이콘 추가하던 방식대로 앱 아이콘 이미지 파일의 이름을 맞춰야합니다. 위의 예시에서 daangn_jeongja-72 라고 하는식으로 뒤에 suffix 를 예전에 하던대로 맞춰야하는거죠. 파일 이름 규칙은 애플문서(App Icons on iPhone, iPad and Apple Watch)를 참고 하세요.

참고자료

게시글의 아마존, iTunes 링크들을 통해 구매를 하시면 제휴(Affiliate) 프로그램에 의해 저에게 일정 금액이 적립될 수 있습니다. ^_____^