アイコンの PNG を6枚並べて、どれが弾かれるのかを確かめたことがあります。背景を塗った1024px の画像と、角を丸くした画像と、グレースケールの画像と、ほんの少し色数を減らした画像と。並べてみると、どれも「透けて」はいません。
それでも App Store Connect の検証は、次のような文言を返すことがあります。
ITMS-90717: Invalid large app icon. The large app icon in the asset catalog in "___.app" can't be transparent or contain an alpha channel.「透過してはいけない」と「alpha チャンネルを含んではいけない」は、似ているようで別の条件です。その差を手元のサンプルで確かめ、提出前に PNG の中身を検査する方法を書き残します。
最初にお伝えしたいのは、目で見て不透明に見える画像は、安全の根拠にならないということです。
症状の見分け方:どこに、どんな文言で出るか
ITMS-90717 は、ビルドをアップロードしたときの検証、または処理のあとに届く連絡で目にします。文言の中心は「can't be transparent or contain an alpha channel」です。
同じ種類のつまずきが、別の文言で出ることもあります。入口として、次の表で自分のメッセージがどれに近いかを見てください。
| 見えているメッセージ | この記事で扱うか | まず疑う場所 |
|---|---|---|
| Invalid large app icon … can't be transparent or contain an alpha channel | 扱います | 1024px アイコンの PNG(alpha の有無) |
| ビルドが「処理中」のまま動かない | 別記事です | 処理待ち・ビルド番号・メール |
| アイコンを変えたのに古い絵が出る | 別の症状です | キャッシュ・アセットの置き換え漏れ |
| Android の通知アイコンが白い四角になる | 別の症状です | 通知用の単色アイコンの作り |
「処理中のまま」と迷った方は、ビルドが処理中のまま止まったときの切り分けを先にご覧ください。
まず、条件を読み違えていました
Expo の公式ドキュメントには、iOS のアイコンは正方形いっぱいに塗り、角丸や透明なピクセルを含めないこと、と書かれています。OS 側が必要に応じて角を丸く切るので、自分で丸める必要はありません。
私は長いあいだ、この一文を「見た目で透けていなければよい」と読んでおりました。ここが読み違いでした。エラー文は「透明であってはならない」に加えて「alpha チャンネルを含んではならない」と、わざわざ二つ並べています。
画像のピクセルがすべて不透明でも、ファイルの形式が RGBA のままなら、alpha チャンネルは存在します。見た目では区別がつきません。
手元で確かめた:6種類のサンプル
1024px のサンプルを6枚作り、PNG の先頭にある IHDR というヘッダを読んで、色の持ち方を調べました。使ったのは Python 3 の標準ライブラリだけです。
| サンプル | 見た目 | 検査結果 |
|---|---|---|
| RGB(alpha なし) | 不透明 | 通過 |
| RGBA、全ピクセルが不透明 | 不透明(RGB と見分けがつかない) | 要対応:alpha チャンネルあり |
| RGBA、四隅を角丸で透明に | 四隅が透ける | 要対応:alpha チャンネルあり |
| グレー+alpha | 不透明 | 要対応:alpha チャンネルあり |
| パレット PNG+透過情報 | 不透明に見える | 要対応:tRNS あり |
| RGB だが 1000×1000 | 不透明 | 要対応:サイズ違い |
二行目が、この記事の中心です。全ピクセルの alpha の最小値と最大値を見ると、どちらも 255 でした。つまり一つも透けていません。それでもファイルは RGBA で、alpha チャンネルを持っています。
なお、この検査が確かめているのは「ファイルの中身」までです。この6枚を実際に App Store Connect へ提出して、受け付けられるかを確かめたわけではありません。Apple 側の判定は、エラー文の記述と、公開されているフォーラムの報告を根拠にしています。
原因の切り分け順
次の順に確かめると、遠回りが少なくなります。
- 書き出した PNG が RGBA になっていないか。 デザインツールの書き出しは、RGBA が既定のものが多いです。背景を塗っていても、alpha チャンネルは残ります。
- 角丸を焼き込んでいないか。 四隅が透明になります。丸めるのは OS の仕事なので、正方形のまま渡します。
- サイズが 1024×1024 か。 1000px や 1024×1023 のような、わずかなずれがあとから見つかります。
- Icon Composer の
.iconを使っていないか。 Apple の開発者フォーラムには、Xcode 26 のベータ期に、Icon Composer のアイコンから生成された PNG に alpha が入る、という報告が複数ありました。あるグループの Blur を有効にし、そのグループのSVG がキャンバスの端に近いときに起きた、と書いた方もいます。Apple の担当者は調査中と答えており、時期によって再現したりしなかったりしたようです。 - ビルド成果物が古くないか。 画像を直したのに同じエラーが出るなら、古いアセットが使われている可能性を疑います。
1番から3番は、ファイル一枚で確かめられます。4番は、書き出し元のツール側の事情です。
検査スクリプト
1枚でも複数枚でも渡せる、標準ライブラリだけのスクリプトです。PNG のヘッダだけを読むので、画像を開く必要はありません。
#!/usr/bin/env python3
"""App Store 用アイコン PNG を提出前に検査する(標準ライブラリだけ)。
使い方: python3 icon_alpha_check.py icon.png [more.png ...]
終了コード: 0=全て通過 / 1=1つでも要対応
"""
import struct, sys
COLOR = {0: "グレー", 2: "RGB", 3: "パレット", 4: "グレー+alpha", 6: "RGBA"}
def inspect(path):
with open(path, "rb") as f:
data = f.read()
if data[:8] != b"\x89PNG\r\n\x1a\n":
return None, ["PNG ではありません"]
pos, width, height, ctype, has_trns = 8, 0, 0, -1, False
while pos + 8 <= len(data):
length, kind = struct.unpack(">I4s", data[pos:pos + 8])
body = data[pos + 8:pos + 8 + length]
if kind == b"IHDR":
width, height, _depth, ctype = struct.unpack(">IIBB", body[:10])
elif kind == b"tRNS":
has_trns = True
pos += 12 + length
problems = []
if (width, height) != (1024, 1024):
problems.append(f"サイズが {width}x{height}(1024x1024 が必要)")
if ctype in (4, 6):
problems.append(f"alpha チャンネルあり({COLOR[ctype]})")
if ctype == 3 and has_trns:
problems.append("パレット PNG に透過情報(tRNS)あり")
return (width, height, COLOR.get(ctype, str(ctype))), problems
def main(paths):
bad = 0
for p in paths:
info, problems = inspect(p)
if problems:
bad += 1
print(f"NG {p}: " + " / ".join(problems))
else:
print(f"OK {p}: {info[0]}x{info[1]} {info[2]}")
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]) if len(sys.argv) > 1 else 2)手元で動かすと、6枚の結果は次のようになりました。
OK a_rgb.png: 1024x1024 RGB
NG b_rgba_opaque.png: alpha チャンネルあり(RGBA)
NG c_rgba_rounded.png: alpha チャンネルあり(RGBA)
NG d_la.png: alpha チャンネルあり(グレー+alpha)
NG e_palette_trns.png: パレット PNG に透過情報(tRNS)あり
NG f_rgb_1000.png: サイズが 1000x1000(1024x1024 が必要)終了コードを返すので、提出の直前に走らせる手順へそのまま組み込めます。1枚でも NG なら、アップロードに進まない、という線引きです。
直し方:alpha を外して、RGB で保存し直す
alpha を外すときは、透明な部分を何色で埋めるかを先に決めます。角丸を焼き込んでいた画像は、四隅が透明なので、背景色で塗りつぶす必要があります。
#!/usr/bin/env python3
"""alpha を取り除いた RGB の PNG を書き出す。
使い方: python3 icon_flatten.py in.png out.png [#RRGGBB]
"""
import sys
from PIL import Image # pip install pillow
src, dst = sys.argv[1], sys.argv[2]
bg = sys.argv[3] if len(sys.argv) > 3 else "#FFFFFF"
bg_rgb = tuple(int(bg.lstrip("#")[i:i + 2], 16) for i in (0, 2, 4))
im = Image.open(src).convert("RGBA")
flat = Image.new("RGB", im.size, bg_rgb)
flat.paste(im, mask=im.getchannel("A"))
flat.save(dst, "PNG")
print(f"{dst}: {flat.mode} {flat.size}")不透明な RGBA(2行目のサンプル)を通すと、元の RGB のサンプルと1ピクセルも違わない画像になりました。差分を取ると、差のある範囲が空(None)で返ります。見た目は変えずに、alpha だけを外せたことになります。
角丸のサンプルは、四隅が背景色で埋まった正方形になります。OS が自分で角を丸めるので、見た目で困ることはありません。
ImageMagick をお使いなら、次の一行でも同じことができます。
convert icon.png -background "#FAFAFA" -alpha remove -alpha off PNG24:icon_fixed.pngここで一つ、私が踏んだところがあります。最初は PNG24: を付けずに実行しました。出力は alpha こそ消えていたものの、パレット形式(256色以下の索引色)の PNG になっていました。グラデーションの多いアイコンでは、色が荒れる原因になりえます。PNG24: を付けると、RGB の PNG で書き出されました。
直らないときの次の一手
スクリプトが OK を返したのに、同じエラーが続く場合は、次の順に見てください。
- アップロードしたのが直した PNG ではなく、古いビルドのままになっていないか。ビルド番号を上げて、出し直します。
- アセットカタログの中に、1024px 用の PNG が複数入っていないか。古いほうが検査されていることがあります。
- Icon Composer の
.iconを使っているなら、Blur を切る、従来の PNG 方式に戻す、書き出した PNG から alpha を外す、のいずれかがフォーラムで報告されています。ただし、どれも見た目の効果を手放す対応です。時期によって再現が揺れていた経緯もあるため、最新の Xcode で再現するかを先に確かめるほうが、遠回りになりません。
Rork から書き出したプロジェクトの、アイコン設定の画面や書き出し時の挙動は、この記事の範囲では確かめておりません。画面の名前や場所は、ご自身の環境でお確かめください。
提出前の習慣にします
透けているかは目で、alpha があるかはバイトで確かめます。 提出の直前に、この線引きだけは守るようにしています。
個人開発の更新作業は、アイコンを触る日と提出する日が離れがちです。数日前に書き出した画像を、提出の日に目で見て「大丈夫そう」で済ませてしまいがちです。気づいたのは、その「目で見る」確認がいちばん信用できない、ということでした。そこを、数秒で終わるスクリプトに任せるようにしました。
アイコンの次に、提出前に一つ確かめておきたいのは、秘密の値がアプリの中に入っていないかどうかです。EAS の secret と公開変数の見え方を二つの軸で整理した記事にまとめましたので、続けてご覧いただければ幸いです。
まずは、いま手元にある 1024px の PNG を1枚、icon_alpha_check.py に渡すところから始めてみてください。