FirebaseのMethod Swizzling

FirebaseのMethod Swizzling

FirebaseのSDKを組み込んだ場合、デフォルトではMethod Swizzlingを使ってAPNsの設定等を行っているようですが、Info.plistに以下の設定をするとそれを無効にすることが出来ます。

FirebaseAppDelegateProxyEnabled = NO

無効にした場合は、SDKが行っていた部分を自前で実装する必要が出てきますが、有効にするか無効にするかは場合によって変わってくると思います。

FirebaseがMethod Swizzlingを使って何をやっているのかを把握しておきたいので調べてみました。

検証環境

  • XCode 7.3.1
  • iOS 8.1以上
  • Swift 2.2.1

Firebase Cloud MessagingがMethod swizzlingを実行する箇所

ドキュメントを引用

The FCM API performs method swizzling in two key areas: mapping your APNs token to the FCM registration token and capturing analytics data during downstream message callback handling. Developers who prefer not to use swizzling can disable it by adding the flag FirebaseAppDelegateProxyEnabled in the app’s Info.plist file and setting it to NO (boolean value). Relevant areas of the guides provide code examples, both with and without method swizzling enabled.

ドキュメントによると、mapping your APNs tokendownstream message callback handling.の2箇所が該当の処理のようです。

mapping your APNs tokenについて

デバイストークンをFCMのトークンにマッピングする処理で、APNSに通信してデバイストークンを取得したあと、デバイストークンをFirebaseのサーバに送ります。

Method Swizzlingを無効にした場合は以下の処理を実装する必要があります。

func application(application: UIApplication,
                   didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
  FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenTypeSandbox)
}

downstream message callback handlingについて

FMCのトラッキングや分析に関する処理のようです。
これも同じく、Method Swizzlingを無効にした場合は以下の処理を実装する必要があります。

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    // Let FCM know about the message for analytics etc.
    FIRMessaging.messaging().appDidReceiveMessage(userInfo)
    // handle your message
  }

注意点

検証した結果、Method Swizzlingが有効になっていると、iPhone5の端末(iOS9.4.3)でのみリフレッシュトークンの取得時に端末が落ちるという問題が発生しました。
これは初回起動時のみに発生し、次回の起動時からは発生しません。

実装したのは以下のとおりです。

//アプリ起動時にトークン更新のオブザーバを登録
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.tokenRefreshNotification(_:)), name:kFIRInstanceIDTokenRefreshNotification, object: nil)

オブザーバで指定しているメソッド
(検証用コードなのでトークンをprintしているだけです)

func tokenRefreshNotification(notification: NSNotification) {
    let token = FIRInstanceID.instanceID().token()!
    print("InstanceID token: \(token)")
}

実装方法が悪いのか何なのか原因がわかりませんが、解決出来ない場合はMethod Swizzlingを無効にして自前で実装したほうが良さそうです。

TAG

  • このエントリーをはてなブックマークに追加
金子 将範
エンジニア 金子 将範 rubyist

新しいことや難しい課題に挑戦することにやりがいを感じ、安定やぬるい事は退屈だと感じます。 考えるより先に手が動く、肉体派エンジニアで座右の銘は諸行無常。 大事なのは感性、プログラミングにおいても感覚で理解し、感覚で書きます。