【SwiftUI】通知機能の実装方法!ローカル通知とリモート通知の違い
この記事からわかること
- Swift UIでプッシュ通知を実装する方法
- ローカル通知とリモート通知の違い
- 通知の許可申請方法
- UNMutableNotificationContentとは?
- ローカル通知を実装する流れ
- 通知が表示されない原因
- フォアグラウンドで通知を表示させるには?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:15.4
- iOS:17.0
- Swift:5.9
- macOS:Sonoma 14.1
SwiftUIで開発しているアプリに通知機能を実装する方法をまとめていきたいと思います。
iOSアプリの通知機能
iOSアプリではユーザーに対して注意を引くために通知機能を実装することが可能です。できることは音を鳴らしたり、以下のようなプッシュ通知(アラート)を送信したり、アイコンにバッジをつけたりすることが可能です。
プッシュ通知は基本的にはアプリファバックグラウンド(アプリが停止している状態)でデバイスに届きますが、フォアグラウンド状態でも届くように設定することも可能です。
iOSアプリのプッシュ通知機能にはさらにローカル通知とリモート通知の2種類に分かれます。
ローカル通知
ローカル通知とはオフラインで実行される通知機能のことを指します。デバイス内からプッシュ通知リクエストを送信し、デバイス内で処理されて通知が届くような仕組みになっています。
ローカル通知は事前準備などは必要なく、Swift内でコードを記述するだけで実装することができます。
通知リクエストを送信するタイミングはアプリ内からしか操作できません。リマインダーやアラーム機能など自分でセットして使用するプッシュ通知などはこのローカル通知を使用して実装されています。
リモート通知
リモート通知とはオンラインで実行される通知機能のことを指します。ローカル通知とは異なり、プッシュ通知リクエストをオンライン上から送信し、デバイス内で処理されて通知が届くような仕組みになっています。
仕組みをもう少し詳しくみて見ると以下の通りになります。
参考文献:リモート通知サーバーのセットアップ
APNs(Apple Push Notification service)と呼ばれるAppleが運営するサービスを介してプッシュ通知は配信されます。そのためにはまずデバイスの登録を行い、デバイストークンを発行、そのトークンをサーバーに登録することでそのサーバーから通知リクエストを送信することが可能になります。
リモート通知を使用することでユーザーの操作などではなく、開発者や運営者の任意のタイミングでアプリに対して通知を送信することができるようになります。
おすすめ記事:【Swift】リモート通知実装用の証明書(cer)とプロビジョニングプロファイルの作り方
SwiftUIでのローカル通知の実装方法
今回はSwift UIを使用している場合にボタン押下時にプッシュ通知(ローカル通知)が表示されるような仕組みを実装していきたいと思います。
ローカル通知の実装のポイント
- 通知の許可申請
- 通知機能の実装
ローカル通知の実装方法は以下の公式リファレンスページを参考にしています。
参考文献:UNMutableNotificationContentクラス
1.通知の許可申請
まずはユーザーにアプリからの通知を許可してもらう必要があります。ユーザーに対して通知の許可申請を送るにはUNUserNotificationCenter
クラスを使用します。詳しい使い方は以下の記事をご覧ください。
通知の許可申請を行う処理を今回はイニシャライザの中に組み込んでおきます。
struct ContentView: View {
init(){
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: .alert) { granted, error in
if granted {
print("許可されました!")
}else{
print("拒否されました...")
}
}
}
var body: some View {
Button(action: {
// ここに通知送信の処理を記述
}, label: {
Text("通知を送信")
})
}
}
アプリを起動すると以下のようなポップアップが表示されユーザーに対して通知の許可の有無を問います。設定されている言語で表示されるので日本語にしたい場合はLocalizations
をJapanese
にしてください。
引数options
には申請したい通知の種類を指定します。複数指定する場合は[.alert, .sound, .badge]
のように配列形式で指定可能です。
UNAuthorizationOptions構造体のプロティ
struct UNAuthorizationOptions {
static var alert: UNAuthorizationOptions { get } // アラート
static var sound: UNAuthorizationOptions { get } // サウンド
static var badge: UNAuthorizationOptions { get } // バッジ
static var carPlay: UNAuthorizationOptions { get } // carPlay
static var provisional: UNAuthorizationOptions { get } // 通知機能のお試し用(通知許可ポップアップは非表示)
}
2.通知機能の実装
通知機能をメソッドとして作成していきます。まずが完成コードを見てみます。
func sendNotificationRequest(){
// 通知オブジェクト作成
let content = UNMutableNotificationContent()
content.title = "通知のタイトルです"
content.body = "通知の内容です"
// 通知を発行するトリガー(条件)を設定
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "通知No.1", content: content, trigger: trigger)
// 通知を登録
UNUserNotificationCenter.current().add(request)
}
あとはこのメソッドをボタンのアクション部分で呼び出せば完了です。これはバックグラウンドで実行される通知処理なので、ボタンを押したらホーム画面に戻って5秒後に通知が来ることを確認してみてください。
Button(action: {
sendNotificationRequest()
}, label: {
Text("通知を送信")
})
ここからは使用したコードを解説していきます。
UNMutableNotificationContentクラス
公式:UNMutableNotificationContentクラス
UNMutableNotificationContent
は通知の内容を作成するクラスです。このクラスのプロパティに通知に載せるタイトルや内容、サウンドなどを渡します。
流れ
- インスタンス化し空のローカル通知を作成
- 通知の内容を構築
- トリガー条件を定義
- 通知本体とトリガー条件を含めたリクエストを構築
- リクエストを追加
1.インスタンス化し空のローカル通知を作成 & 2.通知の内容を構築
まずはインスタンス化してローカル通知を作成していきます。ここに通知に載せたい内容を渡します。
let content = UNMutableNotificationContent()
content.title = "通知のタイトルです"
content.body = "通知の内容です"
UNTimeIntervalNotificationTrigger
3.トリガー条件を定義
トリガー条件はUNTimeIntervalNotificationTrigger
クラスを使って定義します。引数timeInterval
に通知を表示させるタイミングを秒数単位で指定します。以下の場合は5秒後に通知が表示されます。
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
repeats
には通知処理を繰り返すかどうかを指定できます。true
にする場合は60秒以上を設定しないと「time interval must be at least 60 if repeating」というエラーを吐いてアプリがクラッシュしてしまいます。
条件は年月日で指定することも可能です。DateComponents
型で通知を送りたり未来の日時を指定します。
var dateComponents = DateComponents()
dateComponents.year = year
dateComponents.month = month
dateComponents.day = day
dateComponents.hour = hour
dateComponents.minute = minute
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
UNNotificationRequest
4.通知本体とトリガー条件を含めたリクエストを構築
UNNotificationRequest
クラスを使用してリクエスト情報を構築します。identifier
には一意となる識別子を設定し、ローカル通知とトリガーを渡します。
let request = UNNotificationRequest(identifier: "通知No.1", content: content, trigger: trigger)
5.リクエストを追加
最後にユーザーに通知許可申請を送る際にも使用したUNUserNotificationCenter
クラスのadd
メソッドを使用してローカル通知の配信をスケジュールに追加することができます。
UNUserNotificationCenter.current().add(request)
これでローカル通知の実装は完了です。シミュレーターでも正常に動作しますので試してみてください。
provisionalを指定すると通知が表示されない
options
の引数に通知機能をお試しできる.provisional
を指定するとシミュレーターでは通知が表示されませんでした。
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: .provisional) { granted, error in
if granted {
print("許可されました!")
}else{
print("拒否されました...")
}
}
シミュレーターで通知機能のチェックをしたい場合は普通に.alert
などを指定すれば正常に動作します。
App Delegateを使って通知許可申請
先程は通知許可申請をContentView構造体のイニシャライザの中に組み込みましたがこれではこのページが表示されたタイミングでないと許可申請が表示されません。
アプリを起動したタイミングでの申請が望ましいと思います。これを解決するためにApp Delegate
を使用します。詳しい使い方は以下の記事を参考にしてください。
【SwiftUI】App Delegateとは?実装方法と使い方
App Delegateを使って通知許可申請を行う流れ
- AppDelegateクラスの生成
- アプリ起動時に処理される部分に通知許可申請を追加
- <プロジェクト>App.swiftにデリゲートを登録
1.AppDelegateクラスの生成
まずは必要となるAppDelegateクラスを作成します。Swift UIではUIKitと違い「AppDelegate .swift」ファイルがないので自作していきます。
import Foundation
import UIKit
class AppDelegate: NSObject, UIApplicationDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print("アプリが起動したよ")
return true
}
}
2.アプリ起動時に処理される部分に通知許可申請を追加
続いて通知許可申請するためのコードをapplication
メソッドの中に記述します。
import Foundation
import UIKit
class AppDelegate:NSObject,UIApplicationDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
print("許可されました!")
}else{
print("拒否されました...")
}
}
return true
}
}
3.<プロジェクト>App.swiftにデリゲートを登録
最後に「<プロジェクト>App.swift」内から先ほど作成したAppDelegateクラスを@UIApplicationDelegateAdaptor
を付与して定義すれば完成です。
import SwiftUI
@main
struct HelloWorldApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
フォアグラウンドで通知を表示させる
公式リファレンス:userNotificationCenterメソッド
フォアグラウンドで通知を表示させたい場合はAppDelegate
クラスにUNUserNotificationCenterDelegate
プロトコルを準拠させ、userNotificationCenter
メソッドを実装し、UNUserNotificationCenter
クラスのデリゲートにクラスインスタンスを渡します。
import Foundation
import UIKit
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// UNUserNotificationCenterDelegateの適応
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if granted {
print("許可されました!")
}else{
print("拒否されました...")
}
}
return true
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([[.banner, .list, .sound]])
}
}
これで通知がフォアグラウンドでも表示されるようになります。
通知のタップを検知する
Swiftで通知がタップされたことを検知するにはUNUserNotificationCenterDelegate
のデリゲートメソッドの1つであるuserNotificationCenter(_:,didReceive:,withCompletionHandler:)
を利用します。
extension AppDelegate :UNUserNotificationCenterDelegate{
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
print("タップされたよ")
completionHandler()
}
}
またこの通知のタップはローカル通知だけでなくリモート通知でも動作するようです。
おすすめ記事:【Swift UI】アプリアイコンにバッジを付与する方法!applicationIconBadgeNumber
Androidでの実装はこちら
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。
私がSwift UI学習に使用した参考書