「ブラウザのリンクや他のアプリから、myapp://... で自分のアプリを起動したい」——OAuthのコールバックや”アプリで開く”リンクを作ろうとすると、この仕組みが必要になります。これが プロトコルアクティベーション(独自URIによるアプリ起動、いわゆるディープリンク)です。
私自身、最初は「登録方法がパッケージ版と非パッケージ版で違う」「OnLaunched だけではURIが取れない」といった所で詰まりました。この記事では、その全体像と勘所を、WinUI初心者向けに整理します。基礎はWinUI入門記事、ウィンドウまわりの実装はウィンドウ操作入門(WinUIEx / CsWin32)も参考になります。
Table of contents
Open Table of contents
プロトコルアクティベーションとは
独自のURIスキーム(例: myapp://)をOSに登録し、そのURIが呼ばれたときに自分のアプリが起動・前面化する仕組みです。Webページの https:// や mailto: と同じ発想で、自分専用のスキームを持てる、と考えると分かりやすいです。
主な使いどころは次のとおりです。
- OAuth/外部認証の戻り先 … ブラウザ認証後に
myapp://callback?...でアプリへ戻す - Webからアプリ起動 … サイトのボタンから対応アプリを開く
- アプリ間連携 … 別アプリから特定画面をパラメータ付きで開く
全体の流れ(3ステップ)
やることは、大きく3つだけです。
- URIスキームを登録する(
myappを自分のアプリに紐づける) - 起動時にアクティベーションの種別を判定する(プロトコル起動かどうか)
- URIを取り出して処理する(パラメータに応じて画面を開くなど)
以下、順に見ていきます。最初のステップに、最大のハマりどころがあります。
ステップ1:スキームの登録(パッケージ / 非パッケージで違う)
ここが分岐点です。アプリがMSIXパッケージかどうかで、登録方法が変わります。
パッケージ版(MSIX) … Package.appxmanifest に宣言を書きます(Visual Studioのマニフェストエディタの「宣言」→「プロトコル」からでも追加できます)。
<Extensions>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="myapp">
<uap:DisplayName>My App</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
</Extensions>
非パッケージ版 … マニフェストが無いので、起動時にコードで登録します。Microsoft.Windows.AppLifecycle の ActivationRegistrationManager を使います。登録はユーザー単位で永続化されるため、毎回起動時に呼んでも問題ありません。
using Microsoft.Windows.AppLifecycle;
ActivationRegistrationManager.RegisterForProtocolActivation(
"myapp", "", "My App", "");
ステップ2・3:アクティベーションを受け取る
登録できたら、起動時に「どう起動されたか」を判定してURIを取り出します。WinUIでは、OnLaunched だけではプロトコル起動の情報を取れない点に注意が必要です。AppInstance.GetCurrent().GetActivatedEventArgs() を起動のできるだけ早い段階で呼ぶのがポイントです。
using Microsoft.Windows.AppLifecycle;
using Windows.ApplicationModel.Activation;
var args = AppInstance.GetCurrent().GetActivatedEventArgs();
if (args.Kind == ExtendedActivationKind.Protocol)
{
var data = args.Data as ProtocolActivatedEventArgs;
Uri uri = data.Uri; // 例: myapp://open?id=42
// ↓ uri を検証してから、対応する画面を開く
}
uri からホストやクエリを読み取り、目的の画面へ遷移させれば完成です。
見落としがちな「単一インスタンス」問題
もう一つの勘所が、多重起動です。WinUIアプリは既定で複数のインスタンスが起動できるため、URIが呼ばれるたびに新しいウィンドウが増えてしまうことがあります。多くの場合、望みは「既に起動しているアプリにURIを渡す」ことのはずです。
これを実現するには、アプリを単一インスタンスにして、2つ目以降の起動を最初のインスタンスへリダイレクトします。おおまかには次の流れです。
Program.csに独自のMainを用意するAppInstance.FindOrRegisterForKey(...)で自分が最初のインスタンスか判定- 最初でなければ
RedirectActivationTo(...)で起動を最初のインスタンスへ渡して終了
実装には定型のコードが必要になりますが、まずは「プロトコル起動を使うなら単一インスタンス化がほぼ必須」という勘所を押さえておけば十分です(具体的な実装は少し長くなるため、ここでは概要に留めます)。
セキュリティ:URIは信頼しない
プロトコルアクティベーションで最重要なのがこれです。あなたのスキームは、どのアプリ・どのWebサイトからでもURIを送れます。つまり受け取るURIは、常に「信頼できない外部入力」として扱う必要があります。
- 不可逆な操作をURIだけで実行しない(削除・送信・課金など)
- パラメータは必ず検証・サニタイズする(想定外の値や
../などをはじく) - 呼び出し元は識別できない(誰が送ったURIかを確認する手段はない)
- URI値をそのまま実行系に渡さない(
Process.StartやSQLへ直接渡さない)
「便利な入口」は「攻撃の入口」にもなり得ます。ここは必ず設計に織り込んでください。
動作確認とまとめ
登録できたかは、ブラウザのアドレスバーや「ファイル名を指定して実行」に myapp://test と入れる、あるいはコードから Windows.System.Launcher.LaunchUriAsync(new Uri("myapp://test")) を呼べば確認できます。アプリが起動すれば成功です。
要点をまとめます。
- 仕組み … 独自URIスキームを登録し、呼ばれたら起動するディープリンク
- 登録 … パッケージはマニフェスト、非パッケージはコード(
ActivationRegistrationManager) - 受け取り …
AppInstance.GetCurrent().GetActivatedEventArgs()で種別を判定しURI取得 - 単一インスタンス化 … 多重起動を防ぎ、既存インスタンスへリダイレクト
- セキュリティ … URIは信頼しない。検証を徹底する
まずは「登録 → 受け取り」を最小構成で動かしてみると、一気に理解が進みます。OAuthのコールバックなど実用シーンで、そのまま応用できる仕組みです。
