プロトコルアクティベーションに対応する方法
「タイムライン」にカードを表示できるようになりましたが、それだけではカードをクリックしても何も起きません。プロトコルアクティベーションに対応したアプリにする必要があります。
UWPアプリでは、次の2つの作業が必要です。
- マニフェストに宣言する:アプリケーションマニフェストの[宣言]タブでアクティベーションURIのスキーム(プロトコル)を追加します
- プロトコルアクティベーションを処理する:App.xaml.csでOnActivatedメソッドをオーバーライドします。引数に渡されたProtocolActivatedEventArgsを見て、以前の状態を復元します
マニフェストでプロトコルを宣言する
Visual Studioのソリューションエクスプローラーで「Package.appxmanifest」ファイルをダブルクリックしてマニフェストエディターを開きます。[宣言]タブを選び、[使用可能な宣言]で[プロトコル]を選んで[追加]ボタンをクリックし、[名前]欄にアクティベーションURIのスキーム(「:」は含みません)を入力します(次の画像)。[名前]欄の上の[ロゴ]と[表示名]はオプションです。[名前]欄より下の項目は、通常はどれも変更しません。
これで、このUWPアプリを配置したときに、アクティベーションURIが自動的に登録されます。
プロトコルアクティベーションを処理する
普通にUWPアプリを起動したときはOnLaunchedメソッドが呼び出されますが、プロトコルアクティベーションではOnActivatedメソッドが呼ばれます。アプリがすでに実行中であってもOnActivatedメソッドが呼び出されます。プロトコル以外の方法でアクティブ化されたときもOnActivatedメソッドは呼び出されるので、メソッド内ではプロトコルアクティベーションかどうかの判定が必要です。
プロトコルアクティベーションの場合はOnActivatedメソッドに渡される引数がProtocolActivatedEventArgs型(Windows.ApplicationModel.Activation名前空間)なので、そのUriプロパティからアクティベーションURIを取得して、アプリの状態を復元する処理を行います。
起動時にアプリの状態を復元するには、そのために必要な情報を表す(または、その情報へのキーとなる)文字列をNavigateメソッドの第2引数としてページ遷移し、遷移先で状態を復元します。
すでに起動している状態でアプリの状態を復元するときは、起動時と同様にしてもよいです。ただし、それでは状態を変更しなくてもよいときでも、画面が初期化されてしまいます。例えば、このサンプルでは、復元するべきユーザーアクティビティと同じWebページをすでに表示していた場合、画面が初期化される(=Webページが再読み込みされ、スクロール位置が初期化される)のは好ましくありません。そこで、すでに起動している状態でプロトコルアクティベーションを受けた場合には、状態を変える必要がなければ変更しないようにする処理を入れた方がよいでしょう。
以上の処理を記述したコードを次に示します。まずApp.xaml.csの該当部分から。
// アクティベーション時に呼び出されるメソッド
protected override void OnActivated(IActivatedEventArgs args)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
// 起動していないときにアクティベートされた場合は Frame がないので
// 新しく Frame を生成しておく
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
Window.Current.Content = rootFrame;
}
// アクティベートされたプロトコルの種類をチェックして、引数を適切な型にキャストする
if (args.Kind == ActivationKind.Protocol
&& args is ProtocolActivatedEventArgs protocolEventArgs)
{
// プロトコルアクティベーションの場合、その Uri プロパティがアクティベーション URI
switch (protocolEventArgs.Uri.Host)
{
case "url":
// Query の先頭文字 ('?') を除いた部分が表示すべき URL
string url = protocolEventArgs.Uri.Query.Substring(1);
MainPageNavigate(url); // 状態を復元する(ここでは、Webページを表示するだけ)
break;
default:
throw new ArgumentOutOfRangeException();
}
}
Window.Current.Activate();
}
void MainPageNavigate(string url)
{
Frame rootFrame = Window.Current.Content as Frame;
if(rootFrame.Content is MainPage mainPage)
// すでに実行中で、しかも MainPage を表示している場合
mainPage.Navigate(url);
// ↑この Navigate メソッドは、表示中のURLと同じURLが渡されたときは表示を変更しない
else
// 起動時、または、起動していても MainPage を表示していない場合
rootFrame.Navigate(typeof(MainPage), url);
}
続いて、MainPage.xaml.csの該当部分です。
// このページに遷移してきたときに呼び出されるメソッド
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
// 引数に (空でない) 文字列が入っていたら、URL として Web ページを表示する
if (e.Parameter is string url && !string.IsNullOrWhiteSpace(url))
Navigate(url);
}
// 表示している Web ページを変更するメソッド
internal async void Navigate(string url)
{
if (this.WebView1.Source?.ToString() == url)
{
// 現在表示している URL と同じなら、何もせずに「タイムライン」への登録だけ行う
await TimelineLIb.TimelineHelper.Current.AddToTimelineAsync(url, GetCardType());
}
else
{
// 現在表示している URL と異なっているなら、その Web ページを表示する
this.UrlTextBox.Text = url;
this.WebView1.Navigate(new Uri(url));
// ↑ Web ページの表示に成功すると「タイムライン」への登録が行われる
}
}
