◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り35日。API 連携を足したアプリは移行先の確認を●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り35日。API 連携を足したアプリは移行先の確認を●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/アプリ開発
◇ アプリ開発/2026-10-26中級

Linking.canOpenURL が iOS だけ false を返し続ける — LSApplicationQueriesSchemes の書き方と、iOS 27 で 25 件になる上限

他アプリを開けるか調べたいだけの Linking.canOpenURL が、iOS だけ常に false になる原因は Info.plist への宣言漏れです。Expo の app.json での書き方、Android 側の queries、そして iOS 27 でリンクしたアプリから 25 件になる上限への備え方をまとめます。

Expo228iOS116LinkingcanOpenURLInfo.plist8トラブルシューティング98

アプリ内に「LINE で開く」のようなボタンを置いた夜のことです。Android の実機では、アプリが入っていれば開き、入っていなければストアへ飛びます。ところが iOS のシミュレータでも実機でも、Linking.canOpenURL が必ず false を返し、毎回ストアのほうへ流れてしまいました。LINE は確かに端末に入っているのに、です。

コードを疑って 1 時間ほど過ごしましたが、原因はコードの外にあったのだと気づいたのは、Info.plist を開いたときでした。Info.plist に、調べたいスキームを宣言していなかっただけだったのです。

最初にお伝えしたいのは、canOpenURL が false を返すことと、openURL が失敗することは別の話だという点です。ここを分けて考えると、切り分けがぐっと楽になります。

false になる原因は、ほとんど 2 つに絞れます

Apple のドキュメントでは、iOS 9.0 以降にリンクしたアプリが canOpenURL に渡すスキームは、Info.plist の LSApplicationQueriesSchemes に宣言しておく必要があるとされています。宣言のないスキームは、対応アプリが入っていても常に false です。

もう一つは、端末にそのスキームを扱うアプリが本当に入っていない場合です。こちらも false ですが、見た目は同じなので区別がつきません。

切り分けの順番は次のとおりです。

手順確かめることわかること
1Info.plist に該当スキームがあるか無ければ宣言漏れが確定します
2スキームの綴りと「://」の有無宣言するのはスキーム名だけです
3prebuild し直したかapp.json を変えても、ネイティブ側に反映されていないことがあります
4Expo Go で試していないかExpo Go の Info.plist が使われるため、自分の宣言は効きません

手順 4 は私が最初にはまった点です。Expo Go で確認している限り、app.json にどれだけ書いても結果は変わりません。開発ビルド(development build)で試す必要があります。

Expo の app.json での書き方

Expo の公式ガイドでは、ios.infoPlist に LSApplicationQueriesSchemes を書く形が示されています。

{
  "expo": {
    "ios": {
      "infoPlist": {
        "LSApplicationQueriesSchemes": ["line", "twitter"]
      }
    }
  }
}

何を解決するかというと、「調べたいスキームを OS に申告する」ことです。line:// ではなく line と書くのは、plist に入れるのがスキーム名だけだからです。

アプリ側のコードは、判定と遷移を分けて書いておくと後で直しやすくなります。

import { Linking } from 'react-native';
 
async function openOrFallback(appUrl: string, storeUrl: string) {
  try {
    const installed = await Linking.canOpenURL(appUrl);
    await Linking.openURL(installed ? appUrl : storeUrl);
  } catch (e) {
    // Android では判定そのものが reject されることがある
    await Linking.openURL(storeUrl);
  }
}

try/catch を入れているのは、Expo のドキュメントに、Android で確認できない場合は Promise が reject されると書かれているからです。ここで落ちて画面が固まるより、ストアへ流すほうが読者に親切だと私は考えています。

Android 11 以降は、宣言の置き場所が違います

Android には Info.plist はありません。パッケージの可視性の仕組みで、AndroidManifest の queries に調べたいアプリやインテントを書きます。Expo のガイドでは、app.json ではなく config plugin で manifest.queries を足す例が示されています。iOS の感覚で app.json に書いても、Android 側は変わらないのです。

iOS 27 では、宣言できる数が 25 件になります

ここからが、今回いちばん書き残したかったことです。Apple のドキュメントによると、iOS 15 以降にリンクしたアプリは LSApplicationQueriesSchemes を 50 件まで、iOS 27 以降にリンクしたアプリは 25 件までに制限されます。

SNS の共有先を何十個も判定するような作りだと、Xcode 27 でビルドし直したときに、後ろのほうの宣言が効かなくなるおそれがあります。対策は次の 3 つです。

  • 本当に判定が要るスキームだけを残します(共有先なら、よく使われる上位だけです)
  • 判定が要らない箇所では canOpenURL を呼ばず、openURL を直接呼びます(openURL は宣言に縛られません)
  • 可能なら、カスタムスキームでなく universal link に寄せます(アプリが無ければブラウザが開きます)

私自身は、個人開発の壁紙アプリで「判定してから出し分ける」箇所を棚卸しし、本当に必要なものだけを残す方向にしています。

審査との関係

canOpenURL で他アプリの有無を探る使い方は、必要以上に多くのスキームを並べると、審査で用途を聞かれる可能性があります。宣言するのは、画面上の導線として本当に使うものだけに絞っておくのが無難かもしれません。ビルドが審査で止まるときの見方は、空白画面で審査に落ちたときのチェックリストにまとめています。

iOS 側のネイティブ設定をいじるときは、prebuild の挙動も確認が要ります。AppDelegate まわりで詰まった場合は、prebuild で AppDelegate のエラーが出るときも参考になります。Android 側の manifest を見直すなら、依存ライブラリの manifest 監査もあわせてご覧ください。

判定は最小限に、遷移は openURL で。 この線引きだけは、スキームの数が増えたときも守るようにしています。

次にやることは 1 つです。いま app.json に並べているスキームのうち、canOpenURL で本当に判定している数を数えてみていただければと思います。25 を超えていなければ、まず慌てる必要はありません。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

◇ アプリ開発2026-10-15
adjustsFontSizeToFit で特定の1行だけ極小になるとき、疑うのは文字列ではなく枠の高さです
一覧の10行目だけ文字が4ptまで縮む。データも文字列も正常なのに起きる iOS の症状を、Yoga の丸めと縮小判定のソースで確かめ、Node で再現率を数えた記録です。
⬡ 開発ツール2026-05-18
Rork で Linking.canOpenURL が iOS だけ false を返す ─ LSApplicationQueriesSchemes 設定漏れの直し方
TikTok や X、LINE 公式アカウントへ飛ばす実装が iOS の本番ビルドだけで動かない症状を、LSApplicationQueriesSchemes の追加と EAS Build の再生成手順で確実に解消します。
◇ アプリ開発2026-10-18
debug では動くのに、release の起動だけ「見つからない」で落ちました。名前の文字列で引いていた資源が、縮小で消えていたためです
release ビルドだけ、起動時に資源が見つからず落ちる。原因は、名前の文字列で引いていた画像や音がリソース縮小で消えていたことでした。keep.xml を prebuild で書き出す設定と、ビルド後に確かめる検査を組みました。