Azure Notification Hubsを使用してiOSとAndroidにPush通知を行う (2) ~実装編~

# 実装編
Azure Notification Hubs から Push通知を受け取るiOS/Androidのアプリを実装していきます。

## iOS アプリケーションの作成
1. [Azure Mobile Services iOS SDK 1.2.4](https://github.com/Azure/azure-mobile-services/blob/master/CHANGELOG.ios.md#sdk-downloads) をダウンロード
2. Xcodeで、iOS プロジェクトを作成
  1. Xcodeのメニューから[File]->[New]->[Project...]を選択
  2. [Single View Application]を選択し、[Next]をクリック
　　  ![2016_09_15_17_25.png](https://qiita-image-store.s3.amazonaws.com/0/12177/367899b9-a9ae-616f-63c2-45cad6df141a.png)
  3. [Product Name][Organization Name]等を入力し、[Next]をクリック
    ![2016_09_15_17_27.png](https://qiita-image-store.s3.amazonaws.com/0/12177/2ff7d0d0-9b7a-8586-d5b8-90074c4ae4fa.png)
3. [TARGETS]でターゲットの[Bundle Identifier]を。Apple Developerで作成したものに変更、Teamを選択
  ![2016_09_15_17_28.png](https://qiita-image-store.s3.amazonaws.com/0/12177/7976bd19-5b2e-0244-f228-e9dc3cf379f1.png)
4. Provisioning Profileをダウンロード
  1. Xcodeのメニューから [Prefarences...]の[Accounts]を開く
    ![2016_09_13_20_00.png](https://qiita-image-store.s3.amazonaws.com/0/12177/c80ef029-6755-0d83-1898-aaaceb204866.png)
  2. [Apple ID]->[Team]を選択し、[View Details...]を開き、作成した Provisioning Profile　をダウンロード
  　　![2016_09_13_20_10.png](https://qiita-image-store.s3.amazonaws.com/0/12177/c32421d5-cac0-430a-1a40-1d26c6fc1bba.png)
5. iOS 1.2.4 SDKの追加
  1. ダウンロードした[Azure Mobile Services iOS SDK 1.2.4](https://github.com/Azure/azure-mobile-services/blob/master/CHANGELOG.ios.md#sdk-downloads) 　を解凍
    ![2016_09_15_17_31.png](https://qiita-image-store.s3.amazonaws.com/0/12177/7cc63f67-a458-1bab-0e82-6f704bd5d16b.png)
  2. Xcodeのプロジェクトに、WindowsAzureMessaging.framework をドラッグアンドドロップ
  3. [Destination]の[Copy items if needed]をチェックし、[Finish]をクリック
    ![2016_09_15_17_48.png](https://qiita-image-store.s3.amazonaws.com/0/12177/2982486e-d935-c0b1-b84f-13ceb61e9acd.png)
  4.　[WindowsAzureMessaging.framework]がプロジェクトに追加される
　　　　  ![2016_09_15_17_51.png](https://qiita-image-store.s3.amazonaws.com/0/12177/9355d03f-f5d6-008f-5268-2a76f052a228.png)
6. Swiftで[WindowsAzureMessaging.framework]を使用するために、[Objective-C Bridging Header]を追加
  1. プロジェクト名と同じグループを右クリックし、[New File...]をクリック
    ![2016_09_14_17_38.png](https://qiita-image-store.s3.amazonaws.com/0/12177/fd805a95-a3bf-3e95-3265-6e02b0a35479.png)
  2. [Header File]を選択し、[Next]をクリック
    ![2016_09_14_17_39.png](https://qiita-image-store.s3.amazonaws.com/0/12177/85ee1382-625d-f1db-c706-6ff73b4fb75f.png)
  3. 任意のファイル名でHeaderファイルを作成
    ![2016_09_14_17_40.png](https://qiita-image-store.s3.amazonaws.com/0/12177/0fe90255-045b-5507-4cb0-28ed72356cd0.png)
  4. [PROJECT]を開き、[Build Settings]で、[Objective-C Bridging Header]を検索し、作成したHeaderファイルのパスを入力。変数を使用してパスを指定。
    ``` $(SRCROOT)/$(PROJECT)/AzureMessaging-Bridging-Header.h ```
    ![2016_09_14_17_42.png](https://qiita-image-store.s3.amazonaws.com/0/12177/32f2358f-512d-be22-be99-a882759ff0d5.png)

  5. Headerファイルに importを記述

    ```javascript
    #ifndef AzureMessaging_Bridging_Header_h
    #define AzureMessaging_Bridging_Header_h
       
    #import "WindowsAzureMessaging/WindowsAzureMessaging.h"
    
    #endif /* AzureMessaging_Bridging_Header_h */
    ```

7. AppDelegateに、APNsの実装を追加
  1.　application(_:didRegisterUserNotificationSettings:)に、APNsへ登録

    ```swift
    func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
        // APNsへ登録
        application.registerForRemoteNotifications()
    }
    ```
  2.　application(_:didRegisterForRemoteNotificationsWithDeviceToken:)で、APNsで発行される deviceTokenをNotificationHubへ登録
    * SBNotificationHubのconnectionStringに、Notification Hubの[DefaultFullSharedAccessSignature]の文字列を指定、notificationHubPathに、Notification Hubの名前を指定

    ```swift
    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
        // NotificationHubへ登録
        let hub = SBNotificationHub(
            connectionString: "Endpoint=sb://x.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=...",
            notificationHubPath: "AzureNotificationHubsExample")
        hub.registerNativeWithDeviceToken(deviceToken, tags: nil) { (error) in
            if (error != nil) {
                print("Error registering for notifications.", error)
            } else {
                print("Success registering for notifications.", deviceToken)
            }
        }
    }
    ```
  3.　application(_:didReceiveRemoteNotification:)で、APNsからPush通知されるメッセージを受け取り、アプリケーションがアクティブな場合にアラートダイアログを表示

    ```swift
    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject:AnyObject]) {
        switch (application.applicationState) {
        case UIApplicationState.Active:
            let alert = UIAlertController(title: "", message: userInfo.description, preferredStyle: .Alert)
            let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
            alert.addAction(defaultAction)
            self.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
        case UIApplicationState.Background, UIApplicationState.Inactive:
            print(userInfo.description)
        }
    }
    ```


## Android アプリケーションの作成
1. Android Studioで、アプリケーションを作成
    1. [Application Name][Company Domain][Project Location]を入力して[Next]をクリック
       ![2016_09_16_11_21.png](https://qiita-image-store.s3.amazonaws.com/0/12177/be6325db-3507-7a6b-daaf-ee48307a5425.png)
    2. [Empty Activity]を選択して[Next]をクリック
       ![2016_09_16_11_22.png](https://qiita-image-store.s3.amazonaws.com/0/12177/70eb0f9c-6e3c-6d2a-605c-1058e77da075.png)
    3. [Activity Name]等はそのままで[Finish]をクリック
       ![2016_09_16_11_23.png](https://qiita-image-store.s3.amazonaws.com/0/12177/372ae8b5-f478-a832-a697-f57a9c0ce311.png)

2. Firebase Cloud Messaging Client SDKの設定
  1.　ダウンロードした google-services.json を追加。[Project]表示に切り替え、[app]モジュールの下にコピー
    ![2016_09_27_14_34.png](https://qiita-image-store.s3.amazonaws.com/0/12177/4fa7e3f5-e82c-723a-bc43-bacfe128304e.png)
  2.　プロジェクトのbuild.gradleの変更

    ```groovy
    buildscript {
        // ...
        dependencies {
            // ...
            classpath 'com.google.gms:google-services:3.0.0'
        }
    }
    ```
  3.　[app]モジュールのbuild.gradleの修正

    ```groovy
    android {
      // ...
    }
    
    dependencies {
      // ...
      compile 'com.google.firebase:firebase-messaging:9.6.1'
    }
    
    // ADD THIS AT THE BOTTOM
    apply plugin: 'com.google.gms.google-services'
    ```
  4.　GradleのSyncを行う
    * gradleファイルの修正したためSyncを行う
    * 通知の[Sync Now]をクリック 
      ![2016_09_28_10_36.png](https://qiita-image-store.s3.amazonaws.com/0/12177/a34ade36-ea59-a8db-b7f8-f83e1afa3cca.png)
    * もしくは、メニューの[File]->[Synchronize]をクリック

3. Azure Notification Hubs　ライブラリの追加
  1.　[app]モジュールのbuild.gradeの dependencies にライブラリを追加

    ```groovy
    dependencies {
      // ...
      compile 'com.microsoft.azure:notification-hubs-android-sdk:0.4@aar'
      compile 'com.microsoft.azure:azure-notifications-handler:1.0.1@aar'
    }
    ```
  2.　ライブラリのリポジトリの指定をrepositoriesに追加

    ```groovy
    repositories {
        maven {
            url "http://dl.bintray.com/microsoftazuremobile/SDK"
        }
    }
    ```
  3.　GradleのSyncを行う
  4.　エラーの解消
    * 以下のエラーが発生する場合、AndroidManifest.xmlを修正する必要がある

    ```sh
    Error:Execution failed for task ':app:processDebugManifest'.
    > Manifest merger failed : Attribute application@icon value=(@mipmap/ic_launcher) from AndroidManifest.xml:7:9-43
    	is also present at [com.microsoft.azure:azure-notifications-handler:1.0.1] AndroidManifest.xml:13:9-45 value=(@drawable/ic_launcher).
    	Suggestion: add 'tools:replace="android:icon"' to <application> element at AndroidManifest.xml:5:5-18:19 to override.
    ```
    * AndroidManifest.xmlを修正
      * manifestに ```xmlns:tools="http://schemas.android.com/tools"```を追加
      * applicationに ```tools:replace="android:icon"```を追加

    ```xml
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.example.azure.nh.example">

    <application
        tools:replace="android:icon"
    ```
  5.　メニューの[Build]->[Make Project]をクリックしビルドを行う

4. Firebase Cloud Messaging(FCM) の登録の実装を追加
  1. FCMへ登録,tokenの取得と、Azure Notification Hubs への登録
     1.  FirebaseInstanceIdService を継承した Serviceクラスを作成
         1. FCMでTokenが更新されると onTokenRefresh() が呼び出される。
         2. ```FirebaseInstanceId.getInstance().getToken()```で、tokenを取得し、NotificationHubへ登録する。
         3. NotificationHubをnotificationHubPath にNotification Hubの[DefaultFullSharedAccessSignature]の文字列を指定、connectionStringに、Notification Hubの名前を指定して作成
         4. NotificationHub.register(pnsHandle); で、tokenを登録
         5. Registration.getRegistrationId(); で、NotificationHubのregistrationIdを取得

         ```java
         import com.google.firebase.iid.FirebaseInstanceIdService;

         public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

             private static final String TAG = MyFirebaseInstanceIDService.class.getSimpleName();

             @Override
             public void onTokenRefresh() {
                 String refreshedToken = FirebaseInstanceId.getInstance().getToken();
                 Log.d(TAG, "Refreshed token: " + refreshedToken);

                 sendRegistrationToServer(refreshedToken);
             }

            private void sendRegistrationToServer(String refreshedToken) {
                NotificationHub hub = new NotificationHub(
                        "AzureNotificationHubsExample",
                        "Endpoint=sb://x.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=...",
                        this);
        
                try {
                    Registration registration = hub.register(refreshedToken);
                    String registrationId = registration.getRegistrationId();

                    Log.d(TAG, "Registration ID: " + registrationId);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
         }
         ```
    2. AndroidManifest.xmlに作成したServiceクラスを追加
     * ```<intent-filter>```に```<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>```を記述

        ```xml
             <application

                <!-- [firebase_iid_service] -->
                <service android:name=".MyFirebaseInstanceIDService">
                    <intent-filter>
                        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
                    </intent-filter>
                </service>

            </application>
        ```
 
5. 通知を受け取る処理の実装を追加
  1. FirebaseMessagingService を継承した Serviceクラスを作成
     1. onMessageReceived() でメッセージを受信
     2. RemoteMessage.getData()で、ペイロードを取得し、Notificationに表示

        ```java
        public class MyFirebaseMessagingService extends FirebaseMessagingService {
            private static final String TAG = MyFirebaseMessagingService.class.getSimpleName();

            @Override
            public void onMessageReceived(RemoteMessage remoteMessage) {
                Log.d(TAG, "From: " + remoteMessage.getFrom());
                if (remoteMessage.getData().size() > 0) {
                    Log.d(TAG, "Message data payload: " + remoteMessage.getData());

                    notifyNotification(remoteMessage.getData().toString());
                }
            }

            private void notifyNotification(String messageBody) {

                NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                        .setContentTitle("FCM Message")
                        .setContentText(messageBody);

                NotificationManager notificationManager =
                        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

                notificationManager.notify(0, notificationBuilder.build());
            }
        }
        ```
  2. AndroidManifest.xmlに作成したServiceクラスを追加
     * ```<intent-filter>```に```<action android:name="com.google.firebase.MESSAGING_EVENT"/>```を記述

        ```xml
             <application

                <!-- [firebase_service] -->
                <service
                    android:name=".MyFirebaseMessagingService">
                    <intent-filter>
                        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
                    </intent-filter>
                </service>

            </application>
        ```

## Azure Notification Hubs から通知を送信

1. [Azure ポータル](https://portal.azure.com) で、Notification Hubsを開く
2. [Test Send]をクリック 
  * ![2016_10_03_12_42.png](https://qiita-image-store.s3.amazonaws.com/0/12177/84492ad9-f4b7-a2d2-a16f-92c9a1178d1d.png)
3. [Platform]に[Apple]を選択し[Send]をクリック
  * ![2016_10_03_12_44.png](https://qiita-image-store.s3.amazonaws.com/0/12177/c7048619-c2df-d357-2e91-d46a18aa7ce6.png)
4. [Platform]に[Apple]を選択し[Send]をクリック
  * ![2016_10_03_12_49.png](https://qiita-image-store.s3.amazonaws.com/0/12177/4fd2903e-a385-9e9f-6f62-737bf3429677.png)
5. [Send]の下に送信結果が表示される
  * ![2016_10_03_14_32.png](https://qiita-image-store.s3.amazonaws.com/0/12177/cc2c617e-54ab-7c46-c306-3641ee33c578.png)
  * ![2016_10_03_14_33.png](https://qiita-image-store.s3.amazonaws.com/0/12177/bfa6320b-5b32-c12e-37a2-d1625915616c.png)
6. iOS/Androidで通知を受け取れていることを確認


これれで、Azure Notification HubsからのPush通知をアプリケーションが受け取れるようになりました。
次は、[配信編](http://qiita.com/granoeste/items/c4f3d7d14b0efcb4b8ec)になります。