[iOS] - 코드로 앱 아이콘 이미지 변경하기

sun02·2024년 12월 20일
0

iOS

목록 보기
28/28

앱의 아이콘 이미지를 코드로 변경하는 방법에 대해 작성합니다.


요즘 크리스마스와 같은 특정 시즌에만 앱 아이콘 이미지를 변경하는 경우가 많습니다.
날짜에 맞춰 앱을 업데이트할 수 있다면 가장 좋겠지만,
현실적으로 어려우니 코드로 특정 시기에만 특정 이미지를 적용하는 방법에 대해 작성해보겠습니다.


목차

  1. 앱 아이콘 이미지 추가하기
  2. Info.plist에 이미지 파일명 추가하기
  3. 코드로 이미지 변경하기
  4. 팝업창을 띄우지 않고 이미지 변경하기


1. 앱 아이콘 이미지 추가하기

먼저 일반적으로 사용할 앱 아이콘(appIcon)과,
특정 시기에만 사용할 앱 아이콘(specialIcon)을 png 파일로 Asset이 아닌 내부 파일로 추가해줍니다.

  • 각 아이콘 별로 두 가지 사이즈의 이미지를 준비합니다.
    • @2x = 120x120(픽셀)
    • @3x = 180x180(픽셀)
  • 해당 이미지들은 참조 형식이 아니라, 복사 형식으로 Xcode 내에 추가되어야합니다.
    • 이미지의 경로가 앱 파일 내여야하고, target이 해당 앱으로 되어있는지 확인합니다.


2. Info.plist에 이미지 파일명 추가하기

Info.plist에 사용하고자 하는 앱 아이콘들을 아래와 같이 작성해줍니다.

  • PrimaryIcon: 일반적으로 사용하는 앱아이콘
    • Icon files 하위에 앱 아이콘 이미지의 실제 파일 명(appIcon)을 작성합니다.
  • CFBundleAlternateIcons: 특정 시기에 사용해줄 앱 아이콘
    • XmasAppIcon: 앱 아이콘 이미지를 코드상에서 호출할 때 사용할 네이밍
      • CFBundleIconFiles 하위에는 XmasAppIcon을 호출했을 때 적용되었으면 하는 앱 아이콘 이미지의 실제 파일 명(specialIcon)

적용에 어려움이 있다면 아래의 Info.plist 코드를 참고해주세요.

<key>CFBundleIcons</key>
	<dict>
		<key>CFBundlePrimaryIcon</key>
		<dict>
			<key>CFBundleIconFiles</key>
			<array>
				<string>appIcon</string>
			</array>
			<key>UIPrerenderedIcon</key>
			<false/>
		</dict>
		<key>CFBundleAlternateIcons</key>
		<dict>
			<key>XmasAppIcon</key>
			<dict>
				<key>CFBundleIconFiles</key>
				<array>
					<string>specialIcon</string>
				</array>
				<key>UIPrerenderedIcon</key>
				<false/>
			</dict>
			<key>AppIcon</key>
			<dict>
				<key>CFBundleIconFiles</key>
				<array>
					<string>appIcon</string>
				</array>
				<key>UIPrerenderedIcon</key>
				<false/>
			</dict>
		</dict>
	</dict>


3. 코드로 이미지 변경하기

UIApplication.shared.setAlternateIconName("XmasAppIcon")
  • 위와 같이 CFBundleAlternateIcons에 작성해 준 코드상에서 호출할 때 사용할 네이밍을 넣어주면 앱 아이콘이 변경됩니다.
UIApplication.shared.setAlternateIconName(nil) 
  • 혹시 기본 앱 아이콘으로 다시 변경하고 싶다면 이렇게 nil 값을 넣어주면 됩니다.

3-1. 앱 아이콘이 변경되지 않는 경우

그런데, 저는 위 과정을 모두 따라해도 앱 아이콘이 변경되지 않았습니다. 🥲

여러가지 방법을 적용해보았는데 가장 먼저, 현재 앱 아이콘을 변경할 수 있는 상태인지를 확인해야합니다.

UIApplication.shared.supportsAlternateIcons
  • 위 API를 사용하면 해당 상황에서 앱 아이콘 변경이 가능한지를 알 수 있습니다.
  • false가 반환된다면 앱 아이콘 변경이 불가합니다.

일반적으로 구글링을 통해 발견되는 원인은 아래 두 가지 인데

  • 앱 아이콘 이미지가 copy 방식으로 앱 파일 내에 들어가지 않거나, 이미지 경로가 앱 파일 내가 아닌 경우
  • Info.plist 설정이 정확하지 않은 경우

두 가지 모두 아니라면 이 것이 원인일 수도 있습니다.

  • 앱 아이콘 변경 코드가 사용되는 시기가 너무 빠른(?) 경우

저의 경우 SwiftUI로 앱을 개발하고 있었고 App 파일의 onAppear 시기에 앱 아이콘 변경을 시도하고 있었던 것이 원인이였습니다.

그 다음 나타나는 View의 onAppear에서 앱 아이콘 변경을 시도하니 제대로 동작하였습니다 🎉!



4. 팝업 창을 띄우지 않고 이미지 변경하기

그런데, 앱 아이콘은 변경되는건 좋은데 팝업까지는 조금 거창하다고 (저는) 생각했어요.

그래서 이 팝업창 띄우지 않고 앱 아이콘을 바꾸고자 한다면 아래 코드를 사용하면 됩니다.

func setIconWithoutAlert(_ appIconName: String) {
        if let alternateIconName = UIApplication.shared.alternateIconName {
            if alternateIconName == appIconName {
                return
            }
        }
                
        if UIApplication.shared.responds(to: #selector(getter: UIApplication.supportsAlternateIcons)) && UIApplication.shared.supportsAlternateIcons {
            typealias setAlternateIconName = @convention(c) (NSObject, Selector, NSString, @escaping (NSError) -> ()) -> ()
            let selectorString = "_setAlternateIconName:completionHandler:"
            let selector = NSSelectorFromString(selectorString)
            let imp = UIApplication.shared.method(for: selector)
            let method = unsafeBitCast(imp, to: setAlternateIconName.self)
            method(UIApplication.shared, selector, appIconName  as NSString, { _ in })
        } else {
        }
    }
  • UIApplication.shared.alternateIconName은 현재 적용되어있는 앱 아이콘 이름을 반환해줍니다.

따라서, 이름이 동일하면 바꾸지 않고 return 하고 동일하다면 바꿔줍니다.

한 가지 문제는, 여기서 unsafeBitCast가 apple에서 공식적으로 지원하는 함수는 아닌 것 같더라구요. 그래서 잘 판단해서 사용해야할 듯 싶습니다.


4-1. setIconWithoutAlert 사용하기

func changeAppIcon() {
	if isChristmas() {
    	setIconWithoutAlert("XmasAppIcon")
    } else {
        setIconWithoutAlert("AppIcon")
    }
}

요렇게 사용하면 됩니다.

  • setIconWithoutAlert에서는 nil값을 넣을 수가 없어서, 이렇게 팝업이 없는 형태로 앱 아이콘을 변경해주고자 한다면 2번의 CFBundleAlternateIcons에서 AppIcon도 작성해줘야합니다.
    • 팝업을 띄우는 형태로 진행할거라면 작성하지 않아도 됩니당.

0개의 댓글