素振り用iOSプロジェクト fcm編
前回
素振り用iOSプロジェクト fastlane match編 - kz-kazuki’s blog
今回のゴール
firebase cloud messaging(以下fcm)を使ってpush通知を送ることができる
firebaseのドキュメント読んでポチポチすれば終わるが...
firebase
新しくプロジェクトを作成する
iOSボタンを押すと進むので指示通りに作業
現時点ではまだPod推奨なので、*.xcworkspace から起動することになる
fastlaneでapns用証明書を作成する
fastlane/Fastfileにコマンドを追加 (bundle_idをAppFileに記述してるので不要
... desc "create develop apns cert." lane :create_apns_develop do pem( force: true, development: true, save_private_key: true ) end
コマンドを実行する
... [16:51:12]: Creating a new push certificate for app 'org.assaulter.base'. Private key, p12 certificate, PEMが保存されている旨が表示 ...
.p12をfirebaseにアップロード
(p8がfastlaneで作れるか調べてない。できるならそっちのほうが楽
firebase console > プロジェクトを設定 > クラウドメッセージング で、開発用APNs証明書としてアップロードする
push notificationが使えるようにする
xcode > Signing & Capabilities で Push Notificationss を追加する
以下のコマンドを追加し実行
desc "renew develop provisioning profile." lane :force_develop do match(type: "development", force: true) end
$ bundle exec fastlane force_develop
dev centerでidentifierが更新されていることを確認する
push許諾とfcm連携
一旦AppDelegateに実装を追加する
import UIKit import Firebase import FirebaseMessaging @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. FirebaseApp.configure() Messaging.messaging().delegate = self UNUserNotificationCenter.current().delegate = self registerRemoteNotification() return true } // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } } // MARK: - private private extension AppDelegate { /// テスト用なのでcompletionは特に何もしない func registerRemoteNotification() { let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization( options: authOptions, completionHandler: { granted, error in if granted { DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } } }) } } // MARK: - UNUserNotificationCenterDelegate extension AppDelegate: UNUserNotificationCenterDelegate { func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let deviceTokenString: String = deviceToken.map { String(format: "%.2hhx", $0) }.joined() debugPrint("deviceTokenString \(deviceTokenString)") } func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError _: Error) { debugPrint("リモート通知の設定は拒否されました") } func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { let userInfo = notification.request.content.userInfo debugPrint("userInfo: \(userInfo)") completionHandler([.alert, .sound]) } } // MARK: - MessagingDelegate extension AppDelegate: MessagingDelegate { func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) { debugPrint("fcmToken: \(fcmToken)") // TODO: If necessary send token to application server. // Note: This callback is fired at each app startup and whenever a new token is generated. } }
実機でアプリを起動し、許諾を承認するとfcmTokenがログに出る
fcm http api v1を使って動作確認
firebase console > プロジェクトの設定 > サービスアカウント > Firebase Admin SDK > 「新しい秘密鍵を生成」を押す
落ちてきたjsonファイルは保管しておく
認証とリクエストを行うrubyのスクリプト
雑に
# frozen_string_literal: true source "https://rubygems.org" gem "google-api-client" gem "faraday" gem "googleauth"
require 'bundler' Bundler.require require 'json' # Config file_path = "service account key file path" project_id = "Your firebase project id" token = "fcmToken from app." # get access token authorizer = Google::Auth::ServiceAccountCredentials.make_creds( json_key_io: File.open(file_path), scope: 'https://www.googleapis.com/auth/firebase.messaging' ) access_token = authorizer.fetch_access_token! access_key = "#{access_token['token_type']} #{access_token['access_token']}" # request uri = URI.parse("https://fcm.googleapis.com/v1/projects/#{project_id}/messages:send") https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true req = Net::HTTP::Post.new(uri) req['Content-Type'] = 'application/json' req['Authorization'] = access_key req.body = { message: { token: token, notification: { title: 'test push notification', body: 'notification message from fcm.' } } }.to_json res = https.request(req) p res
configの部分を埋めて実行するとpushが飛ぶのを確認できる