URL Scheme — モバイルアプリがオペレーティングシステムに登録するカスタムURIプロトコルで、myapp://pathのようなリンクから開かれます。RFC 3986によると、URIスキームはアドレスの後続すべてのコンポーネントの構文とセマンティクスを定義します。このようなリンクに移動すると、システムは一意の識別子によって登録されたアプリを識別し、リンクから抽出されたパラメータを使用してアプリを起動します。URL Schemeに基づくディープリンクは、より最新の代替手段の出現にもかかわらず、モバイルプラットフォームにおけるアプリ間ナビゲーションの基本メカニズムであり続けています。
重要なポイント
URL Scheme — アプリがカスタムリンクを介して呼び出しを受信するためにオペレーティングシステムに登録する一意のプロトコル識別子です。ユーザーがmyapp://profile/123のようなリンクをクリックすると、システムはmyappスキームを登録したアプリを識別し、完全なURIとともに制御を渡します。このメカニズムにより、アプリはサーバーインフラストラクチャを必要とせずにデータを交換し、相互に開くことができます。
URL Schemeの概念は、ウェブ標準RFC 3986から直接借用されています。RFC 3986では、URIスキームがユニバーサルリソース識別子の最初のコンポーネントです。モバイル開発では、このアイデアはアプリ間通信に適応され、HTTPサーバーの代わりにアプリ自体がリンクハンドラーとして機能します。
多くの人気アプリは、サードパーティサービスとの統合のために独自のURL Schemeを登録しています。たとえば、Spotifyはspotify://スキームを使用し、Telegramはtg://を使用し、Instagramはinstagram://を使用します。開発者はまた、内部ナビゲーションとエンドツーエンドの画面テストのためにappname://スキームを作成することがよくあります。
URL Schemeは、アプリの特定のセクションへの即時ナビゲーションが必要なプッシュ通知、メールニュースレター、QRコードで今でも広く使用されています。ただし、iOS 9とAndroid 6以降、単純なスキームを徐々に補完および置き換える代替メカニズムが登場しました。
カスタムURIの構造は一般的なRFC 3986仕様に従い、複数のコンポーネントで構成されています。スキームが最初に指定され、コロンでアドレスの残り部分から区切られます。スキームの後には、ホスト、ポート、パス、クエリパラメータ、フラグメントが続くことがあり、それぞれオプションです。
完全な構文はscheme://host/path?key=value#fragmentのようになります。スキームが唯一の必須要素であり、残りは特定の実装のニーズによって決定されます。スキームの後のダブルスラッシュは歴史的にHTTPから借用されたもので、仕様上厳密には必須ではありませんが、慣例として広く使用されています。
URI構造を視覚的に表現するために、コンポーネントテーブルが使用されます。各要素には目的と必須レベルがあります。
| コンポーネント | 例 | 必須 |
|---|---|---|
| Scheme | myapp | はい |
| Host | profile | いいえ |
| Path | /user/42 | いいえ |
| Query | ?id=42&tab=main | いいえ |
| Fragment | #section2 | いいえ |
開発者はURI構造を自由に選択でき、柔軟性が生まれますが、アプリの異なるバージョン間で互換性の問題が発生します。URL Schemeの形式をアプリの公開APIの一部として文書化し、変更時にバージョン管理することをお勧めします。
iOSでは、プロジェクトのInfo.plistファイルに各URL Schemeを明示的に登録する必要があります。開発者はCFBundleURLTypes配列を追加し、その各要素には識別子(CFBundleURLName)とサポートされるスキームのリスト(CFBundleURLSchemes)が含まれます。登録後、システムは登録されたスキームへの着信コールすべてを自動的にアプリに転送します。
着信URL Schemeの処理は、アプリデリゲートのapplication(_:open:options:)メソッドを介して行われます。このメソッドはURLオブジェクトを受け取り、そこからパスとクエリパラメータを抽出してナビゲーションの決定を行います。ハンドラーは操作の成功を示すBool値を返す必要があります。
以下は、SwiftでのURL Schemeハンドラーの実装例です。このコードは、URLComponentsを使用して着信URIからホストとクエリパラメータを抽出する方法を示しています。
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any]
) -> Bool {
let host = url.host
let params = URLComponents(
url: url,
resolvingAgainstBaseURL: false
)?.queryItems
if host == "profile" {
navigateToProfile(params)
}
return true
}
このメソッドは、クエリパラメータの安全な解析にURLComponentsを使用します。このアプローチは手動の文字列解析よりも推奨されます。パラメータ値のパーセントエンコーディングと特殊文字のデコードを自動的に処理するためです。
AndroidはIntent Filterシステムを使用して、URL Schemeに基づくディープリンクをルーティングします。開発者は、リンクを処理するActivityタグ内でAndroidManifest.xmlにフィルターを宣言します。フィルターにはVIEWアクション、BROWSABLEおよびDEFAULTカテゴリ、そしてスキーム、ホスト、pathPrefixを指定するdataタグが含まれます。
ユーザーがカスタムスキームのリンクをクリックすると、システムはインストールされているすべてのアプリのIntent Filterをチェックします。複数の一致するアプリが見つかった場合、ユーザーには選択ダイアログが表示されます。BROWSABLEカテゴリにより、ブラウザからのリンク処理が可能になります。
Activityでmyappスキームを処理するためのAndroidManifest.xmlでのIntent Filter宣言の例。正しいディープリンクルーティングには、actionとcategoryの組み合わせが必須です。
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category
android:name="android.intent.category.DEFAULT" />
<category
android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="myapp"
android:host="profile"
android:pathPrefix="/user" />
</intent-filter>
</activity>
Activityでフィルターを設定した後、URIを取得するにはintent.getData()を呼び出す必要があります。intentとデータがnullでないことを確認することが重要です。Activityは、ランチャーからの標準起動時など、着信ディープリンクなしで起動される場合があるためです。
URL Schemeのクエリパラメータは、疑問符の後にkey=value形式で、アンパサンドで区切られて渡されます。この形式はHTTPリクエストと同じで、プラットフォームの標準ツールで簡単に処理できます。許可されたURI文字セットに含まれないすべての文字について、パーセントエンコーディングを使用してパラメータをエンコードする必要があります。
パラメータを含む完全なリンクの例:myapp://profile?userId=42&source=email&ref=abc123。URLを抽出した後、アプリはすべてのクエリアイテムを順次解析し、その値に基づいてターゲット画面へのナビゲーションを決定します。
複雑なデータを渡す際は、URIの長さ制限を考慮することが重要です。iOSでは、URL Schemeの最大長は2 KBに制限されており、それを超えるとシステムがリンクを切り詰めます。Androidでは制限は約8 KBですが、正確な値はOSのバージョンとデバイスの製造元によって異なります。大量のデータの場合は、URL Schemeを介してセッション識別子のみを渡し、残りのデータはサーバーからロードすることをお勧めします。
URL Schemeの主な欠点は、アプリがデバイスにインストールされていない場合にリンクを処理できないことです。ブラウザはエラーを表示し、ユーザーはナビゲーションのコンテキストを失います。この問題を解決するために、AppleはiOS 9でUniversal Linksを、GoogleはAndroid 6でApp Linksを導入しました。どちらのメカニズムも、アプリに関連付けられたウェブドメインを介して登録されます。
Universal LinksとApp Linksは通常のHTTPSリンクのように機能しますが、アプリがインストールされている場合は選択ダイアログなしでアプリを開きます。アプリがインストールされていない場合、リンクは同じドメインのウェブページを開き、ユーザーエクスペリエンスを維持します。これにより、本番環境ではこれらが優先的な代替手段となります。
iOSおよびAndroidのURL Schemeには、組み込みのフォールバックメカニズムはありません。開発者は中間サーバーソリューションを使用します。リンクはJavaScriptを介してアプリのインストールを確認するウェブページに移動し、スキームまたはアプリストアにリダイレクトします。Firebase Dynamic LinksとBranch.ioは、インストール状況を自動的に判断し、カスタムサーバーパイプラインを開発する必要なくユーザーをルーティングするディファードディープリンクをサポートする、この問題の既製ソリューションを提供しています。
iOS 15+およびAndroid 12+でURL Schemeを使用する場合、プライバシールールが厳格化されているため、さらなる複雑さが生じます。Safariは事前確認なしに未登録のスキームを開く試みをブロックし、Android 12はPackageManagerを介したインストール済みアプリの可視性を制限します。これらの変更により、アプリ間通信のためのURL Schemeの使用は、以前のプラットフォームバージョンよりも信頼性が低くなっています。
よくある質問
URL Schemeは暗号化なしのカスタムプロトコルを使用しますが、Universal Linksはドメイン検証付きのHTTPSを介して機能します。Universal Linksはアプリ選択ダイアログを表示せず、アプリがデバイスにインストールされていない場合でも正しく処理されます。
はい、ただしすべての非ASCII文字はRFC 3986に従ってパーセントエンコーディングを使用してエンコードする必要があります。古いOSバージョンやブラウザとの互換性を確保するには、URL Schemeでのキリル文字の使用を避けることをお勧めします。
iOSでもAndroidでも、スキームの数に制限はありません。実際には、アプリは1つから5つのスキームを使用します。たとえば、Telegramはtg://、t.me/、telegram://、telegram.me://のスキームを登録しています。
iOSではcanOpenURL(_:)メソッドを使用し、スキームが登録されている場合trueを返します。AndroidではPackageManager.queryIntentActivities()を介して確認します。どちらのプラットフォームでも、構成でスキームを事前に指定する必要があります。
いいえ、URL Schemeはデータを暗号化しません。同じスキームを登録したアプリはリンクを傍受できます。セキュリティのためには、HTTPSを使用したUniversal Linksまたはプロトコルレベルでのエンドツーエンド暗号化を使用してください。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。