Xamarin.iOS での Message App Extension の基本
この記事では、メッセージ アプリと統合してユーザーに新しい機能を提供する Message App Extension を Xamarin.iOS ソリューションに組み込む方法について説明します。
iOS 10 の新機能であるメッセージ アプリ拡張機能はメッセージ アプリと統合され、ユーザーに新しい機能を提供します。 この拡張機能を使うと、テキスト、ステッカー、メディア ファイル、対話型メッセージを送信できます。
Message App Extension について
前に説明したように、Message App Extension はメッセージ アプリと統合して、ユーザーに新しい機能を提供します。 この拡張機能を使うと、テキスト、ステッカー、メディア ファイル、対話型メッセージを送信できます。 2 種類の Message App Extension を使用できます。
- Sticker Pack - ユーザーがメッセージに追加できるステッカーのコレクションが含まれています。 Sticker Pack は、コードを記述せずに作成できます。
- iMessage App - ステッカーの選択、テキストの入力、メディア ファイルの追加 (オプションの型変換を含む)、対話型メッセージの作成、編集、送信のためのカスタム ユーザー インターフェイスを、メッセージ アプリ内で表示できます。
Message App Extension で提供されている主要なコンテンツ タイプは次の 3 つです。
- 対話型メッセージ: アプリによって生成されるカスタム メッセージ コンテンツの一種であり、ユーザーがメッセージをタップすると、フォアグラウンドでアプリが起動されます。
- ステッカー: ユーザー間で送信されるメッセージに含めることができる、アプリによって生成される画像です。
- サポートされている他のコンテンツ: アプリでは、メッセージ アプリによって常にサポートされている他の任意のコンテンツ タイプに、写真、ビデオ、テキスト、リンクなどのコンテンツを提供できます。
iOS 10 の新機能として、メッセージ アプリは独自の専用の組み込み App Store を含むことができるようになりました。 Message App Extension を含むアプリはすべて、このストアに表示されて、販売促進が行われます。 新しいメッセージ アプリ ドロワーには、ユーザーがすぐにアクセスできるように、Messages App Store からダウンロードされたアプリがすべて表示されます。
また、iOS 10 の新機能として、Apple はユーザーがアプリを見つけやすくなるインライン アプリ属性を追加しました。 たとえば、あるユーザーが別のユーザーに対し、別のユーザーがインストールしていないアプリ (ステッカーなど) からコンテンツを送信した場合、送信元のアプリがメッセージ履歴でコンテンツの下に一覧表示されます。 ユーザーがアプリの名前をタップすると、Message App Store が開き、ストアでアプリが選択されます。
Message App Extension は、開発者が作成し慣れている既存の iOS アプリに似ており、標準の iOS アプリのすべての標準フレームワークと機能にアクセスできます。 次に例を示します。
- In-App Purchase にアクセスできます。
- Apple Pay にアクセスできます。
- カメラなどのデバイス ハードウェアにアクセスできます。
Message App Extension は iOS 10 でのみサポートされていますが、この拡張機能によって送信されるコンテンツは、watchOS および macOS デバイスで表示できます。 watchOS 3 に追加された新しい "[Recents] ページ" には、Message App Extension からのものを含め、スマートフォンから送信された最近のステッカーが表示され、ユーザーはウォッチからそれらのステッカーを送信できます。
メッセージ フレームワークについて
iOS 10 の新機能であるメッセージ フレームワークは、Message App Extension とユーザーの iOS デバイス上のメッセージ アプリの間のインターフェイスを提供します。 ユーザーがメッセージ アプリ内からアプリを起動すると、このフレームワークによってアプリが検出され、UI のレイアウトに必要なデータとコンテキストが提供されます。
アプリが起動されると、ユーザーはそれと対話して新しいコンテンツを作成し、メッセージを介して共有します。 その後、アプリはメッセージ フレームワークを使って、新しく作成されたコンテンツを処理のためにメッセージ アプリに転送します。
メッセージ フレームワークと Message App Extension は、既存の iOS App Extension テクノロジを基にして構築されています。 App Extension について詳しくは、Apple の「アプリ拡張機能プログラミング ガイド」をご覧ください。
Apple がシステム全体で提供している他の拡張ポイントとは異なり、メッセージ アプリ自体がコンテナーとして機能するため、開発者は Message App Extension に対してホスト アプリを提供する必要はありません。 ただし、開発者は、新規または既存の iOS アプリ内に Message App Extension を組み込んで、バンドルと共に配布できます。
Message App Extension が iOS アプリのバンドルに含まれている場合、デバイスのホーム画面と、メッセージ アプリ内からのメッセージ アプリ ドロワーの両方に、アプリのアイコンが表示されます。 アプリのバンドルに含まれない場合は、Message App Extension はメッセージ アプリ ドロワーにのみ表示されます。
Message App Extension がホスト アプリ バンドルに含まれない場合でも、開発者は Message App Extension のバンドルでアプリ アイコンを提供する必要があります。これは、メッセージ アプリ ドロワーや設定などのシステムの他の部分で、拡張機能に対して表示されるアイコンであるためです。
ステッカーについて
Apple は、ステッカーを他のメッセージ コンテンツと同じようにインラインで送信したり、会話内の以前のメッセージ バブルに添付できるようにして、ステッカーを iMessage ユーザーの新しい通信手段として設計しました。
ステッカーとは
- それは、Message App Extension が提供する画像です。
- アニメーションまたは静的な画像を使用できます。
- それは、アプリ内から画像コンテンツを共有する新しい方法を提供します。
ステッカーを作成するには 2 つの方法があります。
- Sticker Pack Message App Extension は、コードを含めずに Xcode 内から作成できます。 必要なのは、ステッカーとアプリ アイコン用のアセットだけです。
- メッセージ フレームワークを介してコードからステッカーを提供する標準の Message App Extension の作成。
Sticker Pack の作成
Sticker Pack は、Xcode 内の特別なテンプレートから作成され、ステッカーとして使用できる静的な画像アセットのセットを提供するだけです。 前に説明したように、コードは必要なく、開発者は、画像ファイルをステッカー アセット カタログ内の Sticker Pack フォルダーにドラッグするだけです。
Sticker Pack に含める画像は、次の要件を満たしている必要があります。
- 画像は PNG、APNG、GIF、または JPEG 形式である必要があります。 Apple は、ステッカー アセットを提供するときは PNG と APNG 形式のみを使うことを推奨しています。
- アニメーション化されたステッカーは、APNG と GIF 形式のみをサポートします。
- ステッカー画像では、ユーザーが会話内のメッセージ バブルの上に配置できるよう、透明な背景を提供する必要があります。
- 個々の画像ファイルは 500 KB 未満にする必要があります。
- 画像を 100 x 100 ポイントより小さく、または 206 x 206 ポイントより大きくすることはできません。
重要
ステッカー画像は、常に 300 x 300 から 618 x 618 ピクセルの範囲の @3x
解像度で提供する必要があります。 システムは、必要に応じて実行時に @2x
と @1x
バージョンを自動的に生成します。
Apple は、さまざまな色の背景 (白、黒、赤、黄、多色など) と写真の上でステッカー画像アセットをテストして、可能性のあるすべての状況で最適に見えるのを確認することを推奨しています。
Sticker Pack は、使用可能な 3 つのサイズのいずれかでステッカーを提供できます。
- 小: 100 x 100ポイント。
- 中: 136 x 136 ポイント。 これが既定のサイズです。
- 大: 206 x 206 ポイント。
メッセージ アプリ内のステッカー ブラウザーで最適な結果になるよう、Xcode の属性インスペクターを使って Sticker Pack 全体のサイズを設定し、要求されたサイズに一致する画像アセットのみを提供します。
詳細については、Apple のメッセージ リファレンスに関するページを参照してください。
カスタム ステッカー エクスペリエンスの作成
Sticker Pack によって提供されるもの以上の制御や柔軟性がアプリで必要な場合は、Message App Extension を組み込み、カスタム ステッカー エクスペリエンス用にメッセージ フレームワーク経由でステッカーを提供できます。
カスタム ステッカー エクスペリエンスを作成すると、次のような利点があります。
- アプリのユーザーにステッカーを表示する方法を、アプリでカスタマイズできます。 たとえば、標準のグリッド レイアウト以外の形式や、異なるの色の背景で、ステッカーを表示します。
- ステッカーを、静的な画像アセットとして組み込むのではなく、コードから動的に作成できます。
- App Store に新しいバージョンをリリースする必要なしに、ステッカー画像アセットを開発者の Web サーバーから動的にダウンロードできます。
- デバイスのカメラにアクセスして、ステッカーをその場で作成できます。
- ユーザーがアプリ内からさらにステッカーを購入できるよう、In-App Purchase に対応します。
カスタム ステッカー エクスペリエンスを作成するには、次のようにします。
既定では、MessagesViewController.cs
ファイルがソリューションに追加されます。 これは拡張機能へのメイン エントリ ポイントであり、MSMessageAppViewController
クラスを継承します。
メッセージ フレームワークから、使用できるステッカーをユーザーに表示するためのクラスが提供されます。
MSStickerBrowserViewController
: ステッカーが表示されるビューを制御します。 また、IMSStickerBrowserViewDataSource
インターフェイスに準拠して、ステッカー数と、指定されたブラウザー インデックスのステッカーを返します。MSStickerBrowserView
: これは、使用できるステッカーが表示されるビューです。MSStickerSize
: ブラウザー ビューに表示されるステッカーのグリッドの個々のセル サイズを決定します。
カスタム ステッカー ブラウザーの作成
開発者は、Message App Extension でカスタム ステッカー ブラウザー (MSMessageAppBrowserViewController
) を提供して、ユーザーに対するステッカー エクスペリエンスをさらにカスタマイズできます。 カスタム ステッカー ブラウザーは、ユーザーがメッセージ ストリームに含めるステッカーを選んだときのステッカーの表示方法を変更します。
次の操作を行います。
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
クラスの 2 つのメソッドをオーバーライドして、このデータ ストアからブラウザーのデータを提供します。
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);
ステッカーをさらにカスタマイズする
Message App Extension に 2 つのクラスを含めるだけで、ステッカーをさらにカスタマイズできます。
MSStickerView
MSSticker
上の方法を使うと、拡張機能で標準のステッカー ブラウザー メソッドに依存しないステッカーの選択をサポートできます。 さらに、ステッカーの表示は、2 つの異なるビュー モード間で切り替えることができます。
- コンパクト: これは、ステッカー ビューがメッセージ ビューの下部 25% を占める既定のモードです。
- 展開: ステッカー ビューがメッセージ ビュー全体に表示されます。
プログラムまたはユーザーが手動で、このステッカー ビューのこれらのモードを切り替えることができます。
2 つの異なるビュー モード間の切り替えを処理する次の例を見てみましょう。 状態ごとに、2 つの異なるビュー コントローラーが必要です。 StickerBrowserViewController
はコンパクト ビューを処理し、次のようになります。
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);
ユーザーが追加するステッカーを選ぶと、それが使用可能なコレクションに追加されて、コンパクト ビューが要求されます。
public void AddStickerToCollection (MSSticker sticker)
{
// Add sticker to collection
BrowserViewController.Stickers.Add (sticker);
// Switch to compact view mode
Request (MSMessagesAppPresentationStyle.Compact);
}
DidTransition
メソッドは、2 つのモード間の切り替えを処理するようにオーバーライドされています。
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;
}
}
まとめ
この記事では、メッセージ アプリと統合してユーザーに新しい機能を提供する Message App Extension を、Xamarin.iOS ソリューションに含める方法を説明しました。 この拡張機能を使ってテキスト、ステッカー、メディア ファイル、インタラクティブ メッセージを送信する方法について説明しました。