はじめに
この間行われたtry! SwiftでFirebaseさんがいらしてたので頑張っていろいろ話していたらなんと
「 mutable-content
に対応したよ」と言われたのでちょっとやってみました!
ちなみに前回「iOSアプリからFirebase Cloud Messaging経由でプッシュ通知を送る」という
記事を書いたのでその時に書いたプログラムを再利用しています。
環境
- macOS Sierra
- Xcode 8.2.1
- Swift3.0.2
- iOS10.x
サンプルソース
プッシュ通知設定関連
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サンプルはここで必要なソースコードの下に示します。
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サンプルプログラムです。
プログラムの説明は前回の記事に書いてあるので参照ください。
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にデータを追加
前回と同じくこんな感じにFirebase Databaseにデータ追加します。
プッシュ通知結果
やったね!
最後に
今回はPythonのプログラムからまた送信してみました。
また、一応FirebaseConsole(Web)からもテストしてみたのですが、できなさそうなのでやはりこっちで対応する形になりそうです。
それとおまけで、Firebaseの中の人から
「近いうちに1to1プッシュ通知に対応するよ〜」
との情報もいただき、Firebaseのソース(タバスコ)などの大切なものもいただきました!