FC2ブログ

記事一覧

プッシュ通知を実装する方法 -iOS編- | Xamarin.Forms


今回はXamarinでiOSのプッシュ通知を送信する方法をご紹介いたします。VisualStudio上の設定のみならず、プロビジョニングの追加設定やAWSでのSNSの設定も含みますので、少し長くなりますがお付き合いいただければと存じます。

尚、プッシュ通知ではアプリ起動時にはバックグラウンドサービスを実行することができますが、アプリが起動していない場合はプッシュ通知されておしまいです。
アプリが起動していない状態でバックグラウンドの処理をキックしたい場合はVoIPプッシュ通知を実装しましょう。次回の記事にてVoIPプッシュ通知の実装方法をご紹介しております。



前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.795 (NuGet Xamarin.Forms 2.3.4.247)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.6.0.10
・AppleDeveloperProgramへの申し込み(年間12,000円程)
・基本的なプロビジョニングが設定済みであること



1.プロビジョニングの追加設定

(1)以下のサイトの画面右上「アカウント」からログインします。
https://developer.apple.com/

(2)左メニューのIdentifiersからApp IDs を選択し、アプリに使用しているAppIDを選択します。無い場合は作成してください。

xamarin_ios_push_notification_01.png


(3)AppIDのEditボタンからPush Notifications を有効にします。
Create Certificate...ボタンから証明書署名要求CSR(Certificate Signing Request)ファイルを取り込みます。証明書署名要求CSR(Certificate Signing Request)ファイルを作成していない場合はMacのキーチェーンから作成します。

Development SSL Certificate ・・・開発用の証明書を作成する場合
Production SSL Certificate  ・・・・リリース用の証明書を作成する場合

xamarin_ios_push_notification_02.png


(4)証明書署名要求CSR(Certificate Signing Request)ファイルに関する説明が書かれていますが、無視してContinueボタンを押下します。

xamarin_ios_push_notification_03.png


(5)Choose File...ボタンからローカルのCSRファイルを選択します。

xamarin_ios_push_notification_04.png


(6)CSRファイルが取り込めたら証明書が発行されますので、Downloadボタンよりローカルに保存します。

xamarin_ios_push_notification_05.png


(7)もう一度AppIDを確認するとPush NotificationsがEnabledに変化していることが分かります。Configurableになっている場合は証明書が未発行です。
尚、リリース用の証明書も発行する場合は(3)~(6)までを繰り返します。

xamarin_ios_push_notification_06.png


(8)ダウンロードした証明書をMacにコピーして、Macでダブルクリックします。
キーチェーンアクセスが起動し、証明書がインストールされます。

xamarin_ios_push_notification_08.png


(9)キーチェーンアクセスに登録ができたら、今度は書き出します。
ファイルから「書き出す」を選択します。

xamarin_ios_push_notification_10.png


(10)フォーマットをP12を選択し、保存ボタンを押下します。

xamarin_ios_push_notification_11_2.png 

(11)任意のパスワードを設定します。AWSの登録で必要なので覚えておいてください。

xamarin_ios_push_notification_12.png


(12)また、プロビジョニングプロファイル自体もステータスがInvalidとなっていますので、再度ダウンロードしてXcodeに取り込み直します。
Provisioning Profile→Development からデバッグで使用しているプロビジョニングファイルを選択し、Editボタン→Downloadボタン→ファイルをMacにコピーしてXcodeにドラッグ。



2.プッシュ通知サービス

AWSのAmazon SNSを使用します。
毎月100万件のプッシュ通知が無料で、追加100万件ごとに1USDかかります。
100万件とは、毎日1回送信したとして33,333ユーザーまで許容でき、無料枠としてはかなりの量だと思います。

Amazon SNS の無料枠の確認は以下のURLから
https://aws.amazon.com/jp/sns/pricing/

また、他のASPと比較しても圧倒的にコストパフォーマンスに優れています。
他のASPでは100万件が無料だとしても1000万件までの残り900万件のプッシュ通知で3万円~6万円程度かかりますが、AWSではたったの9ドル(900万件÷100万件/USD)。つまり超過コストが1000円程で済むのです。
おそらくは世界で1億ダウンロードなどのアプリでない限りは無制限のプランは必要ではないのでしょうか。

Amazon SNS の登録は以下のURLより
https://aws.amazon.com/jp/sns/
※アカウントの登録手順については割愛します。

尚、アベイラビリティゾーン(リージョン)がサービスごとに異なっております。
私の場合は全てus-westで設定しました。IAMはアベイラビリティゾーンの設定が無かったり、us-eastにしかないサービス等もあり、少し困惑します。お気を付けください。


(1)Amazon Cognitoの設定
AWSコンソールよりサービス→モバイルサービス→Cognito
https://us-east-1.console.aws.amazon.com/cognito/home

フェデレーテッドユーザーアイデンティティを作成します。

xamarin_ios_push_notification_13.png


(2)IdentityPoolを作成します。
IDプール名とチェックを付けてプールの作成ボタンを押下します。

xamarin_ios_push_notification_14.png


(3)ロールの作成は自動で作成されますので、ここでは無視して許可ボタンを押下します。

xamarin_ios_push_notification_15.png


(4)Identity Pool IDが取得できます。

xamarin_ios_push_notification_16.png

※Identity Pool IDは左メニューの「ダッシュボード」から画面右上の「IDプール編集」リンクを押下しても確認ができます。


(5)Amazon SNSでTopicを作成します。
左メニューから「Topic」→「Create new topic」ボタンを押下します。

xamarin_ios_push_notification_18.png


(6)Topic name を入力し、「Create Topic」ボタンを押下します。
※Topic name はARNを呼び出す際の一意のIDを作成するようです。

xamarin_ios_push_notification_19.png


(7)Amazon SNSにApplicationの登録をする
Amazon SNSの左メニューの「Application」からApplicationの登録を行います。
Applicationのメニューが存在しない場合はアベイラビリティゾーン(us-east-*には無いかもしれません)を確認してみてください。
「Create Platform application」ボタンを押下します。

xamarin_ios_push_notification_20.png


(8)Applicationの登録内容は以下の通り
1: アプリ名を入力します。任意です。
2: デバッグ環境では「Apple Development」を選択します。画面の構成が変化します。
  配信用アプリの場合は「Apple Production」を選択します。
3: 「iOS push cetificate」を選択します。
4: 「Choose file」ボタンより手順1-10で書き出したp12ファイルを選択します。
5: 手順1-11で入力したp12ファイルのパスワードを入力します。
6: 「Load Credentials from file」ボタンを押下します。(CertificateとPrivate keyの欄にキーが表示されます。)
7: 「Create platform application」ボタンを押下するとapplicationが登録されます。

xamarin_ios_push_notification_21.png


登録ができましたら、Application ARNを控えておきます。
(ARN例)arn:aws:sns:us-west-9:999999999999:app/APNS_SANDBOX/AppName


(9)Amazon IAMでロールポリシーの編集を行います。
https://console.aws.amazon.com/iam/home

IAMメニューのロール→UnAuthロールをダブルクリックし、「ポリシーの編集」リンクを押下します。

xamarin_ios_push_notification_22.png


(10)ポリシーの入力
ポリシードキュメントを以下のように入力します。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "sns:CreatePlatformEndpoint",
                "sns:Subscribe",
                "sns:SetEndpointAttributes"
            ],
            "Resource": [
                "arn:aws:sns:us-west-9:999999999999:*"   
               
            ]
           
        }
    ]
}

入力したら「ポリシーの適用」ボタンを押下します。
※Auth(Unでない)ロールのポリシーは変更必要ありません。



3.iOSプロジェクトの設定

(1)Visual Studioを開き、iOSプロジェクトのプロパティからiOSアプリケーションを選択し、バックグラウンドモードとリモート通知を有効にします。

xamarin_ios_push_notification_07.png


(2)次に Entitlements.plist にaps-environmentを追加します。
デバッグモードの場合は「development」と入力します。
リリースモードの場合は「production」と入力します。

Entitlements.plist
<plist version="1.0">
<dict>
  <key>aps-environment</key>
  <string>production</string> <!--RELEASE MODE-->
<!--<string>development</string> DEBUG MODE-->
</dict>
</plist>

※この設定が欠落していると、「Appの有効な "aps-environment" エンタイトルメント文字列が見つかりません」というエラーが発生します。
※Entitlements.plistファイルはXamarinデフォルトでは存在しないため、無ければiOSプロジェクト直下に作成してください。
※また、Entitlements.plistファイルを iOS Bundle Signing のカスタムの権利に設定してください。デバッグ用とリリース用でEntitlements.plistファイルを分けたほうが運用しやすいと思います。ファイル名称は任意で決めれますので、Entitlements_Release.plist / Entitlements_Debug.plist などとするとわかりやすいでしょう。

xamarin_ios_push_notification_28.png


(3)NuGetパッケージのAWSのSDKをインストールします。
「AWSSDK.SimpleNotificationService」で検索しiOSプロジェクトにインストールします。
続いて「AWSSDK.CognitoIdentity」もインストールします。

xamarin_ios_push_notification_09.png


(4)AppDelegateに以下の記述を追加します。
・CognitoAWSCredentialsのインスタンスを作成する際の引数には手順2-4で取得できたIdentity Pool IDを入力します。

AppDelegate.cs
using Amazon;
using Amazon.Util;
using Amazon.CognitoIdentity;
using Amazon.SimpleNotificationService;
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    global::Xamarin.Forms.Forms.Init();

//通知の許可を求める
DependencyService.Get<INotificationService>().Regist();

    //AWS
    this.SetAmazonSnsSettings();

    LoadApplication(new App());
    return base.FinishedLaunching(app, options);
}

#region "AWS"

private AmazonSimpleNotificationServiceClient _snsClient = null;

/// <summary>
/// AWS認証
/// </summary>
private void SetAmazonSnsSettings()
{
//AWSログの設定
var loggingConfig = AWSConfigs.LoggingConfig;
loggingConfig.LogMetrics = true;
loggingConfig.LogResponses = ResponseLoggingOption.Always;
loggingConfig.LogMetricsFormat = LogMetricsFormatOption.JSON;
loggingConfig.LogTo = LoggingOptions.SystemDiagnostics;

//AWSの認証
AWSConfigs.AWSRegion = "us-west-9";
AWSConfigs.CorrectForClockSkew = true;
var offset = AWSConfigs.ClockOffset;

CognitoAWSCredentials credentials = new CognitoAWSCredentials(
"us-west-9:XXXXXXX-9999-9999-XXXX-XXXXXXXXXX", //Cognito identity pool ID
RegionEndpoint.USWest9 // Region
);

_snsClient = new AmazonSimpleNotificationServiceClient(credentials, RegionEndpoint.USWest2);
}

public override void DidRegisterUserNotificationSettings(UIApplication application, UIUserNotificationSettings notificationSettings)
{
// without this RegisteredForRemoteNotifications doesn't fire on iOS 8!
application.RegisterForRemoteNotifications();
}

/// <summary>
/// AWSへのEndPoint登録処理
/// </summary>
/// <param name="application"></param>
/// <param name="deviceToken"></param>
public override async void RegisteredForRemoteNotifications(
UIApplication application, NSData deviceToken)
{
// Get current device token
var DeviceToken = deviceToken.Description;
if (!String.IsNullOrWhiteSpace(DeviceToken))
{
DeviceToken = DeviceToken.Trim('<').Trim('>').Replace(" ", "");

//register with SNS to create an endpoint ARN
var response = await _snsClient.CreatePlatformEndpointAsync(
new CreatePlatformEndpointRequest
{
Token = DeviceToken,
PlatformApplicationArn = "arn:aws:sns:us-west-9:9999999999:app/APNS_SANDBOX/AppName" /* insert your platform application ARN here */
});
}

// Get previous device token
var oldDeviceToken = NSUserDefaults.StandardUserDefaults.StringForKey("PushDeviceToken");

// Has the token changed?
if (String.IsNullOrEmpty(oldDeviceToken) || !oldDeviceToken.Equals(DeviceToken))
{
//TODO: Put your own logic here to notify your server that the device token has changed/been created!

}

// Save new device token
NSUserDefaults.StandardUserDefaults.SetString(DeviceToken, "PushDeviceToken");
}

/// <summary>
/// プッシュ通知の受信処理
/// </summary>
/// <param name="application"></param>
/// <param name="userInfo"></param>
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
//baseは実行しない(エラーとなるため)
//base.ReceivedRemoteNotification(application, userInfo);

if (application.ApplicationState == UIApplicationState.Active)
{
//アプリがアクティブの場合
}
else if (application.ApplicationState == UIApplicationState.Inactive)
{
//アプリがアクティブでない場合
}

//ローカル通知で表示する場合(無くてもプッシュ通知表示されます)
NotificationService ns = new NotificationService();
ns.On("RemoteNotifications title",
"RemoteNotifications subtitle",
"RemoteNotifications body",
null);
}

/// <summary>
/// プッシュ通知の登録失敗
/// </summary>
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
new UIAlertView("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
}

#endregion
}


(5)NotificationServiceクラスに以下のコードを追加します。
AppDelegateで呼び出しています。

public void Regist()
{
    //ローカル通知の許可を求める
    ・
    ・省略
    ・

    UIApplication.SharedApplication.InvokeOnMainThread(() => {
        //プッシュ通知
        UIApplication.SharedApplication.RegisterForRemoteNotifications();
    });
}

NotificationServiceクラスについては以下の通り以前の記事をご参考ください。
・iOS9までのローカル通知
http://itblogdsi.blog.fc2.com/blog-entry-145.html
・iOS10以降のローカル通知
http://itblogdsi.blog.fc2.com/blog-entry-185.html


※EndPointの登録時に以下のようなエラーが出る場合は、AWSのロール(Auth/UnAuth)の信頼関係にIDプールのIDが登録されているかどうかを確認しましょう。
Invalid identity pool configuration. Check assigned IAM roles for this pool.



4.動作確認

(1)AWSSDKのコードを組み込み、iOSアプリを実行するとデバイスがAmazon SNSにEndPointとして登録されます。(シミュレータでは登録されません)

xamarin_ios_push_notification_23.png


(2)Push通知を送信したいデバイス(EndPoint)にチェックを付けて 「Publish to endpoint」ボタンを押下します。


(3)Message欄に送信したいメッセージ内容を入力して「Publish Message」ボタンを押下します。

xamarin_ios_push_notification_24.png


(4)送信結果

xamarin_ios_push_notification_26.png

無事、Push通知が送信できました。





最後までお読みいただきありがとうございます。
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html


関連記事

コメント

コメントの投稿

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。