Files
jrshikoku/docs/app-icon-system.md

6.2 KiB
Raw Permalink Blame History

アプリアイコンシステム ガイド

アプリのランチャーアイコンをユーザーが好きな車両に変更できる機能の仕組みと、新しいアイコンを追加する手順を説明します。


仕組みの概要

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フロー: LauncherIconSettingssetAlternateAppIcon(id) → OS がアイコン切り替え シェア機能: TrainIconUpdateViewShot でキャプチャ → 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 の命名規則:

  • 既存の命名パターン(車両形式番号 + 塗装識別子)に倣う
  • 先頭文字は数字か大文字英字にすることw741W741 のように) → iOS の xcassets がエントリを生成しないため(小文字始まりは NG
  • ハイフン - はそのまま使える(例: 2000-3)。アンダースコア _ も使える

idapp.jsonname と完全一致させること。

ステップ 3: app.json に登録

app.jsonexpo.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上の列車位置アイコン別システム。アプリアイコンとは無関係