Edited at

Firebase Cloud Messagingで画像つきプッシュ通知を送信する

More than 1 year has passed since last update.


はじめに

この間行われたtry! SwiftでFirebaseさんがいらしてたので頑張っていろいろ話していたらなんと

mutable-content に対応したよ」と言われたのでちょっとやってみました!

ちなみに前回「iOSアプリからFirebase Cloud Messaging経由でプッシュ通知を送る」という

記事を書いたのでその時に書いたプログラムを再利用しています。


環境


  • macOS Sierra

  • Xcode 8.2.1

  • Swift3.0.2

  • iOS10.x


サンプルソース


プッシュ通知設定関連


AppDelegate.swift

import UIKit

import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { (grand, error) in
guard error == nil else {
return
}
if grand {
UIApplication.shared.registerForRemoteNotifications()
}
})
} else {
let settings = UIUserNotificationSettings(types: [.alert, .badge, .sound],
categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
#if DEBUG
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: .sandbox)
#else
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: .prod)
#endif
}
}
・・・

// MARK: - UNUserNotificationCenterDelegate

extension AppDelegate : UNUserNotificationCenterDelegate {
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
completionHandler()
}
}


とりあえずこんなふうなソースコードを書いておく。


プッシュ通知受け取ったときの動作(iOS10以上)

File 」→「 New 」→「 Target... 」で「 Notification Service Extension 」を追加する。

今回はFirebaseのpayloadに image_url を付けてプッシュ通知を送信してみる。

今回のpayloadサンプルはここで必要なソースコードの下に示します。


Notification/NotificationService.swift

import UserNotifications

class NotificationService: UNNotificationServiceExtension {

let imageKey = AnyHashable("gcm.notification.image_url")

var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

if let imageUrl = request.content.userInfo[imageKey] as? String {
let session = URLSession(configuration: URLSessionConfiguration.default)
let task = session.dataTask(with: URL(string: imageUrl)!, completionHandler: { [weak self] (data, response, error) in
if let data = data {
do {
let writePath = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("push.png")
try data.write(to: writePath)
guard let wself = self else {
return
}
if let bestAttemptContent = wself.bestAttemptContent {
let attachment = try UNNotificationAttachment(identifier: "nnsnodnb_demo", url: writePath, options: nil)
bestAttemptContent.attachments = [attachment]
contentHandler(bestAttemptContent)
}
} catch let error as NSError {
print(error.localizedDescription)

guard let wself = self else {
return
}
if let bestAttemptContent = wself.bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
} else if let error = error {
print(error.localizedDescription)
}
})
task.resume()
} else {
if let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}

override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}



今回のpayload

Firebase Cloud Messagingのエンドポイントに向けて送るpayloadサンプルプログラムです。

プログラムの説明は前回の記事に書いてあるので参照ください。


payload.py

import daemon

import json
import pyrebase
import requests

config = {
# GoogleService-info.plistのAPI_KEY
"apiKey": "API_KEY",
"authDomain": "PROJECT_NAME",
"databaseURL": "https://PROJECT_NAME.firebaseio.com/",
# いらないかもしれない
"storageBucket": "gs://PROJECT_NAME.appspot.com"
}

fcm_header = {
'Content-type': 'application/json; charset=UTF-8',
# このコードの下の画像を参照してください!
'Authorization': 'key=API_KEY'
}

firebase = pyrebase.initialize_app(config)

def stream_handler(message):
if message['data'] == None:
return
if message['path'] == '/':
return

if 'title' in message['data']:
title = message['data']['title']
else:
title = '配信'

if 'body' in message['data']:
body = message['data']['body']
else:
body = ''

payload = {'to': '/topics/news',
'priority': 'high',
'notification': {
'title': title,
'body': body,
'badge': 1,
'sound': 'default',
'mutable_content': True,
}
}
if 'image_url' in message['data']:
payload['notification']['image_url'] = message['data']['image_url']

r = requests.post('https://fcm.googleapis.com/fcm/send', \
headers=fcm_header, \
data = json.dumps(payload))
print(r.json())

if __name__ == '__main__':
db = firebase.database()
dc = daemon.DaemonContext()
with dc:
stream = db.child("message").stream(stream_handler)



実行結果


Firebase Databaseにデータを追加

スクリーンショット_2017-03-14_21_36_30.png

前回と同じくこんな感じにFirebase Databaseにデータ追加します。


プッシュ通知結果

C6aiGhnVMAAvZVl.jpg

C6aiGffUwAAONdg.jpg

やったね!


最後に

今回はPythonのプログラムからまた送信してみました。

また、一応FirebaseConsole(Web)からもテストしてみたのですが、できなさそうなのでやはりこっちで対応する形になりそうです。

それとおまけで、Firebaseの中の人から

「近いうちに1to1プッシュ通知に対応するよ〜」

との情報もいただき、Firebaseのソース(タバスコ)などの大切なものもいただきました!