昨夜、次の更新に入れたい機能の相談を Rork にしておりました。新しい OS で使えるようになると聞いた仕組みを、名前だけ挙げて「これを使ってください」と書いたのです。
返ってきたコードは整っていました。型もそろっていて、赤い波線も出ませんでした。ビルドも通りました。
けれども、頼んだ仕組みはどこにも使われておりませんでした。代わりに置かれていたのは、去年から使っている見慣れた書き方でした。
返事が来たことと、頼んだものが入っていることは、別の話です。 iOS 27 と iPadOS 27 は9月14日の配信が告知されていますので、この確かめ方を先に決めておくと、配信後の数週間がずいぶん楽になります。
生成 AI の「知らない」には二種類あります
まず整理しておきたいのは、知らない状態には性質の違う二つがあるということです。
ひとつめは、実在しない名前を作ってしまう場合です。存在しないクラス名やメソッド名が生成され、ビルドの段階で落ちます。作業は止まりますが、止まったこと自体が知らせてくれています。これは、ありがたい失敗のほうです。
ふたつめは、知っている古い書き方へ寄せてしまう場合です。新しい API の名前が学習の中に無いとき、モデルはいちばん近い既知の形で埋め合わせます。そのコードは実在しますから、ビルドは通りますし、動きもします。ただし、頼んだ機能は入っておりません。これが静かなほうの失敗です。
嘘をついているわけではないのだと思います。知らない領域に呼ばれたときに、いちばん近い既知の形へ寄っていく——それだけのことなのです。ただ、寄られた側にはそれが見えません。
| 種類 | 何が起きるか | どこで気づくか | 危険度 |
|---|---|---|---|
| 実在しない名前を作る | ビルドが通らない | ビルド時・エディタの警告 | 低い(止まってくれる) |
| 古い書き方へ寄せる | 通る・動く・頼んだ機能だけが無い | 実機で触るまで気づきにくい | 高い |
| それらしい代替で置き換える | 見た目だけ似た動きになる | 新旧の端末を並べて初めて分かる | 高い |
新しい OS が配られる時期は、ふたつめとみっつめが増えます。学習した時点の世界には、まだその機能が無いからです。
標準 Rork では、新しい OS の機能は JS の側からは届きません
ここで製品の線引きを確認しておきます。標準の Rork は Expo 経由の React Native を生成します。Rork Max(2026年2月に公開された別製品)はネイティブの Swift を生成します。同じ「AI がアプリを作る」でも、新しい OS に対する立ち位置が違います。
標準 Rork の側から先に書きます。JavaScript から呼べるのは、ネイティブ側に橋が架かっている機能だけです。橋というのは、Expo のモジュールやコミュニティのネイティブモジュールのことです。
つまり、新しい OS の API は、Expo と React Native の版が上がり、モジュールが対応して初めて JS から届きます。橋が無いあいだは、どれだけ丁寧にプロンプトを書いても届きません。AI が返してくるのは、JS の範囲で書ける「見た目の似た代替」になります。
自分の手元に何の橋が架かっているかは、その場で数えられます。
# app.json に並んでいる config plugin を一覧で出します
node -e "const c=require('./app.json');console.log((c.expo.plugins||[]).map(p=>Array.isArray(p)?p[0]:p).join('\n'))"
# 実際に適用された結果まで見たいときはこちらです
npx expo config --type introspectここに名前が出てこない領域は、いまの構成では届かない領域です。プロンプトの書き方の問題ではありません。プランを上げても変わりません。届かないものは、頼み方を変えても届かないのです。
私はこの一覧を、配信の前の週に一度だけ出して手元に残すようにしております。線引きを先に持っておくと、配信直後に「なぜ動かないのか」を探して半日を溶かすことがなくなります。届かないと分かっていれば、待つという判断ができます。
Rork Max では、ビルドが通ったことは「その名前が在る」ことしか示しません
Rork Max はネイティブの Swift を生成し、クラウドの Mac でコンパイルします。こちらは Xcode と SDK が対応すれば追随できますので、待ち行列がひとつ短くなります。
ただし、待ち行列が短いことと、生成されたコードが正しいことは別です。モデルが新しい SDK を知らなければ、やはり古い書き方へ寄ります。そしてそのコードは実在しますから、コンパイルは通ります。
コンパイルが通ったという事実が示しているのは、「その名前が SDK に在る」ことだけです。「頼んだ新しい経路を通っている」ことは、まったく示しておりません。ここを取り違えると、出したあとで気づくことになります。
読み取りに使える手がかりがひとつあります。新しい OS だけの API を使うコードには、古い OS 向けの分岐が必ず要るということです。
if #available(iOS 27, *) {
// 新しい OS だけを通る経路をここに書きます
startWithNewCapability()
} else {
// 古い OS の端末はこちらへ来ます
startWithExistingCapability()
}関数やプロパティごと分けたいときは、宣言の側に付けます。
@available(iOS 27, *)
func startWithNewCapability() {
// 新しい OS 専用の実装です
}つまり、生成されたコードに #available も @available も一度も出てこないのに「新しい API を使いました」と説明が添えられている場合、その説明は怪しいということになります。分岐が要らないコードは、古い OS でも動く古い経路だからです。この読み方は、Swift の細部を知らなくても使えます。
返ってきたコードを確かめる三つの順番
やることを三つに絞ります。順番に意味があります。
一、名前が実在するかを、公式のドキュメントの本文で引きます。 検索結果の要約や、まとめ記事の一覧ではありません。Apple の Developer Documentation と Expo のドキュメント を開いて、そのページに書いてあるかどうかを見ます。二次情報は、新しい OS が出た直後のいちばん当てにならない時期に、いちばん量が増えます。
二、経路が分かれているかを見ます。 Swift なら #available の有無、React Native 側なら、そもそもそのモジュールが依存に入っているかどうかです。分岐も依存も無いまま「新しい機能を使っています」と書かれていたら、そこで一度止まります。
三、古い OS の端末で触ります。 新しい OS を入れた端末だけで確認すると、分岐の片側しか通りません。手元に予備の端末が無ければ、シミュレータでひとつ前のバージョンを立ち上げるだけでも、片側の抜けは見つかります。公開中のアプリを新しい OS で先に触っておく手順は、iOS 27 が正式版になる前に、予備の iPhone で公開中の Rork アプリを触っておくにまとめてあります。
そして三つのあとに、もうひとつだけ足します。頼んだ経路が本当に呼ばれたかを、ログの一行で確かめます。 画面が正しく出たことは、新しい経路を通った証明にはなりません。私はここを何度か省いて、出したあとに気づきました。表示が正しいときほど、確かめる気が起きないのです。
9月14日からの二週間、私が手を止めておく場所
個人でアプリを出しておりますので、新しい OS が配られる時期の身の置き方は、毎年少しずつ決まってきました。私はいまのところ二週間を目安に、次のように分けております。
出すのは、既存の経路だけで完結する修正です。文言の直し、レイアウトの調整、以前から分かっていた不具合の修正。これらは新しい OS の影響をほとんど受けません。
止めておくのは、新しい API に触る機能です。橋が架かるまで待ちます。急いで入れても、二週間後に書き直すことになりがちですし、その書き直しは審査をもう一度通ることになります。
例外がひとつあります。画面の形にまつわる備えは、待たずに進められます。折りたたみのような新しい画面の形が増えるとき、最初に崩れるのは固定幅を前提にしたビューです。ここは新しい API を待たなくても、いまのコードのまま直せます。ビルド環境そのものを固定するかどうかの判断は、eas.json に image を書かないままだと、SDK を上げた日に Xcode も pnpm も一緒に動きますのほうに書きました。
今夜できることをひとつだけ挙げるとしたら、さきほどの node -e の一行を走らせて、いま架かっている橋の一覧を手元に貼っておくことです。配信後に「これは届く領域なのか」と迷ったとき、その一覧が判断を数秒で終わらせてくれます。
お読みいただきありがとうございました。新しい OS の週は、誰にとっても足場が揺れます。揺れているあいだに何を出して何を待つのか、その線引きだけは自分で持っておきたいと思っております。