DatePickerで取得した日時をローカルプッシュ通知で通知する実装したい
オリジナルのリマインダーアプリを作っています。
Datepickerでユーザが設定した値をプッシュ通知日時として設定する機能を実装しているのですが、実機でテストを行ってもバックグラウンド、フォアグラウンド 共に通知が出てこない状況です。
ネットの情報を参考にして、APNSに通知が登録されているところまでは確認できているのですが、なぜ通知が出てこないのかが解決できません。
コードの解説を致しますと、NextViewCOntrollerのDatepickerで設定した日時を
Viewcontrollerのデリゲートメソッドで処理を行い、プッシュ通知の実装もそちらで行っています。
基礎理解が足りなくてすみませんが、
Appdelegateの記述が足りない、コードの記載場所が違うなど
どなたかヒントをいただけますと幸いです。
swift
//Appdelegate.swift
import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder,UIApplicationDelegate,DateProtocol {
var viewController: ViewController!
var window: UIWindow?
var dateTime = Date()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.viewController.setDateSystem(date: dateTime)
}
func setDateSystem(date: Date) {
dateTime = date
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
swift
ViewController.swift
import UIKit
import UserNotifications
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, ReloadProtocol, DateProtocol, UNUserNotificationCenterDelegate {
var notificationGranted = true
var dateTime = Date()
//タスク入力用テキストフィールド
@IBOutlet weak var textField: UITextField!
//テーブルビュー
@IBOutlet weak var tableView: UITableView!
//タスク件数表示用ラベル
@IBOutlet weak var todaysTaskMessageLabel: UILabel!
var indexNumber = Int()
//リターンキーが押されたかどうかを判定する
var textFieldTouchReturnKey = false
//タスク名の配列
var textArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
textField.delegate = self
// let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
// appDelegate.viewController = self
}
//viewが表示される直前の処理
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
todaysTaskMessageLabelChange()
textField.text = ""
}
//本日のタスクの文言表示処理メソッド
func todaysTaskMessageLabelChange() {
//本日のタスクが1件以上なら「本日のタスクは〇〇件です」と表示
if textArray.count >= 1 {
todaysTaskMessageLabel.text = "本日のタスクは\(textArray.count)件です"
//本日のタスクがない場合(0件)
} else {
todaysTaskMessageLabel.text = "本日のタスクはありません"
}
}
func reloadSystemData(checkCount: Int) {
if checkCount == 1 {
tableView.reloadData()
}
}
func setDateSystem(date: Date) {
print(date)
//プッシュ通知認証許可フラグ
var isFirst = true
//デリゲートメソッドを使えるように設定
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (granted, error) in
self.notificationGranted = granted
if let error = error {
print("エラーです")
}
self.setNotification(date: date)
}
isFirst = false
}
func setNotification(date: Date) {
//通知日時の設定
var notificationTime = DateComponents()
var trigger: UNNotificationTrigger
//ここにdatepickerで取得した値をset
notificationTime = Calendar.current.dateComponents(in: TimeZone.current, from: date)
trigger = UNCalendarNotificationTrigger(dateMatching: notificationTime, repeats: true)
let content = UNMutableNotificationContent()
content.title = "タスク実行時間です"
content.body = "タスクを実行してください"
content.sound = .default
//通知スタイル
let request = UNNotificationRequest(identifier: "uuid", content: content, trigger: trigger)
//通知をセット
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
//NFセンターに登録した一覧を表示
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (requests: [UNNotificationRequest]) in
for request in requests {
print(request)
print("---------------")
}
}
}
//セクションのセルの数
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return textArray.count
}
//セクション数(今回は1つ)
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//セルの中身
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = textArray[indexPath.row]
return cell
}
//セルが選択された時
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
textFieldTouchReturnKey = false
indexNumber = indexPath.row
}
//セルの高さ
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return view.frame.size.height / 8
}
//セルをスワイプで削除
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteButton: UITableViewRowAction = UITableViewRowAction(style: .normal, title: "削除") { (action, index) -> Void in
self.textArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
deleteButton.backgroundColor = UIColor.red
return [deleteButton]
}
//値を次の画面へ渡す処理
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//セルがタップされた状態(タスク詳細画面の表示)
if (segue.identifier == "next") &&
textFieldTouchReturnKey == false {
//タップした時にその配列の番号の中身を取り出して値を渡す
let nextVC = segue.destination as! NextViewController
//変数名.が持つ変数 = 渡したいものが入った変数
nextVC.taskNameString = textArray[indexNumber]
} else if (segue.identifier == "next") && textFieldTouchReturnKey == true {
//タップした時にその配列の番号の中身を取り出して値を渡す
let nextVC = segue.destination as! NextViewController
nextVC.taskNameString = textField.text!
nextVC.reloadData = self
nextVC.dateProtol = self
}
}
//returnキーが押された時に発動するメソッド
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
//リターンキーが押された
textFieldTouchReturnKey = true
textArray.append(textField.text!)
textField.resignFirstResponder()
//タスク作成画面へ遷移させる
performSegue(withIdentifier: "next", sender: nil)
return true
}
}
swift
//NextViewController.swift
import UIKit
protocol ReloadProtocol {
//規則をきめる
func reloadSystemData(checkCount: Int)
}
protocol DateProtocol {
//規則を決める
func setDateSystem(date: Date)
}
class NextViewController: UIViewController {
var reloadData: ReloadProtocol?
var dateProtol: DateProtocol?
//タスク名のテキストフィールド
var taskNameString = String()
@IBOutlet weak var taskNameTextField: UITextField!
//タスク通知日時のDatePicker
@IBOutlet weak var taskDatePicker: UIDatePicker!
override func viewDidLoad() {
super.viewDidLoad()
// let appDelegate:AppDelegate = UIApplication.shared.delegate as! AppDelegate
// appDelegate.viewController = self
taskNameTextField.text = taskNameString
//Datepicker無効果
taskDatePicker.isEnabled = false
//デートピッカーの値を取得
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "HH:mm"
//動作確認用コード
print("\(formatter.string(from: taskDatePicker.date))")
}
//タスク通知セグメント設定
@IBAction func taskSegment(_ sender: Any) {
switch (sender as AnyObject).selectedSegmentIndex {
case 0:
//タスク通知のdatepickerを無効化する処理
taskDatePicker.isEnabled = false
//datepickerの入力値を空にする
//タスク通知のdatepickerを有効化する処理
case 1: taskDatePicker.isEnabled = true
default:
taskDatePicker.isEnabled = false
break
}
}
//戻るボタン
@IBAction func back(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
//完了ボタン
@IBAction func done(_ sender: Any) {
dateProtol!.setDateSystem(date: taskDatePicker!.date)
print(taskDatePicker.date)
reloadData?.reloadSystemData(checkCount: 1)
dismiss(animated: true, completion: nil)
}
}