阪急沿線アプリで見られる列車走行位置を、ブラウザーでも確認できるWeb版にしました。列車位置を見るために毎回アプリを開くのではなく、URLを開くだけで確認できるようにしたかったためです。調べてみると、アプリの画面にはAPK内のAndroidコードと、阪急のサーバーから読み込むWeb画面の両方が関わっていました。この記事では、APKのどこを見てAPIを見つけ、JSONを読み、PHPのWebページとして公開したのかを、コードを追いながら説明します。
先に使ってみる場合は阪急 車両位置 Web版へ。ソースコードはGitHub、APK解析とJSONの詳細は解析ノート、実際の応答例はJSONサンプルで読めます。
他社はどうしている? 公式Web版とオープンデータを調べました
「列車が今どこにいるか」を見る入口は、専用アプリだけである必要があるのでしょうか。調べると、ブラウザーで公式に提供している鉄道会社や、外部の開発者が利用するためのデータ公開の仕組みが実際にあります。ここでは2026年10月11日に確認した公式資料を紹介します。
| 事業者・仕組み | 確認できた提供方法 | 公式の参照先 |
|---|---|---|
| JR西日本 | 「列車走行位置」をWebで提供しています。対象路線をブラウザーで選んで確認できます。 | JR西日本 列車走行位置 |
| 京阪電車 | 「列車走行位置」の公式Webページがあります。 | 京阪電車 列車走行位置 |
| JR東日本 | 「どこトレ」はスマートフォンとパソコンのブラウザーに対応しています。主に地方路線が対象で、JR東日本アプリとは対応路線が異なります。 | JR東日本公式メディアの説明・どこトレ |
| 公共交通オープンデータセンター(ODPT) | 開発者向けのデータ配信があります。例えば東京都交通局は、都営地下鉄と東京さくらトラムの列車ロケーション情報をJSONで提供しています。 | 開発者サイト・東京都交通局の列車ロケーション情報 |
JR西日本については、2020年1月の公式発表で、同年2月6日から「Yahoo!乗換案内」アプリと列車走行位置サービスを連携させると説明しています。自社アプリの外から情報にアクセスできる入口を用意してきた例です。
ODPTは、利用者向けのWeb画面に加えて、外部の開発者がアプリを作るための仕組みです。東京都交通局の上記データセットはCC BY 4.0で、提供元の表示などの条件が示されています。公開されるデータの種類・対象路線・期間・利用条件は事業者ごとに違うため、「参加各社の全列車位置が、いつでも無条件に使える」という意味ではありません。
さらに公共交通オープンデータチャレンジ2026の開催概要では、オープンデータを使った作品を募り、賞金総額を最大300万円としています。第三者による便利なサービスの開発を、公式の制度として後押しする取り組みです。
公式Web版があれば、この解析作業は不要でした
阪急の公式案内では、列車走行位置を阪急沿線アプリの機能として紹介しています。今回調べた画面も、アプリからWebViewを開く構成でした。利用者としては、JR西日本や京阪のように公式サイトのURLを開くだけで見られる入口があれば、それを使えば済みます。今回の目的に対しては、APKを解析し、APIを特定し、代替Web版を作る作業自体が不要になったはずです。
ブラウザーから簡単に見たい情報の入口がアプリに偏ると、利用者にはインストールや起動の手間が生まれ、外部の開発者には表示方法を調べ直す手間が生まれます。この点は、アプリへの「囲い込み」と感じられても不思議ではありません。公共交通の状況を知るための入口は、端末や閲覧方法を選べるほうが便利だと考えます。
一方、WebViewで作られていたという事実だけで、一般公開が「ボタン一つ」で済むとは限りません。外部公開に伴う負荷対策や運用もあります。また、アプリのダウンロード数を増やす意図や、列車位置の閲覧にログインが必須だということは、今回の解析からは確認していません。ここで指摘したいのは、公式Web版や条件を明示した公式APIがあれば、利用者も開発者も同じ情報を得るための余計な作業を減らせるということです。
まず分かったこと:位置画面はAPKの中だけで描かれていない
Androidアプリを調べる前は、列車位置の地図も駅や列車の情報も、すべてAPKに入ったネイティブ画面だと思っていました。ところが阪急沿線アプリの車両位置画面は、AndroidのWebViewでWebページを開いていました。つまり、APKは画面の入口や初期駅を渡し、路線図や列車表示の多くはWebViewが受け取るHTML・JavaScript側にあります。
調査対象はAndroidパッケージjp.co.hankyu.tokkapp、versionName 10.3.3、versionCode 98のアプリです。XAPKを展開し、base APKのDEXコードをJADXで確認しました。JADXの表示は元のKotlinソースそのものではなく、DEXからJavaに近い形へ復元したものです。以下の短いコードは、その処理を初心者向けに整えた抜粋です。
APKのどこにURLが書かれているか
中心になるのはjp.co.hankyu.tokkapp.presentation.stationinfo.TrainPositionFragmentです。JADXではbase APKのclasses3.dexにあり、BaseWebFragmentを継承しています。画面が作られるとonViewCreated(View, Bundle)が呼ばれ、タイトルを「列車走行位置」にしてからWebViewへURLを渡します。
// JADXの処理を読みやすくした抜粋。実際の元ソースではありません。
Uri page = Uri.parse(
"https://cdn.hankyu-app.com/webview/train/position"
);
Uri.Builder url = new Uri.Builder();
url.scheme(page.getScheme());
url.authority(page.getAuthority());
url.appendQueryParameter("token", BuildConfig.APP_AUTH_TOKEN);
url.appendQueryParameter("dtype", DeviceType.ANDROID.getParam());
// args: NavArgsLazyから得た路線ID・駅ID(説明用に変数化)
url.appendQueryParameter("line_id", args.getTrainPositionLineId());
url.appendQueryParameter("station_id", args.getStationId());
super.loadUrl(url.build().toString());
URLへ付ける値は4つです。tokenはBuildConfig.APP_AUTH_TOKEN、dtypeはAndroid端末であること、line_idは最初に表示する路線、station_idは初期表示する駅を表します。画面を隠してから戻したときのonHiddenChanged(boolean)にもURLを組み立て直す処理がありました。
ここでいうBuildConfigは、ビルド時にアプリへ組み込まれる定数を持つクラスです。jp.co.hankyu.data.BuildConfigにはAPIのベースURLとアプリ共通の認証値があります。これはユーザーごとのログインや個人アクセストークンではなく、APKに固定で含まれる値です。固定値だから将来も使えるとは限らず、有効期限もコードだけからは分かりません。
RetrofitのAPI定義と、位置APIの呼び出しを区別する
APKにはjp.co.hankyu.data.remote.AppApiServiceもあり、駅や時刻表などの一般APIをRetrofitで定義しています。メソッドには@Headers("x-auth-token: …")という指定があります。一方、列車位置画面が使うtrain/positionsは、このRetrofit定義からではなく、WebViewに読み込まれるJavaScriptから呼び出されます。似た認証値が見えても、通信経路は分けて読む必要があります。
そこでWebViewのHTMLが読み込むNuxtのJavaScriptを追いました。共通APIクライアントのベースはhttps://cdn.hankyu-app.com/v1/です。画面のsetParameters()がURLのtokenを読み、APIクライアントのx-auth-tokenヘッダーへ設定します。車両位置ストアのfetchTrainPositions(lineId)は、次のGETを行います。
GET https://cdn.hankyu-app.com/v1/train/positions/?train_position_line_id=1
x-auth-token: [APKに含まれるアプリ共通値]
Accept: application/json
line_idはWebViewを開く画面用の値で、位置APIへ送るクエリ名はtrain_position_line_idです。名前が似ているので混同しやすいところです。
APKにはjp.co.hankyu.data.remote.entity.CurrentInfoPositionEntityという別のデータクラスもあります。JSON注釈はtime_real、stop_index、prev_indexですが、これは駅情報の現在位置を表すモデルです。列車配列のpositionsと同じものとして扱わないよう、呼び出し元とJSONの階層も合わせて確認しました。
JSONの形を読む
API応答の一番上は、取得時刻、配信状態、列車配列を持つオブジェクトです。実際に観測した応答から1列車分を抜き出すと、次の形です。
{
"timestamp": "2026-10-10T22:10:50",
"state": "normal",
"positions": [
{
"operation_number": "8203",
"destination": "新開地",
"from_station": 1,
"from_station_name": "大阪梅田",
"to_station": null,
"to_station_name": null,
"line_destination_id": 33,
"delay": 0,
"is_display_delay": true,
"train_kind_key": "semi_limited_express",
"train_kind_name": "準特急",
"direction": 1,
"track_number": 9,
"is_edge_station": true
}
]
}
positionsは列車ごとの配列です。例にあるキーは、次のように読みます。
| JSONキー | 意味 |
|---|---|
timestamp | 位置データの時刻。例にはタイムゾーン表記がありません。 |
state | 配信状態。例は通常運行を示すnormalです。 |
positions | 列車ごとの位置オブジェクトを並べた配列です。 |
operation_number | 運行番号。車両編成番号とは別です。 |
destination | 画面に表示する行先名です。 |
from_station、from_station_name | 停車駅、または走行中の出発駅です。IDと表示名を持ちます。 |
to_station、to_station_name | 走行中の次駅です。停車中の例では両方nullです。 |
line_destination_id | 行先を識別する数値IDです。 |
delay、is_display_delay | 遅延値と、その遅延を表示するかどうかのフラグです。 |
train_kind_key、train_kind_name | 列車種別の機械向けキーと画面表示名です。 |
direction | APIの方向コードです。路線図上の向きは駅順とも照合します。 |
track_number、is_edge_station | 番線と、路線端の駅に関係するフラグです。 |
stateはnormal、finished、under_maintenanceなどを表します。配列が空のとき、件数だけ見て「運休」や「故障」と決めつけるのではなく、状態と一緒に読みます。timestampの例にはタイムゾーン表記がないため、受け取った文字列以上の時刻情報を推測しません。
列車の進行方向をどう決めるか
列車位置APIにはdirectionもありますが、数値コードをそのまま「上り」「下り」と表示すると、支線や進行方向が反対になる場合があります。また、駅IDの数字が小さいほうから大きいほうへ進むとも限りません。
そこで路線ごとの順序付き駅一覧を使い、走行中ならfrom_stationとto_stationが駅配列のどちら向きに並ぶかを比べます。停車中は現在駅と路線内の行先を比較します。これで決められないときだけAPIのdirectionを補助に使い、根拠が足りないケースでは矢印を断定しないようにしました。表示上の矢印は路線図の端から端への向きで、線路上の正確なGPS位置や到着予測を示すものではありません。
APKとWebViewの解析で見つけた路線画面の構成も参考にし、Web版では路線の切り替え、駅の順序、停車中・駅間走行中の表示、行先と進行方向をまとめて見られるようにしています。
ブラウザーから直接阪急APIを呼ばない理由
ブラウザーから別ドメインのAPIへ直接アクセスすると、相手サーバーのCORS許可が必要です。今回はページと同じ配信元にあるPHPのAPIをブラウザーが呼び、PHPが阪急のAPIへ接続する形にしました。
ブラウザー
└─ GET /api/positions?line_id=1
└─ PHPサーバー
└─ GET 阪急API + x-auth-token
└─ JSONをPHP経由でブラウザーへ返す
そのため、ブラウザーは阪急APIのCORS設定に依存せず、認証値をJavaScriptへ埋め込まずに済みます。PHP版は成功した位置JSONを保存し、APIアクセスを日付単位の記録として残します。保存領域はWebから読めないようにします。
公開したWeb版と確認できる範囲
公開版はxn--c5r.jpの阪急 車両位置ページです。実装と解析ノートはGitHubのnew2xin/hankyuで公開しています。
この仕組みは阪急電鉄が開発・提供する公式Webサービスではありません。APIはアプリ用の経路として観測したもので、公開開発者向けの仕様保証があるわけではありません。アプリや配信JavaScriptが更新されるとURL、認証、JSON項目が変わる可能性があります。運行の確認には阪急電鉄の公式運行情報もご利用ください。