共用方式為


Xamarin.iOS 中的訊息應用程式延伸模組基本概念

本文說明如何在與訊息應用程式整合的 Xamarin.iOS 解決方案中包含訊息應用程式延伸模組,並將新功能呈現給使用者。

iOS 10 的新功能,訊息應用程式延伸模組會與 訊息 應用程式整合,並將新功能呈現給使用者。 延伸模組可以傳送文字、貼紙、媒體檔案和互動式訊息。

關於訊息應用程式延伸模組

如上所述,訊息應用程式延伸模組會與訊息應用程式整合,並將新功能呈現給使用者。 延伸模組可以傳送文字、貼紙、媒體檔案和互動式訊息。 有兩種類型的訊息應用程式延伸模組可供使用:

  • 貼紙套件 - 包含使用者可以新增至訊息的貼紙集合。 貼紙套件可以建立,而不需要撰寫任何程序代碼。
  • iMessage 應用程式 - 可在訊息應用程式中呈現自定義使用者介面,以選取貼紙、輸入文字,包括媒體檔案(具有選擇性類型轉換),以及建立、編輯和傳送互動訊息。

訊息應用程式延伸模組提供三個主要內容類型:

  • 互動式訊息 - 應用程式產生的自訂訊息內容類型,當使用者點選訊息時,應用程式將會在前景啟動。
  • 貼紙 - 應用程式所產生的影像,這些影像可以包含在用戶之間傳送的訊息中。
  • 其他支援的內容 - 應用程式可以提供內容,例如相片、影片、文字,或訊息應用程式一直支援的任何其他內容類型連結。

iOS 10 的新功能,訊息應用程式現在包含自己的專用內建 App Store。 任何包含 Message Apps 擴充功能的應用程式都會在此市集中顯示及升級。 新的訊息應用程式選單會顯示任何已從訊息 App Store 下載的應用程式,以提供使用者快速存取權。

在 iOS 10 中,Apple 也新增了內嵌應用程式屬性,讓使用者可以輕鬆地探索應用程式。 例如,如果某個用戶從未安裝第 2 位使用者的應用程式傳送內容到另一個使用者(例如貼紙),則傳送應用程式的名稱會列在訊息歷程記錄的內容底下。 如果使用者點選應用程式的名稱,則會開啟訊息 App Store,並在市集中選取應用程式。

訊息應用程式延伸模組與開發人員熟悉建立的現有 iOS 應用程式類似,而且他們能夠存取標準 iOS 應用程式的所有標準架構和功能。 例如:

  • 他們可以存取應用程式內購買。
  • 他們有權存取 Apple Pay。
  • 他們可以存取裝置硬體,例如 相機。

訊息應用程式延伸模組僅在iOS 10上受到支援,不過,這些延伸模組傳送的內容可在 watchOS 和macOS裝置上檢視。 新增至 watchOS 3 的新 [最近使用] 頁面 會顯示最近從手機傳送的貼紙,包括來自 Message Apps 延伸模組的貼紙,並允許使用者從手錶傳送貼紙。

關於訊息架構

iOS 10 的新功能是訊息架構,會在使用者的 iOS 裝置上提供 Message Apps 擴充功能與訊息應用程式之間的介面。 當使用者從訊息應用程式內啟動應用程式時,此架構可讓應用程式探索,並提供配置其 UI 所需的數據和內容。

應用程式啟動後,用戶會與其互動,以建立新的內容,以透過訊息共用。 然後,應用程式會使用 Messages 架構,將新建立的內容傳送至訊息應用程式進行處理。

訊息架構和訊息應用程式延伸模組是以預先存在的 iOS 應用程式延伸模組技術為基礎所建置。 如需應用程式延伸模組的詳細資訊,請參閱 Apple 的應用程式 延伸模組程式設計指南

不同於 Apple 在整個系統中提供的其他擴充點,開發人員不需要為其訊息應用程式延伸模組提供主機應用程式,因為訊息應用程式本身會作為容器。 不過,開發人員可以選擇在新的或現有的 iOS 應用程式中加入 Message Apps 延伸模組,並隨附套件組合。

如果訊息應用程式延伸模組包含在 iOS 應用程式的套件組合中,應用程式圖示將會同時顯示在裝置的主畫面和訊息應用程式抽屜的訊息應用程式中。 如果未包含在應用程式套件組合中,訊息應用程式延伸模組只會顯示在訊息應用程式選單中。

即使訊息應用程式延伸模組未包含在主機應用程式套件組合中,開發人員也需要在訊息應用程式延伸模組的套件組合中提供應用程式圖示,因為此圖示會顯示在系統的其他部分,例如訊息應用程式抽屜或 設定,以供延伸模組使用。

關於貼紙

Apple 設計貼紙作為 iMessage 用戶溝通的新方式,允許貼紙以任何其他訊息內容內嵌方式傳送,或者可以附加至交談內的先前訊息泡泡。

什麼是貼紙?

  • 它們是 Message Apps 擴充功能所提供的影像。
  • 它們可以是動畫或靜態影像。
  • 它們提供從應用程式內部共用影像內容的新方式。

有兩種方式可以建立貼紙:

  1. 貼紙套件訊息應用程式延伸模組可以從 Xcode 內部建立,而不需要包含任何程式代碼。 所有必要專案都是貼紙和應用程式圖示的資產。
  2. 藉由建立標準 Message Apps 擴充功能,透過訊息架構從程式代碼提供貼紙。

建立貼紙套件

貼紙套件是從 Xcode 內的特殊範本建立,只需提供一組靜態影像資產,即可作為貼紙使用。 如上所述,他們不需要任何程式代碼,開發人員只需將圖像檔拖曳到貼紙資產目錄內的貼紙套件資料夾中。

若要將映像包含在貼紙套件中,它必須符合下列需求:

  • 影像必須是 PNG、APNG、GIF 或 JPEG 格式。 Apple 建議在提供貼紙資產時,只使用 PNG 和 APNG 格式。
  • 動畫貼紙僅支援APNG和GIF格式。
  • 貼紙影像應該提供透明背景,因為它們可以放在使用者交談中的訊息泡泡上。
  • 個別圖像文件必須小於 500kb。
  • 影像不能小於 100x100 點,或大於 206 x 206 點。

重要

貼紙影像應一律以 @3x 300 x 300 到 618 x 618 像素範圍的解析度提供。 系統會視需要在運行時間自動產生 @2x@1x 版本。

Apple 建議針對各種不同顏色的背景測試貼紙圖像資產(例如白色、黑色、紅色、黃色和多色)和多色相片,以確保它們在所有可能的情況下看起來最好。

貼紙套件可以提供三種可用大小的貼紙之一:

  • 小型 - 100 x 100 點。
  • - 136 x 136 點。 這是預設大小。
  • - 206 x 206 點。

使用 Xcode 的屬性偵測器來設定整個貼紙套件的大小,並且只提供符合所要求大小的影像資產,以在訊息應用程式內的貼紙瀏覽器取得最佳結果。

如需詳細資訊,請參閱Apple的 訊息參考

建立自定義貼紙體驗

如果應用程式需要比貼紙套件所提供的更多控制權或彈性,它可以包含訊息應用程式延伸模組,並透過訊息架構提供貼紙,以取得自定義貼紙體驗。

建立自定義貼紙體驗有哪些優點?

  1. 允許應用程式自定義貼紙對應用程式用戶顯示的方式。 例如,若要以標準網格線配置以外的格式或不同色彩背景呈現貼紙。
  2. 允許動態建立貼紙從程序代碼建立,而不是包含在靜態影像資產中。
  3. 允許從開發人員的網頁伺服器動態下載貼紙映像資產,而不需要將新版本發行至 App Store。
  4. 允許存取裝置的相機,以即時建立貼紙。
  5. 允許應用程式內購買,讓使用者可以從應用程式內部購買更多貼紙。

若要建立自定義貼紙體驗,請執行下列動作:

  1. 啟動 Visual Studio for Mac。

  2. 開啟解決方案以新增訊息應用程式延伸模組。

  3. 選取 [iOS>擴充>功能 iMessage 擴充功能],然後按兩下一步[ 下一步] 按鈕:

    選取 [iMessage 擴充功能]

  4. 輸入延伸模組名稱,然後按下一步: 按鈕:

    輸入擴充功能名稱

  5. 按兩下 [ 建立] 按鈕以建置延伸模組:

    按一下 [建立] 按鈕

根據預設,檔案 MessagesViewController.cs 會新增至方案。 這是擴充功能的主要進入點,它會繼承自 MSMessageAppViewController 類別。

訊息架構提供類別,向用戶呈現可用的貼紙:

  • MSStickerBrowserViewController - 控制貼紙將呈現在 中的檢視。 它也符合 介面, IMSStickerBrowserViewDataSource 以傳回指定瀏覽器索引的貼紙計數和貼紙。
  • MSStickerBrowserView - 這是顯示可用貼紙的檢視。
  • MSStickerSize - 決定瀏覽器檢視中所呈現貼紙網格線的個別儲存格大小。

建立自訂貼紙瀏覽器

開發人員可以在訊息應用程式延伸模組中提供自定義貼紙瀏覽器 (MSMessageAppBrowserViewController) 來進一步自定義使用者的貼紙體驗。 自定義貼紙瀏覽器會在用戶選取貼紙以包含在訊息串流中時,變更貼紙向用戶呈現的方式。

執行下列操作:

  1. 在 Solution Pad 中,以滑鼠右鍵按兩下延伸模組的專案名稱,然後選取[新增>檔案...>iOS |Apple Watch>介面控制器

  2. 針對 [名稱] 輸入 StickerBrowserViewController ,然後按兩下 [新增] 按鈕:

    輸入 [名稱] 的 StickerBrowserViewController

  3. StickerBrowserViewController.cs開啟檔案以進行編輯。

StickerBrowserViewController.cs如下所示:

using System;
using System.Collections.Generic;
using UIKit;
using Messages;
using Foundation;

namespace MonkeyStickers
{
    public partial class StickerBrowserViewController : MSStickerBrowserViewController
    {
        #region Computed Properties
        public List<MSSticker> Stickers { get; set; } = new List<MSSticker> ();
        #endregion

        #region Constructors
        public StickerBrowserViewController (MSStickerSize stickerSize) : base (stickerSize)
        {
        }
        #endregion

        #region Private Methods
        private void CreateSticker (string assetName, string localizedDescription)
        {

            // Get path to asset
            var path = NSBundle.MainBundle.PathForResource (assetName, "png");
            if (path == null) {
                Console.WriteLine ("Couldn't create sticker {0}.", assetName);
                return;
            }

            // Build new sticker
            var stickerURL = new NSUrl (path);
            NSError error = null;
            var sticker = new MSSticker (stickerURL, localizedDescription, out error);
            if (error == null) {
                // Add to collection
                Stickers.Add (sticker);
            } else {
                // Report error
                Console.WriteLine ("Error, couldn't create sticker {0}: {1}", assetName, error);
            }
        }

        private void LoadStickers ()
        {

            // Load sticker assets from disk
            CreateSticker ("canada", "Canada Sticker");
            CreateSticker ("clouds", "Clouds Sticker");
            ...
            CreateSticker ("tree", "Tree Sticker");
        }
        #endregion

        #region Public Methods
        public void ChangeBackgroundColor (UIColor color)
        {
            StickerBrowserView.BackgroundColor = color;

        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Initialize
            LoadStickers ();
        }

        public override nint GetNumberOfStickers (MSStickerBrowserView stickerBrowserView)
        {
            return Stickers.Count;
        }

        public override MSSticker GetSticker (MSStickerBrowserView stickerBrowserView, nint index)
        {
            return Stickers[(int)index];
        }
        #endregion
    }
}

請詳細查看上述程序代碼。 它會為延伸模組提供的貼紙建立記憶體:

public List<MSSticker> Stickers { get; set; } = new List<MSSticker> ();

並覆寫 類別的 MSStickerBrowserViewController 兩種方法,以提供此資料存放區中瀏覽器的數據:

public override nint GetNumberOfStickers (MSStickerBrowserView stickerBrowserView)
{
    return Stickers.Count;
}

public override MSSticker GetSticker (MSStickerBrowserView stickerBrowserView, nint index)
{
    return Stickers[(int)index];
}

方法 CreateSticker 會從延伸模組的套件組合取得映像資產的路徑,並使用它從這個資產建立的新實例 MSSticker ,它會新增至集合:

private void CreateSticker (string assetName, string localizedDescription)
{

    // Get path to asset
    var path = NSBundle.MainBundle.PathForResource (assetName, "png");
    if (path == null) {
        Console.WriteLine ("Couldn't create sticker {0}.", assetName);
        return;
    }

    // Build new sticker
    var stickerURL = new NSUrl (path);
    NSError error = null;
    var sticker = new MSSticker (stickerURL, localizedDescription, out error);
    if (error == null) {
        // Add to collection
        Stickers.Add (sticker);
    } else {
        // Report error
        Console.WriteLine ("Error, couldn't create sticker {0}: {1}", assetName, error);
    }
}

LoadSticker 呼叫 方法 ViewDidLoad ,從具名映射資產建立貼紙(包含在應用程式的套件組合中),並將其新增至貼紙集合。

若要實作自定義貼紙瀏覽器,請編輯 MessagesViewController.cs 檔案,使其看起來如下:

using System;
using UIKit;
using Messages;

namespace MonkeyStickers
{
    public partial class MessagesViewController : MSMessagesAppViewController
    {
        #region Computed Properties
        public StickerBrowserViewController BrowserViewController { get; set;}
        #endregion

        #region Constructors
        protected ViewController (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Create new browser and configure it
            BrowserViewController = new StickerBrowserViewController (MSStickerSize.Regular);
            BrowserViewController.View.Frame = View.Frame;
            BrowserViewController.ChangeBackgroundColor (UIColor.Gray);

            // Add to view
            AddChildViewController (BrowserViewController);
            BrowserViewController.DidMoveToParentViewController (this);
            View.AddSubview (BrowserViewController.View);
        }
        #endregion
    }
}

詳細檢視此程式碼,它會建立自訂瀏覽器的記憶體:

public StickerBrowserViewController BrowserViewController { get; set;}

在方法中 ViewDidLoad ,它會具現化並設定新的瀏覽器:

// Create new browser and configure it
BrowserViewController = new StickerBrowserViewController (MSStickerSize.Regular);
BrowserViewController.View.Frame = View.Frame;
BrowserViewController.ChangeBackgroundColor (UIColor.Gray);

然後,它會將瀏覽器新增至檢視以顯示它:

// Add to view
AddChildViewController (BrowserViewController);
BrowserViewController.DidMoveToParentViewController (this);
View.AddSubview (BrowserViewController.View);

進一步貼紙自定義

在訊息應用程式延伸模組中只包含兩個類別,即可進一步自定義貼紙:

  • MSStickerView
  • MSSticker

使用上述方法,延伸模組可以支援不依賴標準貼紙瀏覽器方法的貼紙選取。 此外,貼紙顯示器可以在兩種不同的檢視模式之間切換:

  • Compact - 這是貼紙檢視佔用訊息檢視底部 25% 的預設模式。
  • 展開 -貼紙檢視會填滿整個訊息檢視。

用戶可透過程序設計方式或手動在這些模式之間切換此貼紙檢視。

請查看下列處理兩種不同檢視模式之間切換的範例。 每個狀態都需要兩個不同的檢視控制器。 會 StickerBrowserViewController 處理 Compact 檢視,如下所示:

using System;
using System.Collections.Generic;
using UIKit;
using Messages;
using Foundation;

namespace MessageExtension
{
    public partial class StickerBrowserViewController : MSStickerBrowserViewController
    {
        #region Computed Properties
        public MessagesViewController MessagesAppViewController { get; set; }
        public List<MSSticker> Stickers { get; set; } = new List<MSSticker> ();
        #endregion

        #region Constructors
        public StickerBrowserViewController (MessagesViewController messagesAppViewController, MSStickerSize stickerSize) : base (stickerSize)
        {
            // Initialize
            this.MessagesAppViewController = messagesAppViewController;
        }
        #endregion

        #region Private Methods
        private void CreateSticker (string assetName, string localizedDescription)
        {

            // Get path to asset
            var path = NSBundle.MainBundle.PathForResource (assetName, "png");
            if (path == null) {
                Console.WriteLine ("Couldn't create sticker {0}.", assetName);
                return;
            }

            // Build new sticker
            var stickerURL = new NSUrl (path);
            NSError error = null;
            var sticker = new MSSticker (stickerURL, localizedDescription, out error);
            if (error == null) {
                // Add to collection
                Stickers.Add (sticker);
            } else {
                // Report error
                Console.WriteLine ("Error, couldn't create sticker {0}: {1}", assetName, error);
            }
        }

        private void LoadStickers ()
        {

            // Load sticker assets from disk
            CreateSticker ("add", "Add New Sticker");
            CreateSticker ("canada", "Canada Sticker");
            CreateSticker ("clouds", "Clouds Sticker");
            CreateSticker ("tree", "Tree Sticker");
        }
        #endregion

        #region Public Methods
        public void ChangeBackgroundColor (UIColor color)
        {
            StickerBrowserView.BackgroundColor = color;

        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Initialize
            LoadStickers ();

        }

        public override nint GetNumberOfStickers (MSStickerBrowserView stickerBrowserView)
        {
            return Stickers.Count;
        }

        public override MSSticker GetSticker (MSStickerBrowserView stickerBrowserView, nint index)
        {
            // Wanting to add a new sticker?
            if (index == 0) {
                // Yes, ask controller to present add sticker interface
                MessagesAppViewController.AddNewSticker ();
                return null;
            } else {
                // No, return existing sticker
                return Stickers [(int)index];
            }
        }
        #endregion
    }
}

AddStickerViewController會處理展開貼紙檢視,如下所示:

using System;
using Foundation;
using UIKit;
using Messages;

namespace MessageExtension
{
    public class AddStickerViewController : UIViewController
    {
        #region Computed Properties
        public MessagesViewController MessagesAppViewController { get; set;}
        public MSSticker NewSticker { get; set;}
        #endregion

        #region Constructors
        public AddStickerViewController (MessagesViewController messagesAppViewController)
        {
            // Initialize
            this.MessagesAppViewController = messagesAppViewController;
        }
        #endregion

        #region Override Method
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Build interface to create new sticker
            var cancelButton = new UIButton (UIButtonType.RoundedRect);
            cancelButton.TouchDown += (sender, e) => {
                // Cancel add new sticker
                MessagesAppViewController.CancelAddNewSticker ();
            };
            View.AddSubview (cancelButton);

            var doneButton = new UIButton (UIButtonType.RoundedRect);
            doneButton.TouchDown += (sender, e) => {
                // Add new sticker to collection
                MessagesAppViewController.AddStickerToCollection (NewSticker);
            };
            View.AddSubview (doneButton);

            ...
        }
        #endregion
    }
}

MessageViewController 實作這些檢視控制器來驅動要求的狀態:

using System;
using UIKit;
using Messages;

namespace MessageExtension
{
    public partial class MessagesViewController : MSMessagesAppViewController
    {
        #region Computed Properties
        public bool IsAddingSticker { get; set;}
        public StickerBrowserViewController BrowserViewController { get; set; }
        public AddStickerViewController AddStickerController { get; set;}
        #endregion

        #region Constructors
        protected MessagesViewController (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Public Methods
        public void PresentStickerBrowser ()
        {
            // Is the Add sticker view being displayed?
            if (IsAddingSticker) {
                // Yes, remove it from view
                AddStickerController.RemoveFromParentViewController ();
                AddStickerController.View.RemoveFromSuperview ();
            }

            // Add to view
            AddChildViewController (BrowserViewController);
            BrowserViewController.DidMoveToParentViewController (this);
            View.AddSubview (BrowserViewController.View);

            // Save mode
            IsAddingSticker = false;
        }

        public void PresentAddSticker ()
        {
            // Is the sticker browser being displayed?
            if (!IsAddingSticker) {
                // Yes, remove it from view
                BrowserViewController.RemoveFromParentViewController ();
                BrowserViewController.View.RemoveFromSuperview ();
            }

            // Add to view
            AddChildViewController (AddStickerController);
            AddStickerController.DidMoveToParentViewController (this);
            View.AddSubview (AddStickerController.View);

            // Save mode
            IsAddingSticker = true;
        }

        public void AddNewSticker ()
        {
            // Switch to expanded view mode
            Request (MSMessagesAppPresentationStyle.Expanded);
        }

        public void CancelAddNewSticker ()
        {
            // Switch to compact view mode
            Request (MSMessagesAppPresentationStyle.Compact);
        }

        public void AddStickerToCollection (MSSticker sticker)
        {
            // Add sticker to collection
            BrowserViewController.Stickers.Add (sticker);

            // Switch to compact view mode
            Request (MSMessagesAppPresentationStyle.Compact);
        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Create new browser and configure it
            BrowserViewController = new StickerBrowserViewController (this, MSStickerSize.Regular);
            BrowserViewController.View.Frame = View.Frame;
            BrowserViewController.ChangeBackgroundColor (UIColor.Gray);

            // Create new Add controller and configure it as well
            AddStickerController = new AddStickerViewController (this);
            AddStickerController.View.Frame = View.Frame;

            // Initially present the sticker browser
            PresentStickerBrowser ();
        }

        public override void DidTransition (MSMessagesAppPresentationStyle presentationStyle)
        {
            base.DidTransition (presentationStyle);

            // Take action based on style
            switch (presentationStyle) {
            case MSMessagesAppPresentationStyle.Compact:
                PresentStickerBrowser ();
                break;
            case MSMessagesAppPresentationStyle.Expanded:
                PresentAddSticker ();
                break;
            }
        }
        #endregion
    }
}

當使用者要求將新的貼紙新增至其可用的集合時,會讓新的 AddStickerViewController 控制器成為可見控制器,而貼紙檢視會 輸入展開 的檢視:

// Switch to expanded view mode
Request (MSMessagesAppPresentationStyle.Expanded);

當使用者選擇要新增的貼紙時,它會新增至其可用的集合,並 要求 Compact 檢視:

public void AddStickerToCollection (MSSticker sticker)
{
    // Add sticker to collection
    BrowserViewController.Stickers.Add (sticker);

    // Switch to compact view mode
    Request (MSMessagesAppPresentationStyle.Compact);
}

方法 DidTransition 會覆寫以處理兩種模式之間的切換:

public override void DidTransition (MSMessagesAppPresentationStyle presentationStyle)
{
    base.DidTransition (presentationStyle);

    // Take action based on style
    switch (presentationStyle) {
    case MSMessagesAppPresentationStyle.Compact:
        PresentStickerBrowser ();
        break;
    case MSMessagesAppPresentationStyle.Expanded:
        PresentAddSticker ();
        break;
    }
}

摘要

本文涵蓋在 Xamarin.iOS 解決方案中包含訊息應用程式延伸模組,可與訊息應用程式整合,並將新功能呈現給使用者。 它涵蓋使用延伸模組來傳送文字、貼紙、媒體檔案和互動式訊息。