面白きことは良きことなり

拙く未熟なiOSエンジニアの備忘録と戯言

iOS10+FirebaseでPushNotificationの最小実装

iOS10でPushが大きく変わるってことで、以前にちょろってどんな実装になるか試そうとしたことがあったけど、
時間都合により実装できずに終わった。

時間が取れたので改めて実装する。
また、前回やろうとした時、Parse.comからPushを送るテストをしていたが、今は別サービスへ移行されていたので、
Googleが買収したFirebaseがmBaasとして主流になるだろうから、Firebaseの導入兼Pushの送信を試みた。

firebase.google.com

1. Xcode8でプロジェクトを作成する

  • 自分はわかりやすいように "iOS10PushTestWithFirebase"という名前で作成した。

f:id:aryzae:20160702191659p:plain

2. 証明書周りを用意する

  • Xcode8だと割と自動的にここらへんもやってくれたりするぽい?
  • とりあえず自前でcertificateから生成をやった。

3. Firebaseを導入する

  • 「2.」で取得したPushNotification用の証明書(.p12)をエクスポートし、Firebaseに設定する。
    エクスポートするファイル名は、極力日本語を使わないこと。ファイル名に日本語が入っている場合、正常にサーバ側で扱えないことがある。
    パスワードは任意でかける。ただし、serverによってはパスワード必須だったり、その逆だったりとまちまちなので、server側の説明を確認しておく必要がある。
    (Firebaseは、どちらでもいけるので、テストの今回はパスワードなしにして試した。)
  • cocoaPodsでやるのならFirebaseのサイトに書いてあるので手順通りに進めれば困らないと思う。自分はRubyのversionで怒られて別途RubyのUpdateから行うハメになった。
  • 手動でやれるようにcocoaPodsの導入説明ページの1番下にzipへのURLがあったが、解凍して使おうとしたらエラーで怒られた…よくよくzipの中身みたら必要なframeworkが足りてないようだったので、現在(2016/07/02)では使い物にならないと思う。

    それでもPodsで管理したくない人はダミープロジェクト作って、そいつでFirebaseをPods使ってinstallし、必要なファイルを抽出して使おう。フォルダ内には不要な.mdファイル等も入っているので削除しておく。(Podsが嫌いなので今回はこの方法でやった。)

    Pods導入直後 (Podsは、pod 'Firebase/Core'、pod 'Firebase/Messaging'だけ)>
    f:id:aryzae:20160702192910p:plain

    Podsフォルダから必要なフォルダだけ抽出した状態>
    f:id:aryzae:20160702192929p:plain]
  • 抽出したフォルダやファイルを取り込む
    ※"GoogleService-Info.plist" は、Firebaseでプロジェクトの登録設定を行うとDLできる。これも必須なのでやっておく必要がある。

    <「1.」で作ったプロジェクトに含めた状態>
    f:id:aryzae:20160702193621p:plain

4. プロジェクトの設定を行う

  • Pushのテストなので、当然ながら "Capabilities" で "Push Notification" をONにしておく
    f:id:aryzae:20160702194750p:plain
  • FirebaseのFrameworkはまだ、Objective-Cで提供しているのでSwiftで取り込めるようにする必要がある。"Search Header Path" に記述する手もあるが、楽なのでbridge-headerをXcodeに自動生成してもらう。
    自動で生成するにはプロジェクトに適当なObjective-Cファイルを追加してやれば作成するか聞かれるので、そこで作ればOK!
    f:id:aryzae:20160702195148p:plain
  • 手動でSDKを取り込んだ場合に必要。"Other Linker Flags" に "-ObjC" をつける
    つけないでObjective-CのFrameworkを使うと正常に動作しなかったり、クラッシュする。
    f:id:aryzae:20160702194651p:plain

5. コードを記述し、端末でアプリを起動する

  • <AppDelegate.swift>
import UIKit
import FirebaseAnalytics
import FirebaseInstanceID

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        FIRApp.configure()
        
        return true
    }

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~省略~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print(#function)
        // 不要かもしれない※1
        FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: .sandbox)
    }
}

※1 【swift3】push通知【firebase】 - 徒然もちもち。 で必要だったことが判明。ありがとうございます。

  • <PushNotificationを受けたいクラス (今回テストなのでViewControllerに実装)>
import UIKit
import UserNotifications

// delegateを追加
class ViewController: UIViewController, UNUserNotificationCenterDelegate {

    let notification = UNUserNotificationCenter.current()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        // delegateをセット
        notification.delegate = self
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // 許可するかのポップアップ表示 (ポップアップ自体は1インストール1回しか表示されない)
        notification.requestAuthorization([.alert, .badge, .sound], completionHandler: {(isAllow, error) in
            print(#function)
            if let error = error {
                print(error.localizedDescription)
            } else {
                if isAllow {
                    print("allow")
                    // regist Token
                    UIApplication.shared().registerForRemoteNotifications()
                } else {
                    print("not allow")
                }
            }
        })
    }

    // Pushが表示された時
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Swift.Void) {
        print(#function)
    }
    
    // Pushをタップした時
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Swift.Void) {
        print(#function)
    }
}

6. FirebaseからPushの送信テストを行う

  • アプリを実行し、バックグラウンドにする。
  • FirebaseからPushの送信を行う。
    →Pushが届く
    →ミッションコンプリート!


思ったよりは実装自体は簡単だった。
しかし、iOS10からPush周りでできることが一気に増えたため、こんなのは序の口なんだろう。iOS10でもDepricateになった旧Pushのメソッドは動くという記事があったので、まだ無理に実装する必要はないだろうが、実装するのであれば、iOSでif分岐させるようにしておかねば。