Skip to content

Instantly share code, notes, and snippets.

@TatsukiIshijima
Last active January 26, 2022 01:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TatsukiIshijima/d0e468950d19f70346048838eb14e4f9 to your computer and use it in GitHub Desktop.
Save TatsukiIshijima/d0e468950d19f70346048838eb14e4f9 to your computer and use it in GitHub Desktop.
iOSのPush通知実装サンプル
//
// AppDelegate.swift
// PushSample
//
import UIKit
import UserNotifications
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
// プッシュ通知の許可を要求
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (granted, error) in
if let error = error {
print("プッシュ通知許可要求エラー : \(error.localizedDescription)")
return
}
if !granted {
print("プッシュ通知が拒否されました。")
return
}
DispatchQueue.main.async {
// APNs への登録
UIApplication.shared.registerForRemoteNotifications()
}
}
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
// APNs 登録成功時に呼ばれる
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
print("デバイストークン : \(token)")
}
// APNs 登録失敗時に呼ばれる
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("APNs 登録に失敗しました : \(error.localizedDescription)")
}
// Push通知を受信した時(サイレントプッシュ)
// payload に "Content-available"=1 が設定されている、かつ
// BackgroundModes の RemoteNotification の設定も必要
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
guard let data = userInfo["data"] as? [String: Any],
let newTitle = data["newTitle"] as? String,
let newBody = data["newBody"] as? String else {
completionHandler(.noData)
return
}
// ローカル通知で表示するタイトルとメッセージを変更する
showLocalNotification(identifier: "SilentPush", title: newTitle, body: newBody)
completionHandler(.newData)
}
// フォアグラウンドで通知を受け取るために必要
// フォアグラウンドで通知を受信した時
// UNUserNotificationCenter.current().delegate = self も必須
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound])
}
// Push通知がタップされた時
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo as NSDictionary
print("userNotificationCenter didReceive : userInfo=\(userInfo)")
completionHandler()
}
func showLocalNotification(identifier: String, title: String, body: String?) {
let content = UNMutableNotificationContent()
content.title = title
if let body = body {
content.body = body
}
content.sound = .default
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
}
//
// NotificationService.swift
// PushExtensionSample
//
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
private var contentHandler: ((UNNotificationContent) -> Void)?
private var bestAttemptContent: UNMutableNotificationContent?
// プッシュ通知を受信した時に呼ばれる
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
guard let bestAttemptContent = bestAttemptContent else {
contentHandler(request.content)
return
}
guard let data = request.content.userInfo["data"] as? [String: Any],
let imageUrl = URL(string: data["imageUrl"] as? String ?? "") ,
let newTitle = data["newTitle"] as? String,
let newBody = data["newBody"] as? String else {
contentHandler(bestAttemptContent)
return
}
// タイトルとボディを書き換え
bestAttemptContent.title = newTitle
bestAttemptContent.body = newBody
let downloadTask = URLSession.shared.downloadTask(with: imageUrl) { (url, _, _) in
guard let url = url else {
contentHandler(bestAttemptContent)
return
}
// tempに保存
let fileName = imageUrl.lastPathComponent
let path = URL(fileURLWithPath: NSTemporaryDirectory().appending(fileName))
do {
try FileManager.default.moveItem(at: url, to: path)
// 保存先のURLをプッシュ通知の表示領域に伝える
let attachment = try UNNotificationAttachment(identifier: fileName, url: path, options: nil)
bestAttemptContent.attachments = [attachment]
contentHandler(bestAttemptContent)
} catch {
contentHandler(bestAttemptContent)
}
}
downloadTask.resume()
}
// タイムアウト時に呼ばれる
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler,
let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment