6.2 KiB
アプリアイコンシステム ガイド
アプリのランチャーアイコンをユーザーが好きな車両に変更できる機能の仕組みと、新しいアイコンを追加する手順を説明します。
仕組みの概要
expo-alternate-app-icons を使って複数のアプリアイコンを事前に登録しており、実行時に setAlternateAppIcon(id) で切り替えます。
assets/icons/ ← PNG画像の置き場(後述の規格に合わせること)
assets/icons/icons.ts ← UIに表示するアイコン一覧の定義
app.json ← ネイティブビルドへの登録(expo-alternate-app-icons)
ios/JR/Images.xcassets/ ← prebuildで自動生成(手動変更不要)
android/.../AndroidManifest.xml ← 同上
UIフロー: LauncherIconSettings → setAlternateAppIcon(id) → OS がアイコン切り替え
シェア機能: TrainIconUpdate → ViewShot でキャプチャ → expo-sharing で共有
PNG画像の規格
すべての画像は以下の規格に揃えること。 規格が揃っていないと選択画面でサイズがバラバラになる。
| 項目 | 値 |
|---|---|
| キャンバスサイズ | 1024 × 1024 px |
| 背景 | 透明(alpha あり) |
| コンテンツ領域 | 570 × 705 px(横長車両)または 570 × 720 px(縦長・高背車両) |
| コンテンツの位置 | キャンバス中央(左右 227px 余白) |
storage.haruk.in から取得できる画像は 40 × 48 px の小さい素材なので、そのままでは使えない。後述の変換手順が必要。
変換コマンド(新素材を規格に合わせる)
cd assets/icons
convert input.png \
-trim +repage \
-resize 570x720 \
-background none \
-gravity center \
-extent 1024x1024 \
output.png
-trim +repage: 透明余白を除去-resize 570x720: アスペクト比を保ちつつ最大 570×720 に拡大(横長車両は自動的に 570×705 になる)-gravity center -extent 1024x1024: 1024×1024 の透明キャンバスの中央に配置
複数ファイルをまとめて処理する場合
cd assets/icons
for f in ファイル1.png ファイル2.png ...; do
convert "$f" -trim +repage -resize 570x720 -background none -gravity center -extent 1024x1024 "$f"
done
アイコン追加手順
ステップ 1: 画像を取得して assets/icons/ に配置
storage.haruk.in にある画像ファイル名は、unitList ページ(https://jr-shikoku-data-system.pages.dev/unitList)の API レスポンスや lib/webview/trainIconMap.ts を参照して確認する。
cd assets/icons
curl -O https://storage.haruk.in/ファイル名.png
取得後、上記の変換コマンドで 1024×1024 に変換する。
ステップ 2: icons.ts にエントリを追加
assets/icons/icons.ts の配列に追加する:
{ "id": "識別子", "name": "表示名(日本語)", "icon": require("./ファイル名.png") },
id の命名規則:
- 既存の命名パターン(車両形式番号 + 塗装識別子)に倣う
- 先頭文字は数字か大文字英字にすること(
w741→W741のように) → iOS の xcassets がエントリを生成しないため(小文字始まりは NG) - ハイフン
-はそのまま使える(例:2000-3)。アンダースコア_も使える
id は app.json の name と完全一致させること。
ステップ 3: app.json に登録
app.json の expo.plugins 内にある expo-alternate-app-icons の配列に追加する:
{
"name": "ステップ2と同じid",
"ios": "./assets/icons/ファイル名.png",
"android": {
"foregroundImage": "./assets/icons/ファイル名.png",
"backgroundColor": "#001413"
}
}
backgroundColor は全アイコン共通で #001413(アプリのテーマカラー)。
ステップ 4: expo prebuild を実行
npx expo prebuild --no-install
これにより以下が自動生成される:
- iOS:
ios/JR/Images.xcassets/<id>.appiconset/ - Android:
AndroidManifest.xmlへのactivity-alias追加 + mipmap リソース生成
@bacons/apple-targets 由来の withIosXcodeProjectBeta2BaseMod: Cannot read properties of undefined というエラーが出ることがあるが、アイコン関連のファイルは生成されているので無視してよい。 これは JRWidget ターゲットの既知の問題。
ステップ 5: 確認
# iOS xcassets に追加されているか
ls ios/JR/Images.xcassets/ | grep <id>
# Android Manifest に追加されているか
grep "<id>" android/app/src/main/AndroidManifest.xml
# Android mipmap リソースが生成されているか
ls android/app/src/main/res/mipmap-hdpi/ | grep <id>
一括確認スクリプト(app.json と xcassets の整合性チェック)
python3 -c "
import json, os
with open('app.json') as f:
data = json.load(f)
plugins = data['expo']['plugins']
idx = next(i for i, p in enumerate(plugins) if isinstance(p, list) and p[0] == 'expo-alternate-app-icons')
names = {e['name'] for e in plugins[idx][1]}
xcassets = set()
base = 'ios/JR/Images.xcassets/'
for d in os.listdir(base):
if d.endswith('.appiconset') and d != 'AppIcon.appiconset':
xcassets.add(d.replace('.appiconset', ''))
missing = names - xcassets
print(f'app.json: {len(names)}, xcassets: {len(xcassets)}')
print('Missing from xcassets:', sorted(missing) if missing else 'none')
"
関連ファイル一覧
| ファイル | 役割 |
|---|---|
assets/icons/icons.ts |
UI に表示するアイコン一覧。ここに無いものはアイコン変更画面に出てこない |
assets/icons/*.png |
1024×1024 の PNG 画像(規格に合わせること) |
app.json |
expo-alternate-app-icons プラグイン設定。prebuild のソース |
components/ActionSheetComponents/LauncherIconSettings.tsx |
アイコン変更 UI。setAlternateAppIcon(id) を呼ぶ |
components/ActionSheetComponents/TrainIconUpdate.tsx |
変更後の確認 + シェア UI |
lib/webview/trainIconMap.ts |
地図WebView上の列車位置アイコン(別システム。アプリアイコンとは無関係) |