Airaw Widget API

The Airaw Widget API is a JavaScript bridge that allows HTML widgets displayed on CarPlay to retrieve real-time iOS system data — battery, network, music, weather, and more.

Airaw Widget API は、CarPlay 上に表示される HTML ウィジェットが iOS システム情報(バッテリー・ネットワーク・音楽・天気など)を リアルタイムで取得するための JavaScript ブリッジです。

Communication is bidirectional. The widget requests data via WKScriptMessageHandler (airawAction) — or the injected helper airawRequest(method) — which avoids touching window.location. The legacy arapi: URL scheme is still supported for compatibility. Airaw responds by injecting global variables and calling mainUpdate(type).

通信は双方向です。データ要求は WKScriptMessageHandlerairawAction)、または注入済みの airawRequest(method) を推奨します(window.location を汚しません)。 互換のため従来の arapi: URL スキームも利用できます。 Airaw がグローバル変数を注入した上で mainUpdate(type) を呼び出します。

💡 Platform Support対応プラットフォーム

iOS 14 / 15 / 16 / 17. Only active when CarPlay is connected.
Designed for rootless jailbreak environments (Dopamine / palera1n).

iOS 14 / 15 / 16 / 17 対応(CarPlay 接続時のみ動作)。
Rootless jailbreak(Dopamine / palera1n)環境下での動作を想定しています。

Architectureアーキテクチャ

The data flow between the widget and Airaw is shown below.

Widget ↔ Airaw 間のデータフローを示します。

HTML Widget
── airawRequest('arcall_Battery') ──→
Airaw Tweak
HTML Widget
←── JS injection + mainUpdate('battery') ────
Airaw Tweak
Airaw Tweak
── private API hooks ──→
iOS SpringBoard

Communication Model通信モデル

Direction方向 Mechanism手段 Description説明
Widget → Airaw postMessage / airawRequest Recommended. window.webkit.messageHandlers.airawAction.postMessage({ action: 'requestData', method: 'arcall_Battery' }), or airawRequest('arcall_Battery') injected by Airaw (falls back to arapi: only when the handler is unavailable). 推奨。 window.webkit.messageHandlers.airawAction.postMessage({ action: 'requestData', method: 'arcall_Battery' })、または Airaw が注入する airawRequest('arcall_Battery')(ハンドラが無い場合のみ arapi: にフォールバック)。
Widget → Airaw arapi: URL scheme Legacy. Assign window.location = 'arapi:arcall_Battery'; Airaw intercepts navigation. Prefer postMessage to avoid history / SPA side-effects. レガシー。 window.location = 'arapi:…' でナビゲーションをインターセプト。履歴や SPA への影響を避けるなら postMessage を推奨。
Airaw → Widget Direct JS evaluationJS 文字列の直接評価 Declares global variables with var xxx = ..., then calls mainUpdate(type). グローバル変数を var xxx = ... で宣言後、mainUpdate(type) を呼び出します。

Quick Startクイックスタート

Minimal widget implementation example.

最小構成のウィジェット実装例です。

<!-- Request all data on page load -->
<script>
window.addEventListener('load', function() {
  // Recommended: injected helper (uses postMessage internally)
  airawRequest('arcall_all');
  // Legacy: window.location = 'arapi:arcall_all';
});

// Airaw calls this after injecting variables
function mainUpdate(type) {
  if (type === 'battery') {
    document.getElementById('bat').textContent = batteryPercent + '%';
  }
  if (type === 'weather') {
    document.getElementById('temp').textContent = weather.temperature + '°C';
  }
}
</script>
⚠️ Do not rename mainUpdate関数名を変更しないこと

The function name mainUpdate is hardcoded in Airaw. It cannot be renamed.

mainUpdate という関数名は Airaw が固定で呼び出します。この名前は変更できません。

Widget Options (airaw-widget-schema.json)ウィジェットオプション(airaw-widget-schema.json

Place a schema file named airaw-widget-schema.json in the same folder as your widget HTML. Airaw reads it to build a settings UI and injects the merged values into the WebView as window.AIRAW_WIDGET_OPTIONS. User overrides are persisted under /var/jb/Library/Airaw/WidgetOptions/ on rootless setups (path may vary by jailbreak).

ウィジェットの HTML と同じフォルダairaw-widget-schema.json を置きます。 Airaw がスキーマを読み取り設定画面を生成し、マージ結果を WebView に window.AIRAW_WIDGET_OPTIONS として注入します。 ユーザーが変更した値は rootless 環境では /var/jb/Library/Airaw/WidgetOptions/ 以下に保存されます(JB により実パスは異なる場合があります)。

Schema shapeスキーマの形

Top-level keys such as widgetId / version are optional metadata for authors. Airaw uses the properties object to generate prefs cells and defaults.

ルートの widgetIdversion は作者向けメタデータとして任意です。 設定 UI と既定値には properties オブジェクトが使われます。

Field (per property)各プロパティのフィールド Description説明
type string, boolean, number, or integer. Unknown types are ignored. string / boolean / number / integer。それ以外は無視されます。
default Fallback when no user override exists. ユーザー未設定時に使われる既定値。
label Shown in Settings; falls back to the property key. 設定画面のラベル。省略時はプロパティ名。
minimum / maximum Clamp for number and integer types. number / integer の値をこの範囲に収めます。
{
  "widgetId": "com.example.mywidget",
  "version": 1,
  "properties": {
    "accentColor": {
      "type": "string",
      "default": "#4fc3f7",
      "label": "Accent color (#hex)"
    },
    "compactCards": {
      "type": "boolean",
      "default": false,
      "label": "Compact cards"
    }
  }
}

Storage identifier (slug)保存キー(スラッグ)

Overrides are stored under /Library/Airaw/WidgetOptions/ (rootless prefix applied by the jailbreak). The plist basename starts from the HTML path’s folder names: xenhtml.<parent>.<folder> (segments lowercased). Example: …/MyPack/widget/index.htmlxenhtml.mypack.widget.plist. If your schema defines a non-empty widgetId, Airaw appends a sanitized segment so different widgets under the same folder path do not collide: xenhtml.mypack.widget.<sanitized-widgetId>.plist. When you add widgetId later, an existing legacy plist at the base-only filename is moved to the new name on first access so user settings are preserved.

保存先は(rootless ではプレフィックス付きの)/Library/Airaw/WidgetOptions/ です。 ベース名は HTML のフォルダから xenhtml.<親>.<フォルダ>(小文字)。例: …/MyPack/widget/index.htmlxenhtml.mypack.widget.plist。 スキーマに空でない widgetId がある場合は衝突回避のため xenhtml.mypack.widget.<sanitized-widgetId>.plist のように続けます。 後から widgetId を追加した場合、既存のレガシー plist は初回アクセス時に新ファイル名へ移動され、設定は引き継がれます。

JavaScript APIJavaScript からの利用

Mechanism手段 Description説明
window.AIRAW_WIDGET_OPTIONS Plain object of merged defaults + user overrides. Updated on load and when settings change. 既定値とユーザー値をマージしたオブジェクト。読み込み時および設定変更時に更新されます。
airawwidgetoptions window CustomEvent; event.detail is the options object (empty object when no keys). window の CustomEvent。detail にオプションオブジェクト(キーが無い場合は空オブジェクト)。
window.onAirawWidgetOptions If defined as a function, Airaw calls it with the options object after each injection. 関数として定義されていれば、注入のたびにその関数がオプションオブジェクトで呼ばれます。
function applyOptions(o) {
  if (!o) return;
  document.documentElement.style.setProperty('--accent', o.accentColor || '#4fc3f7');
  document.body.classList.toggle('compact', !!o.compactCards);
}

window.addEventListener('airawwidgetoptions', function(e) {
  applyOptions(e.detail);
});

window.onAirawWidgetOptions = applyOptions;

// Initial paint if already injected before listeners ran
if (typeof window.AIRAW_WIDGET_OPTIONS !== 'undefined') {
  applyOptions(window.AIRAW_WIDGET_OPTIONS);
}

Settings UI設定アプリでの操作

Open Airaw’s screen where you configure CarPlay widget placement for your HTML widget. When the schema file is present, a group titled HTML widget options lists switches, sliders, or text fields per property. Tap Apply to push changes to CarPlay / refresh the WebView.

Airaw のCarPlay 上のウィジェット配置を編集する設定画面で、その HTML ウィジェットを開きます。 スキーマがある場合、HTMLウィジェットのオプションというグループにスイッチ・スライダー・テキストなどが現れます。 変更を反映するには Apply をタップしてください。

📎 Sample filesサンプル

See Samples/airaw-widget-schema.json and Samples/airaw-sample-widget.html for a complete working example (CSS variables, compact layout, and option listeners).

実装例はリポジトリの Samples/airaw-widget-schema.jsonSamples/airaw-sample-widget.html を参照してください(CSS 変数・コンパクト表示・オプション連動)。

Trigger APIsトリガー API

Call Airaw from JavaScript to refresh widget data. Prefer airawRequest(method) or postMessage so the webview does not navigate. The arapi: URL form remains supported as a legacy fallback.

JavaScript から Airaw にデータ取得を依頼します。airawRequest(method) または postMessage を推奨します(WebView がナビゲーションしないため)。 arapi: 形式はレガシー互換として残ります。

📌 Recommended vs legacy推奨とレガシー

Recommended: airawRequest('arcall_Battery') (injected at document start), or explicitly: window.webkit.messageHandlers.airawAction.postMessage({ action: 'requestData', method: 'arcall_Battery' }). The method string is always the same token that follows arapi: (e.g. arcall_all, action_launchApp_com.apple.Music).

推奨: ドキュメント開始時に注入される airawRequest('arcall_Battery')、または明示的に window.webkit.messageHandlers.airawAction.postMessage({ action: 'requestData', method: 'arcall_Battery' })method は常に arapi: の後ろと同じ識別子です(例: arcall_allaction_launchApp_com.apple.Music)。

Legacy: window.location = 'arapi:' + method; — Airaw cancels navigation and runs the same pipeline.

レガシー: window.location = 'arapi:' + method; — Airaw がナビゲーションをキャンセルし、同じ処理へ渡します。

CALL arapi:arcall_Battery Request battery dataバッテリー情報を要求
airawRequest('arcall_Battery');
// postMessage: window.webkit.messageHandlers.airawAction.postMessage({ action: 'requestData', method: 'arcall_Battery' });
// legacy: window.location = 'arapi:arcall_Battery';

Airaw collects battery info and calls mainUpdate('battery').

Airaw がバッテリー情報を収集し mainUpdate('battery') を実行します。

CALL arapi:arcall_Statusbar Request network statusステータスバー情報を要求
airawRequest('arcall_Statusbar');
// postMessage … method: 'arcall_Statusbar'
// legacy: window.location = 'arapi:arcall_Statusbar';
CALL arapi:arcall_Music Request now-playing info再生中の音楽情報を要求
airawRequest('arcall_Music');
// postMessage … method: 'arcall_Music'
// legacy: window.location = 'arapi:arcall_Music';
Async delivery非同期配信

Music data is fetched asynchronously via the MediaRemote framework, so it may arrive later than other categories. Airaw also fires mainUpdate('music') automatically whenever the track changes — no explicit request needed.

音楽情報は MediaRemote フレームワーク経由で非同期取得されます。そのため他のカテゴリより 遅延が生じる場合があります。また、楽曲が変わると Airaw が自動的に mainUpdate('music') を呼び出します(要求不要)。

CALL arapi:arcall_Weather Request weather data天気情報を要求
airawRequest('arcall_Weather');
// postMessage … method: 'arcall_Weather'
// legacy: window.location = 'arapi:arcall_Weather';

Data is sourced from the iOS Weather framework. The "Weather API" option must be enabled in Airaw settings.

iOS 標準の Weather フレームワークから取得します。 Airaw の設定で「Weather API」が有効になっている必要があります。

CALL arapi:arcall_System Request device / RAM infoシステム情報を要求
airawRequest('arcall_System');
// postMessage … method: 'arcall_System'
// legacy: window.location = 'arapi:arcall_System';
CALL arapi:arcall_all Fetch all categories at once全カテゴリを一括取得
airawRequest('arcall_all');
// postMessage … method: 'arcall_all'
// legacy: window.location = 'arapi:arcall_all';

Requests Battery, Statusbar, Music, Weather, and System together. Recommended for use in window.onload.

Battery / Statusbar / Music / Weather / System をまとめて要求します。 初期化時(window.onload)での使用を推奨します。

Callbacks — mainUpdate(type)コールバック — mainUpdate(type)

After collecting data, Airaw injects global variables and calls mainUpdate(type). Use type to identify the category and read the corresponding variables.

Airaw はデータ収集後、グローバル変数を注入してから mainUpdate(type) を呼び出します。 type で対象カテゴリを判別し、各変数を読み取ります。

EVENT mainUpdate('battery') Battery informationバッテリー情報

Injected variables注入される変数

Variable変数名 Type Description説明 Example
batteryPercent number Battery level (0–100)バッテリー残量(0〜100) 87
batteryCharging number Charging flag (1 = charging, 0 = not)充電中フラグ(1=充電中, 0=未充電) 1
batteryLowPowerMode number Low Power Mode (1 = ON)省電力モード(1=ON, 0=OFF) 0
batteryCycles number Charge cycle count充放電サイクル数 342
batteryHealth number Battery health (0.00–100.00)バッテリー健全度(0.00〜100.00) 94.32
batteryVoltage number Voltage (mV)電圧(mV) 4023
batteryCelsius number Battery temperature (°C)バッテリー温度(℃) 29.45
bateryInfo object Connected device battery info (AirPods, etc.). Contains a devices array.接続デバイス(AirPods 等)のバッテリー情報。devices 配列を含む。 { devices: [...] }
⚠️ Typo in variable name変数名のタイポについて

bateryInfo (one "t" missing) is a typo in the source code, preserved for backward compatibility.

bateryInfo("t" が1つ)はソースコード上のタイポですが、 互換性のためそのまま維持されています。

bateryInfo.devices[] structurebateryInfo.devices[] の構造

bateryInfo: {
devices: [{
deviceName: string// "AirPods Pro"
batteryPercent: number// 0–100
machineName: string// display name
allmachineName: string// glyph asset name
deviceIdentifier: string// device identifier
deviceProductIdentifier: number// product identifier
}]
}

Example実装例

function mainUpdate(type) {
  if (type === 'battery') {
    const pct = typeof batteryPercent !== 'undefined' ? batteryPercent : 0;

    document.getElementById('pct').textContent  = pct + '%';
    document.getElementById('icon').style.display = batteryCharging ? 'block' : 'none';

    // Connected devices (AirPods, etc.)
    if (bateryInfo?.devices?.length) {
      bateryInfo.devices.forEach(d => console.log(d.deviceName, d.batteryPercent));
    }
  }
}
EVENT mainUpdate('statusbar') Network / carrier statusステータスバー / ネットワーク情報

Injected variables注入される変数

Variable変数名 Type Description説明 Example
signalBars string Cellular signal strength ('0'–'4')セルラー電波強度('0'〜'4') '3'
signalName string Carrier nameキャリア名 'Softbank'
wifiBars string Wi-Fi signal strength ('0'–'3')Wi-Fi 電波強度('0'〜'3') '2'
wifiName string Connected SSID接続中の SSID 'HomeNetwork_5G'
signalNetworkType string Data network typeデータ通信規格 '5G' | 'LTE' | '4G' | '3G' | 'E'
EVENT mainUpdate('music') Now-playing info (auto-delivered)再生中の音楽情報(自動配信)

Airaw automatically fires this callback whenever the track or playback state changes. You can also request it manually with arcall_Music.

楽曲変更・再生状態変化時に Airaw が自動で呼び出しますarcall_Music で手動要求することも可能です。

Injected variables注入される変数

Variable変数名 Type Description説明 Example
title string Track title楽曲タイトル 'Blinding Lights'
artist string Artist nameアーティスト名 'The Weeknd'
album string Album nameアルバム名 'After Hours'
currentDuration string Total track duration (seconds)楽曲の総再生時間(秒) '200'
currentElapsedTime string Current playback position (seconds)現在の再生位置(秒) '73'
PlayingApplication string Bundle ID of the playing app再生アプリのバンドル ID 'com.apple.Music'
PlayingApplicationName string Localized display name of the playing app再生アプリの表示名 'ミュージック'
isplaying boolean / number Whether playback is active (1/0)再生中かどうか(1/0 1
artworkUrl string iOS 16+ HTTP URL for album art (recommended for CarPlay widgets). See Artwork. iOS 16+ アルバムアートの HTTP URL(CarPlay ウィジェット推奨)。Artwork 参照。 'http://localhost:18765/AirawMedia/MusicArt.png?t=…'
playingAppIconUrl string iOS 16+ HTTP URL for the playing app’s icon (same HTTP daemon as artwork). iOS 16+ 再生アプリのアイコン HTTP URL(アートと同じ HTTP デーモン)。 'http://localhost:18765/AirawMedia/PlayingAppIcon.png?t=…'

Example実装例

function mainUpdate(type) {
  if (type === 'music') {
    const playing = typeof isplaying !== 'undefined' ? !!isplaying : (title !== '');
    const dur     = parseFloat(currentDuration)    || 0;
    const elapsed = parseFloat(currentElapsedTime) || 0;
    const pct     = dur > 0 ? (elapsed / dur) * 100 : 0;

    document.getElementById('title').textContent  = playing ? title  : 'Not Playing';
    document.getElementById('artist').textContent = playing ? artist : '';
    document.getElementById('bar').style.width    = pct + '%';

    // App name + icon (iOS 16+)
    const appLabel = typeof PlayingApplicationName !== 'undefined' && PlayingApplicationName
      ? PlayingApplicationName
      : (PlayingApplication || '');
    const appNameEl = document.getElementById('appName');
    if (appNameEl) appNameEl.textContent = appLabel;

    const appIcon = document.getElementById('appIcon');
    if (appIcon) {
      if (typeof playingAppIconUrl !== 'undefined' && playingAppIconUrl) {
        appIcon.src = playingAppIconUrl;
        appIcon.style.display = 'block';
      } else {
        appIcon.style.display = 'none';
      }
    }

    // iOS 16+: use artworkUrl (HTTP). Do not rely on Documents path.
    const img = document.getElementById('artwork');
    if (img) {
      if (playing && typeof artworkUrl !== 'undefined' && artworkUrl) {
        img.src = artworkUrl;
        img.style.display = 'block';
      } else {
        img.style.display = 'none';
      }
    }
  }
}
EVENT mainUpdate('weather') Weather data (object format)天気情報(オブジェクト形式)

Weather data is provided as a single weather object, unlike other categories which inject flat variables.

天気データは単一の weather オブジェクトとして提供されます。 他のカテゴリとは異なりフラットな変数ではありません。

weather object structureweather オブジェクト構造

weather: {
city: string// "Tokyo"
countryISOCode: string// "JP"
temperature: number// current temp (unit follows celsius)
feelsLike: number// feels-like temperature
celsius: string// "C" or "F" (follows iOS setting)
condition: string// "Partly Cloudy"
conditionCode: number// see Condition Codes table
humidity: number// humidity (%)
windSpeed: number// wind speed (km/h)
windDirection: number// degrees
windChill: number// wind chill index
dewPoint: number// dew point
uvIndex: number// UV index (0–11+)
visibility: number// visibility (km)
pressure: number// pressure (hPa)
heatIndex: number// heat index
precipitationPast24Hours: number// 24h rainfall (mm)
chanceOfRain: number// precipitation probability (%)
moonPhase: number// moon phase (0.0–1.0)
high: number// today's high
low: number// today's low
sunrise: string// "6:24" (H:MM)
sunset: string// "18:45" (HH:MM)
updateTimeString: string// last update time
latlong: string// "35.6762,139.6503"
dayForecasts: DayForecast[]// up to 7 days
hourlyForecasts: HourlyForecast[]// hourly data
}

DayForecast[]

{
dayNumber: number// sequential day number
dayOfWeek: number// 0=Sun, 1=Mon … 6=Sat
icon: number// condition code
high: number// high temp
low: number// low temp
}

HourlyForecast[]

{
time: string// "14:00"
hourIndex: number// hour index
conditionCode: number// condition code
temperature: number// temperature
percentPrecipitation: number// precipitation probability (%)
detail: string// description text
}

Example実装例

function mainUpdate(type) {
  if (type === 'weather') {
    if (typeof weather === 'undefined') return;

    const unit = weather.celsius === 'C' ? '°C' : '°F';
    document.getElementById('temp').textContent = weather.temperature + unit;
    document.getElementById('city').textContent = weather.city;

    // 7-day forecast
    const days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
    weather.dayForecasts?.slice(0, 7).forEach(f => {
      console.log(days[f.dayOfWeek], f.high + unit, f.low + unit);
    });
  }
}
EVENT mainUpdate('system') Device & memory infoデバイス / メモリ情報

Injected variables注入される変数

Variable変数名 Type Description説明 Example
deviceName string Device display name (Settings → General → About)デバイスの表示名(設定 → 一般 → 情報 と同じ) 'iPhone'
deviceType string Platform / model identifier機種識別子(プラットフォーム名) 'iPhone16,1'
systemVersion string iOS versioniOS バージョン '17.4.1'
ipAddress string Wi-Fi IPv4 addressWi-Fi の IPv4 アドレス '192.168.1.5'
ramFree string Free RAM (MB)空き RAM(MB) '1243'
ramUsed string Used RAM (MB)使用中 RAM(MB) '2853'
ramTotal string Total installed RAM (MB)搭載 RAM 合計(MB) '6144'

RAM values are provided as string type. Use parseFloat() before arithmetic operations.

RAM 系の値は文字列型(string)で提供されます。数値演算前に parseFloat() で変換してください。

EVENT mainUpdate('CarPlay') CarPlay page change notificationCarPlay ページ切り替え通知

Called automatically when the user navigates between CarPlay dashboard pages. Useful for controlling widget animations per page.

ユーザーが CarPlay のダッシュボードページを切り替えた際に自動で呼び出されます。 ウィジェットのアニメーション切り替えなどに利用できます。

Injected variables注入される変数

Variable変数名 Type Description説明 Example
pageIndex number Current page index (0-based). -1 = widget not visible. 現在表示中のページインデックス(0 始まり)。-1 = 非表示状態。 0

Example実装例

function mainUpdate(type) {
  if (type === 'CarPlay') {
    // Animate only when on page 0
    document.body.style.opacity = (pageIndex === 0) ? '1' : '0.4';
  }
}

Condition Codes天気コード(conditionCode)一覧

Numeric codes used by weather.conditionCode, dayForecasts[].icon, and hourlyForecasts[].conditionCode. Follows the Apple Weather framework (formerly WeatherData) definition.

weather.conditionCode / dayForecasts[].icon / hourlyForecasts[].conditionCode で使用される数値コードです。 Apple Weather フレームワーク(旧 WeatherData)の定義に従います。

0–1 🌪
Tornado / Tropical Storm竜巻 / 熱帯暴風
2–3
Hurricaneハリケーン
4–12 🌧
Thunderstorm / Rain雷雨 / 雨
13–17
Snow / Sleet / Heavy Rain雪 / みぞれ / 大雨
19 🌫
Dust / Haze砂塵 / もや
20–22 💨
Foggy / Windy霧 / 強風
25–30 🌨
Snow / Blizzard雪 / 吹雪
31 / 33 🌙
Clear Night夜間・快晴
32 / 34 ☀️
Sunny / Mostly Sunny晴れ / 概ね晴れ
36 🌡
Hot酷暑
37–40 🌦
Scattered Storms局地的雷雨
41–43 🌩
Heavy Snow / Blizzard大雪 / 猛吹雪
44
Partly Cloudy一部曇り

Emoji mapping function絵文字マッピング関数の実装例

function weatherEmoji(code) {
  const c = parseInt(code, 10);
  if (c <= 1)  return '🌪';
  if (c <= 3)  return '⛈';
  if (c <= 12) return '🌧';
  if (c <= 17) return '⛈';
  if (c === 19) return '🌫';
  if (c <= 22) return '💨';
  if (c <= 30) return '🌨';
  if (c === 31 || c === 33) return '🌙';
  if (c === 32 || c === 34) return '☀️';
  if (c === 36) return '🌡';
  if (c <= 40) return '🌦';
  if (c <= 43) return '🌩';
  return '⛅';
}

Artwork Imageアートワーク画像の取得

iOS 16+ (recommended) — artworkUrliOS 16+(推奨)— artworkUrl

On iOS 16+, CarPlay widgets often run inside CarPlayWallpaper, which cannot read /var/mobile/Documents/ (sandbox). Airaw therefore serves artwork over a local HTTP server on SpringBoard and injects an HTTP URL as artworkUrl when calling mainUpdate('music').

iOS 16 以降、CarPlay ウィジェットは多くの場合 CarPlayWallpaper 上で動作し、 サンドボックスのため /var/mobile/Documents/ を直接読めません。 Airaw は SpringBoard 側のローカル HTTP でアートを配信し、 mainUpdate('music') 時に変数 artworkUrl として注入します。

// Injected example
artworkUrl = 'http://localhost:18765/AirawMedia/MusicArt.png?t=1710000000000';
Item項目 Value
Variable artworkUrl
URL form http://localhost:18765/AirawMedia/MusicArt.png?t=<version>
File on device /var/mobile/Library/Airaw/Media/MusicArt.png (rootless-aware)
App icon file /var/mobile/Library/Airaw/Media/PlayingAppIcon.pngplayingAppIconUrl
t= query Changes only when artwork bytes change (cache-friendly). アートのバイト列が変わったときだけ更新(キャッシュしやすい)。
// Recommended (iOS 16+ CarPlay widget)
function mainUpdate(type) {
  if (type !== 'music') return;
  const img = document.getElementById('artwork');
  if (!img) return;

  if (typeof artworkUrl !== 'undefined' && artworkUrl) {
    img.onerror = function() { this.style.display = 'none'; };
    img.onload  = function() { this.style.display = 'block'; };
    img.src = artworkUrl;  // already includes ?t=
  } else {
    img.style.display = 'none';
  }
}

Requires Airaw’s SpringBoard HTTP daemon (same localhost server used for SBHTML widgets). If artworkUrl is empty, artwork data was unavailable for the current track.

SpringBoard 上の Airaw HTTP デーモンが必要です(SBHTML 配信と同じ localhost)。 artworkUrl が空の場合は、その曲のアートデータが取得できていません。

Legacy path (not for iOS 16+ CarPlayWallpaper)レガシー経路(iOS 16+ CarPlayWallpaper では非推奨)

Airaw still writes a copy to the Documents path for older environments / Prefs preview. Do not rely on this path inside iOS 16+ CarPlayWallpaper widgets — the file is not readable there.

互換のため Documents にもコピーしますが、 iOS 16+ の CarPlayWallpaper ウィジェットではこのパスに依存しないでください(読めません)。

/var/mobile/Documents/MusicArt.png
// Legacy only (Prefs preview / older hosts that can read Documents)
const img = document.getElementById('artwork');
img.src = '/var/mobile/Documents/MusicArt.png?t=' + Date.now();
img.onerror = function() { this.style.display = 'none'; };

On rootless jailbreaks (Dopamine, etc.), /var/mobile/Documents/ may map to /var/jb/var/mobile/Documents/. Prefer artworkUrl so you do not need to resolve jbroot yourself.

Rootless 環境(Dopamine 等)では /var/mobile/Documents/ のパスが /var/jb/var/mobile/Documents/ にマップされる場合があります。 artworkUrl を使えば jbroot を意識する必要はありません。

Best Practices実装のヒント

1. Safe variable access1. 安全な変数アクセス

Airaw always injects variables before calling mainUpdate, but use typeof checks for safety when opening the HTML file directly during development.

Airaw は変数を注入してから mainUpdate を呼びますが、開発・デバッグ時に 直接 HTML を開く場合に備え、typeof チェックを推奨します。

// Recommended pattern
const pct = typeof batteryPercent !== 'undefined' ? batteryPercent : 0;

// Nullish coalescing (modern browsers)
const temp = weather?.temperature ?? '--';

2. Periodic polling2. 定期更新の実装

Airaw notifies automatically on changes, but you can also poll at a fixed interval.

Airaw は変化があった際に自動で通知しますが、一定間隔でポーリングすることもできます。

// Refresh all data every 30 seconds
setInterval(function() {
  if (typeof airawRequest === 'function') {
    airawRequest('arcall_all');
  } else {
    window.location = 'arapi:arcall_all';
  }
}, 30000);

3. mainUpdate template3. mainUpdate のテンプレート

function mainUpdate(type) {
  switch (type) {
    case 'battery':
      /* batteryPercent, batteryCharging, batteryLowPowerMode,
         batteryCycles, batteryHealth, batteryVoltage,
         batteryCelsius, bateryInfo */
      break;
    case 'statusbar':
      /* signalBars, signalName, wifiBars, wifiName,
         signalNetworkType */
      break;
    case 'music':
      /* title, artist, album, currentDuration,
         currentElapsedTime, PlayingApplication, PlayingApplicationName,
         isplaying, artworkUrl, playingAppIconUrl (iOS 16+ HTTP) */
      break;
    case 'weather':
      /* weather.{ temperature, city, condition, humidity,
         windSpeed, uvIndex, high, low, celsius,
         dayForecasts[], hourlyForecasts[] ... } */
      break;
    case 'system':
      /* deviceName, deviceType, systemVersion, ipAddress,
         ramFree, ramUsed, ramTotal */
      break;
    case 'CarPlay':
      /* pageIndex */
      break;
  }
}

window.addEventListener('load', function() {
  if (typeof airawRequest === 'function') {
    airawRequest('arcall_all');
  } else {
    window.location = 'arapi:arcall_all';
  }
});

4. Demo data for development4. デバッグ用デモデータ

To develop the UI without a real device, refer to the fillRandom() function in airaw-sample-widget.html. It injects demo values into all fields without making any API calls.

実デバイスなしで UI 開発を進める場合は、airaw-sample-widget.htmlfillRandom() 関数を参考にしてください。 API 呼び出しを一切せずにすべてのフィールドにデモ値を注入できます。

5. Widget options alongside API data5. API データと並行するウィジェットオプション

User-configurable widget options (schema file + window.AIRAW_WIDGET_OPTIONS) are independent of data triggers (requestData / airawRequest / legacy arapi:) and mainUpdate. You can read options inside mainUpdate or react via airawwidgetoptions — see the Widget Options section.

スキーマに基づくユーザー設定(window.AIRAW_WIDGET_OPTIONS)は、データ取得(requestData / airawRequest / レガシー arapi:)や mainUpdate とは別経路です。 mainUpdate 内で参照してもよいし、airawwidgetoptions で UI を更新しても構いません。詳細はウィジェットオプションを参照してください。