【iOS】アプリアイコンをさくっと作成する方法

アプリのアイコンが付いていないとコードを書く気が出ないという時ってありますよね。そんなときに、とりあえずそれっぽいアイコンをさくっく作成する方法のご紹介です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/56872699-0a53-3405-3b02-c2de0b0d4fcd.png)
↑ やる気がでないやつ

:::note info
Android版のアイコン作成アプリもつくってみました。(2023/10/9)
https://qiita.com/yuppejp/items/353d312492681c8244a8
:::

# アプリアイコンの作成の流れ
1. アイコン画像を表示するViewの作成
1. Viewのスナップショットをファイルに保存(1024x1024ピクセル、透過PNG)
1. 画像ファイルをXcodeのAppIconアセットに設定

## アイコン画像を表示するViewの作成
[SF Symboles](https://developer.apple.com/jp/sf-symbols/)を使って適当なアイコンをViewに表示して、背景色にグラデーションをかけるだけです。背景色にグラデーションを付けるのはiOS16から使えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/f179542b-02fe-4a54-2b8b-68574bd0179d.png)

```swift:AppIconView.swift
struct AppIconView: View {
    var systemName: String  // SF Symbolsの名前
    var color: AnyGradient  // グラデーションカラー(iOS16〜)
    
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Rectangle()
                    .fill(color)
                Image(systemName: systemName)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .foregroundColor(.white)
                    .padding(geometry.size.width * 0.15) // 余白を多めにとる(全体の15%程度)
            }
        }
    }
}

#Preview {
    VStack {
        AppIconView(systemName: "pencil.and.outline", color: Color.orange.gradient)
            .frame(width: 150, height: 150)
        AppIconView(systemName: "tram", color: Color.green.gradient)
            .frame(width: 150, height: 150)
        AppIconView(systemName: "sailboat.fill", color: Color.blue.gradient)
            .frame(width: 150, height: 150)
    }
}
```

## Viewのスナップショットをファイルに保存
ファイル保存用のボタンを設置し、UIViewControllerに拡張したsnapshotメソッドでレンダリングします。このとき背景透過になるようにbackgroundColorを .clear に設定します。画像ファイルはカメラロールに保存されます（シミュレーター時のファイルパスは後述）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/fbe2385b-64a3-3f37-76ca-f6f935cb8283.png" width="300">

アイコンや色を変えるUIは今回用意していなので、コード上のiconNameとiconColorを直接書き換えてください。

```swift:ContentView.swift
import SwiftUI
import Photos

struct ContentView: View {
    var iconName = "pencil.and.outline"
    var iconColor = Color.orange.gradient
    @State private var showAlert = false
    @State private var alertMessage = ""
    
    var body: some View {
        VStack {
            Spacer()
            AppIconView(systemName: iconName, color: iconColor)
                .frame(width: 300, height: 300)
            Text(iconName)
            Spacer()
            Button("Save Image") {
                saveToPhotos()
            }
        }
        .alert(isPresented: $showAlert) {
            Alert(title: Text("Result"), message: Text(alertMessage), dismissButton: .default(Text("OK")))
        }
    }
    
    private func saveToPhotos() {
        DispatchQueue.main.async {
            let viewSize = CGSize(width: 1024, height: 1024)
            
            let hostingController = UIHostingController(
                rootView: AppIconView(systemName: iconName, color: iconColor)
                    .frame(width: viewSize.width, height: viewSize.height)
                    .offset(CGSize(width: 0, height: -12))
                    .background(iconColor)
            )
            
            hostingController.view.frame = CGRect(origin: .zero, size: viewSize)
            hostingController.view.backgroundColor = .clear
            
            let image = hostingController.snapshot(viewSize: viewSize)
            
            // PNGとしてカメラロールに保存
            if let data = image.pngData() {
                PHPhotoLibrary.shared().performChanges({
                    let creationRequest = PHAssetCreationRequest.forAsset()
                    creationRequest.addResource(with: .photo, data: data, options: nil)
                }) { success, error in
                    if let error = error {
                        alertMessage = "Error saving the image: \(error)"
                        showAlert = true
                    } else {
                        alertMessage = "Success saving image"
                        showAlert = true
                    }
                }
            }
        }
    }
}

extension UIViewController {
    func snapshot(viewSize: CGSize) -> UIImage {
        let rendererFormat = UIGraphicsImageRendererFormat.default()
        rendererFormat.scale = 1
        let renderer = UIGraphicsImageRenderer(size: viewSize, format: rendererFormat)
        
        let image = renderer.image { _ in
            let context = UIGraphicsGetCurrentContext()!
            context.interpolationQuality = .high
            view.drawHierarchy(in: CGRect(origin: .zero, size: viewSize), afterScreenUpdates: true)
        }
        
        return image
    }
}

#Preview {
    ContentView()
}
```

## シミュレーターで実行している場合の保存場所
XcodeのiOSエミュレータでアプリを実行すると、アプリの画像ファイルはMac上の特定のディレクトリに保存されます。エミュレータの内部ファイルシステムにアクセスするには、以下のディレクトリパスをFinderで参照することができます：

> ~/Library/Developer/CoreSimulator/Devices/[DEVICE_ID]/data/Media/DCIM/100APPLE/

ここの、[DEVICE_ID]は実行中のエミュレータデバイスの一意のIDです。
DEVICE_IDを調べる手順：
1. Xcodeの"Window" メニューから "Devices and Simulators" を選択します。
2. 左側のペインで実行中のシミュレータデバイスを選択します。
3. 右ペインの上部に表示されるIdentifierがデバイスIDです。
![貼り付けた画像_2023_10_09_12_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/7ab7e959-44ce-bcb4-28b6-506d564984a1.png)
Finderで表示した例:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/79c43b21-2932-4097-d3bc-4eea4b03d789.png)
IMG_nnnn.PNGという感じでファイルが作成されます。


## 画像ファイルをXcodeのAppIconアセットに設定
拡張子が大文字だとXcodeが警告してくるので、小文字の .png に変更しておきます。あとはXcodeのAppIconアセットに画像ファイルをDrang&Dropしたら完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/635094f1-0ffa-0260-cbd7-0144de95f199.png)

# 完成サンプル
いい感じにできました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/5d3cab59-3e9d-cf22-7a30-7c1144d3a0e9.png)

おしまい！

## サンプルコード一式
https://github.com/yuppejp/IconMaker-iOS

## Android版はこちら
[【Android】アプリアイコンをさくっと作成する方法](https://qiita.com/yuppejp/items/353d312492681c8244a8)

https://github.com/yuppejp/IconMaker-Android