UWP - 使用 Deep link 串聯 web-to-app 的互動

過去介紹過 註冊 URI scheme 就利用自定義的 URI scheme 在網頁或是 App 裏面呼叫自己的 App 起來做事情。 Windows 10(14393) 加入新功能(web-to-app linking),讓 user 開啓 http/https 的網站連結時,不是開啓 web browser 而是開啓 App。

web-to-app linking 技術讓 App 與 website 可以互相串聯,例如:原本在 App 已經做好購物機制,在用戶在瀏覽網頁或是點到特定的 URL link 時就會開啓 App 進去必要的流程跟畫面。

如果 website 未註冊支援該 App,用戶點擊了連結一樣只是開啟 web browser,使用經驗是不會有影響的。

要做到這樣的效果有幾個重點:

  1. 在 App 的 package.manifest 宣告要處理的網站路徑
  2. 在該網站的 root 目錄層加入特定的檔案,裡面宣告要支援的 App package family name
  3. 在 App 加入 OnActived 的事件處理由連結送入的内容

Step1. 在 package.manifest 宣告要處理的 http 與 https link

<Application>
  <Extensions>
    <uap3:Extension Category="windows.appUriHandler">
        <uap3:AppUriHandler>
            <!-- 可以加入到 1000 組 -->
            <uap3:Host Name="botwebhook.azurewebsites.net" />
        </uap3:AppUriHandler>
    </uap3:Extension>
  </Extensions>
</Application>

uap3 來自 http://schemas.microsoft.com/appx/manifest/mobile/windows10 的定義,需要把 App 升級到 target version: 14393 才會被讀取。

另外,在 uap3 裏面還有更多的説明可以參考 uap3:AppUriHandler

Step2. 在網站的根目錄加入 JSON 格式的檔案,命名為: windows-app-web-link 不需要副檔名

[
  {
    "packageFamilyName": "d78b1add-10d6-43c8-b4d9-445edc861b0f_s1mb6h805jdtj",
    "paths": [ "*" ],
    "excludePaths" : [ "/news/*", "/blog/*" ]
  },
  {
    "packageFamilyName": "Your2ndAppsPFN",
    "paths": [ "/example/*", "/links/*" ]
  }
]

格式説明:

  • packageFamilyName:可以從 package.manifest 中取得,代表該 App
  • paths: 定義可以被註冊的網站路徑。衹有被寫在這裏的路徑,App 才會被觸發
  • excludePaths: 定義被排除不可以被訪問的網站路徑

由於網站的目錄很多層,因此,可以利用萬用字元(wildcards)來定義,如下説明:

Wildcard Description
\* Represents any substring
? Represents a single character

例如上述範例, /news/* 代表 news 目錄下的檔案都可以存取;如果是 /new*/ 代表是任何 new 起頭的目錄都可以使用;

盡量多使用 excludePaths 規範 App 所要支援的範圍,避免用戶點擊 link 後進入到 App 不能處理的範圍反而更糟糕。

放在 web server 根目錄的 JSON 檔案會在 App 被安裝的時候,Windows 系統利用 https 連線去檢查是否符合格式

Step3. App.xaml.cs 註冊處理 OnActivated 事件

protected override void OnActivated(IActivatedEventArgs e)
{
    Frame rootFrame = Window.Current.Content as Frame;
    if (rootFrame == null)
    {
       // 建立 rootFrame 邏輯與還原之前的 App 狀態
    }

    // Check ActivationKind, Parse URI, and Navigate user to content
    Type deepLinkPageType = typeof(MainPage);
    if (e.Kind == ActivationKind.Protocol)
    {
        var protocolArgs = (ProtocolActivatedEventArgs)e;        
        switch (protocolArgs.Uri.AbsolutePath)
        {
            // ... 利用 url path 來拆解要前往的目錄
        }
    }

    // Default navigation
    rootFrame.Navigate(deepLinkPageType, e);

    // Ensure the current window is active
    Window.Current.Activate();
}

上面是截取 Support web-to-app linking with app URI handlers 的程式片段。

可以看出在 JSON 裏面定義的路徑,在 OnActivated 事件拿到的就是可存取範圍的 path,藉由拆開 path 轉還到特定的頁面,link 裏面有帶一些 query string 一樣可以被處理。

 

[補充]

1. 根據 Support web-to-app linking with app URI handlers 提到:

  • 需要確定寫在 windows-app-web-link 裡的路徑(link) 都是 App 可以處理的,如果不行要記得移除以免用戶錯亂
  • 在宣告處理多個 host 時,要注意 www.example.com 與 example.com 是不同的 host
  • 用戶可以自行從設定中選擇開啓 link 的對象是誰
  • windows-app-web-link 檔案必須上傳到有支援 https 的 server
  • 如果需要更換支援的 link,不需要更新 App 只要更新 windows-app-web-link 檔案,用戶在 1-8 天之内就會更新
  • 宣告在 package.manifest 的 host 時,系統會自動去驗證該 host 是否有 windows-app-web-link 檔案,不需要自己上傳
  • This feature works whenever your app is a UWP app launched with LaunchUriAsync or a Windows desktop app launched with ShellExecuteEx. If the URL corresponds to a registered App URI handler, the app will be launched instead of the browser.

2. 如果在 Desktop 下, 開啓 Edge (或是其他的 browser) 點擊 link 是不會開啓 App 的,只能透過 Windows Key + R 輸入要測試的 link 。

    或是把 link 傳給其他的 app (例如:LINE, Facebook messenger) 從裡面點擊 link 也是可以。

3. 在 Mobile 下,在 Edge 裏面點擊註冊 host 的 link 是可以直接開啓 App 的 4. 如果想要從設定裏面調整 apps for websites 的設定可以參考下圖:

  • Mobile 在 settings/Apps/Apps for websites
  • Desktop 在 settings/System/Apps for websites

[範例程式]

Link: DeeplinkSample

根據上面介紹的内容,我建立一個比較常見的網站範例來做說明,例如:網站有分語系,分功能範圍,因此網址如下:

  • https://{domain}/{language}/{function}/{path}
  • {language} 提供: en, tw, cn
  • {function} 提供: food, book, ticket
  • {path} 屬於隨意檔案類型: *
  • host name: depplinksampleweb.azurewebsites.net

參考上面的説明,需要在 windows-app-web-link 這個 JSON 定義開發對應的路徑,如下:

[
  {
    "packageFamilyName": "5a578a94-4456-40e4-ac47-7ce11352856b_s1mb6h805jdtj",
    "paths": [ "/en/*", "/tw/*", "/cn/*" ],
    "excludePaths": [ "/en/food/*", "/tw/food", "/cn/food/" ]
  }
]

接著在 UWP 的 package.manifest 加入 windows.appUriHandler 的定義,以及 OnActivated 的事件:

protected override void OnActivated(IActivatedEventArgs args)
{
    var rootFrame = GetOrCreateRootFrame(null);

    if (args.Kind != ActivationKind.Protocol)
    {
         return;
    }

    var protocolArgs = args as ProtocolActivatedEventArgs;

    // linkL https://{domain}/{language}/{function}/{file}?{query_string}
    Uri linkUri = protocolArgs.Uri;

    Type pageType = typeof(MainPage);
    // 利用 {function} 路徑識別,如果 {file} 也是判斷依據可以再寫下一層的邏輯
    switch (linkUri.Segments[2].Replace("/",string.Empty))
    {
         case "book":
              pageType = typeof(BookPage);
              break;
         case "ticket":
              pageType = typeof(TicketPage);
              break;
         default:
              break;
    }

    rootFrame.Navigate(pageType, linkUri.Query);
}

根據拿到的 link 做拆解,因爲可以拿得到 query string 的内容,更可以拿來做一些判斷,非常容易。

======

這個用途在 Android, iOS 系統很常見,作爲 UWP 開發人員是一定要加入的。趕快來試看看吧,希望對大家有幫助。

References: