質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.62%

  • Swift

    7005questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    3990questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • iOS

    3889questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • Firebase

    563questions

    Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

iOS11の端末でFirebaseからリモートPush通知を受け取りたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,772

alan-d-haller

score 10

前提・実現したいこと

初めて質問させていただきます。
iOSアプリ開発を始めて1ヶ月半の初心者です。

iOS11をインストールした端末(iPhone SE)に
FirebaseからのリモートPush通知を受け取る機能をアプリに実装したいと思い、
Qiitaのこちらの記事を参考に準備を進めました。
https://qiita.com/jiiikki/items/31f294cf2afcfe8d868d

Podのインストールと、FirebaseへのAPNs証明書のアップロード、
プロビジョニングプロファイルのインストールまでは問題なく完了できたのですが、
最後のXcodeでプロジェクトの編集をする段階でつまづいています。

上記参考ページのコードではビルドできなかったため、
ご指導いただいている方から教えていただいた
後述するコードに変更したらビルドに成功したので、
実機でプッシュ通知を受け取ろうとテストしたところ、
通知を受け取ることができませんでした。

最近Firebase側で大規模なアップデートがあったと聞いたので、
それに関連してコードの仕様が変更になったのかと思ったのですが…
通知が受け取れない原因がいまいち特定できません。

Firebaseの仕様の変更後で、
iOS11の端末にFirebaseからのリモートPush通知を受け取るための
必要な最新のソースコードをご存知の方がいらっしゃいましたら、
ご教授いただけると幸いです。

どうぞ宜しくお願いいたします。

【更新】該当のソースコード

import UIKit
import UserNotifications

import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    let gcmMessageIDKey = "gcm.message_id"

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        FirebaseApp.configure()

        // [START set_messaging_delegate]
        Messaging.messaging().delegate = self
        // [END set_messaging_delegate]
        // Register for remote notifications. This shows a permission dialog on first run, to
        // show the dialog at a more appropriate time move this registration accordingly.
        // [START register_for_notifications]
        if #available(iOS 10.0, *) {
            // For iOS 10 display notification (sent via APNS)
            UNUserNotificationCenter.current().delegate = self

            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })
        } else {
            let settings: UIUserNotificationSettings =
                UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            application.registerUserNotificationSettings(settings)
        }

        application.registerForRemoteNotifications()

        // [END register_for_notifications]
        return true
    }

    // [START receive_message]
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
        // If you are receiving a notification message while your app is in the background,
        // this callback will not be fired till the user taps on the notification launching the application.
        // TODO: Handle data of notification
        // With swizzling disabled you must let Messaging know about the message, for Analytics
        // Messaging.messaging().appDidReceiveMessage(userInfo)
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // If you are receiving a notification message while your app is in the background,
        // this callback will not be fired till the user taps on the notification launching the application.
        // TODO: Handle data of notification
        // With swizzling disabled you must let Messaging know about the message, for Analytics
        // Messaging.messaging().appDidReceiveMessage(userInfo)
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)

        completionHandler(UIBackgroundFetchResult.newData)
    }
    // [END receive_message]
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
    }

    // This function is added here only for debugging purposes, and can be removed if swizzling is enabled.
    // If swizzling is disabled then this function must be implemented so that the APNs token can be paired to
    // the FCM registration token.
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print("APNs token retrieved: \(deviceToken)")

        // With swizzling disabled you must set the APNs token here.
        // Messaging.messaging().apnsToken = deviceToken
    }
}

// [START ios_10_message_handling]
@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {

    // Receive displayed notifications for iOS 10 devices.
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo

        // With swizzling disabled you must let Messaging know about the message, for Analytics
        // Messaging.messaging().appDidReceiveMessage(userInfo)
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)

        // Change this to your preferred presentation option
        completionHandler([])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)

        completionHandler()
    }
}
// [END ios_10_message_handling]

extension AppDelegate : MessagingDelegate {
    // [START refresh_token]
    func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")
    }
    // [END refresh_token]
    // [START ios_10_data_message]
    // Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
    // To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
    func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
        print("Received data message: \(remoteMessage.appData)")
    }
    // [END ios_10_data_message]
}

【更新】試したこと

・Firebase公式ガイドに記載されている手順の通りにコードを記述した。
https://firebase.google.com/docs/cloud-messaging/ios/client?hl=ja

・上記公式ガイドにリンク付けされているGitHubのページ記載のクイックスタートをAppDelegateに丸ごとコピペしてみた。
https://github.com/firebase/quickstart-ios/blob/master/messaging/MessagingExampleSwift/AppDelegate.swift#L40-L55

しかし、いずれもうまくいかず、以下のようなエラーがコンソールに出る。

【更新】発生している問題・エラーメッセージ

実機テストでFirebaseからのリモートPush通知を受け取れない。

イメージ説明

2017-09-22 15:55:59.494542+0900 Swift4RemotePushTest1[4966:1766557] [Firebase/Core][I-COR000012] Could not locate configuration file: 'GoogleService-Info.plist'.
2017-09-22 15:55:59.494 Swift4RemotePushTest1[4966] <Error> [Firebase/Core][I-COR000012] Could not locate configuration file: 'GoogleService-Info.plist'.
2017-09-22 15:55:59.495386+0900 Swift4RemotePushTest1[4966:1766557] [Firebase/Core][I-COR000005] No app has been configured yet.
2017-09-22 15:55:59.495 Swift4RemotePushTest1[4966] <Error> [Firebase/Core][I-COR000005] No app has been configured yet.
2017-09-22 15:55:59.502100+0900 Swift4RemotePushTest1[4966:1766494] *** Terminating app due to uncaught exception 'com.firebase.core', reason: '`[FIRApp configure];` (`FirebaseApp.configure()` in Swift) could not find a valid GoogleService-Info.plist in your project. Please download one from https://console.firebase.google.com/.'
*** First throw call stack:
(0x183f1bd38 0x183430528 0x183f1bc80 0x1025b5830 0x102550c64 0x1025516d0 0x18d39a050 0x18d58d898 0x18d5926e4 0x18d820454 0x18daf01f0 0x18d8200b8 0x18d820928 0x18df896e8 0x18df8958c 0x18dd059c0 0x18de9afc8 0x18dd05870 0x18daef850 0x18d590e28 0x18d9946ec 0x1865bd768 0x1865c6070 0x1036f145c 0x1036fdb74 0x1865f1a04 0x1865f16a8 0x1865f1c44 0x183ec4358 0x183ec42d8 0x183ec3b60 0x183ec1738 0x183de22d8 0x185c73f84 0x18d38e880 0x1025542cc 0x18390656c)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

補足情報(言語/FW/ツール等のバージョンなど)

開発環境は以下の通りです。
macOS Sierra(10.12.6)
iOS 11.0
Xcode 9.0
Swift 4.0

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

まず最初に読むべきはFirebaseのドキュメントです。
日本語のドキュメントあります。

iOS での Firebase Cloud Messaging クライアント アプリの設定

参考にしている記事はiOS10以降に対応していないと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/22 15:33 編集

    ご回答ありがとうございます。
    実はお送りいただいた記事は事前に目を通していました。
    その上で記載されていた手順の通りにコードを記述したり、GitHubに記載されているクイックスタートのサンプルコードをまとめてコピペするなどして一通り試してみたりもしましたが、やはり端末で通知を受け取ることはできませんでした。
    ただ、上記のFirebase公式の記事の解説はやや複雑だったので、通知を受け取るために最低限必要なコードさえわかれば助かるのですが…

    キャンセル

  • 2017/09/22 15:46

    なるほど、そこまでは試しているのですね。

    https://github.com/firebase/quickstart-ios/blob/master/messaging/MessagingExampleSwift/AppDelegate.swift

    クイックスタートのAppDelegateは最低限に近いコードだと思います。
    ここからはじめるのが一番オススメです。

    気になったのは、このAppDelegateのコードの場合はFirebaseのメソッド実装入れ替えに頼っているので、Qiitaの記事にあるような「FirebaseAppDelegateProxyEnabledをNO」にするのは駄目です。

    キャンセル

  • 2017/09/22 16:22

    再びのご回答ありがとうございます。
    なるほど、そのような仕組みなのですね。

    早速、「FirebaseAppDelegateProxyEnabledをNO」を削除した上で、クイックスタートのコードを丸ごとAppDelegateにコピペして実機テストを試みました。

    しかし、上記で【更新】試したことで追加したようなエラーメッセージのようなものがコンソールに表示されてしまい、classにはThread 1: signal SIGABRTとエラーが出てしまいます。

    これは何が原因なのでしょうか?

    キャンセル

  • 2017/09/22 16:30

    ログに
    '`[FIRApp configure];` (`FirebaseApp.configure()` in Swift) could not find a valid GoogleService-Info.plist
    とあります。
    GoogleService-Info.plistを作って組み込んでありますか?

    キャンセル

  • 2017/09/22 16:46

    はい、GoogleService-Info.plistであれば、Firebaseコンソールの該当プロジェクトからダウンロードしてXcodeのInfo.plistの下にドラッグ&ドロップで組み込んであります。

    キャンセル

  • 2017/09/22 16:51 編集

    ではそのGoogleService-Info.plistをクリックした時にXcode画面右側にでるGoogleService-Info.plistについての情報をチェックしてください。Target Membership ってのがありますが、そこにある各ターゲットで、試しているビルドターゲットがチェックなしになっていませんか?
    チェックがない場合、ビルドに含まれません。

    キャンセル

  • 2017/09/22 17:11

    ああ、そういうことだったんですね!
    早速GoogleService-Info.plistのユーティリティをチェックしたところ、ご指摘のようにTarget Membershipにチェックが付いていませんでした。
    チェックをつけた上で再度実機テストでFirebaseからプッシュ通知を飛ばしたところ、おかげさまで今度はちゃんと受け取ることができました!
    本当にありがとうございます!

    ただ、今回はコード自体は完全にクイックスタートのコピペそのままだったので、これから一つずつコードの意味を読み解いて、自分で自在に使いこなせるように勉強していきます。

    重ね重ねになりますが、何度も助けてくださり本当に感謝しています。
    どうもありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Swift

    7005questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    3990questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • iOS

    3889questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • Firebase

    563questions

    Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。