公開中のアプリ

[Swift/Xcode]初心者必見!iOSアプリ作成から公開まで徹底解説!#26「ローカル通知編③」

今回でローカル通知は完成です!

ここさえクリアすればもうアプリはほぼ完成と言っていいでしょう!

あとは広告つけたりアプリのアイコンを作ったりやる事はありますが(^^;

もう一度、動画貼っておきます!

動作環境は下記の通りです!
Xcode Version 12.5 Swift version 5.4

Switchを切り替えた時の処理

SwitchをONにしたらアラームをセットして、OFFにしたらアラームを解除したいと思います。

まずはSwitchを切り替えた時の処理を書いていきます!
編集するファイルはNotificationViewController.swiftです。

@objc func changeSwitch(_ sender: Any) {

    if (sender as AnyObject).isOn {

        // 通知を管理するクラスのシングルトンを取得
        let center = UNUserNotificationCenter.current()

        // datePickerで指定された時間を取得
        let date = self.datePicker.date

        //datePickerに時刻を保存
        let valueToSave = self.datePicker.date
        UserDefaults.standard.set(valueToSave, forKey: "Date")

        // 予定されている全ての通知の設定を削除してから通知の設定を行う
        center.removeAllPendingNotificationRequests()

        // 通知の内容を設定 ======
        let content = UNMutableNotificationContent()

        // 通知のタイトル
        content.title = "貯金箱に貯金してや〜"

        // 通知のサブタイトル(iOS10から使用可能)
        //content.subtitle = ""

        // 通知の本文
        //content.body = ""

        // 通知音の設定
        content.sound = UNNotificationSound.default

        // カレンダーのインスタンスを生成
        let calendar = Calendar.current

        // 日付や時間をを数値で取得できるDateComponentsを作成
        // 今回はdatePickerで設定した時間を基に時間、分のみを取得
        let dateComponents = calendar.dateComponents([.hour, .minute], from: date)

        // どの時間で通知をするかを設定するか、繰り返し通知するかの設定
        // dateComponentsで設定した時間で通知。今回は繰り返し通知を行うので、repeatsはtrue
        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents,repeats: true)

        // 通知の識別子を設定
        let identifier = "Notification"

        // 通知の内容と時間を基にリクエストを作成
        let request = UNNotificationRequest(identifier:identifier,
                                            content:content,
                                            trigger:trigger)
        // 通知を設定する
        center.add(request, withCompletionHandler: nil)

        //アラート
        let alertController = self.common.originalAlert(title: "アラームをセットしました", message: "")
        self.present(alertController, animated: true, completion: nil)

    } else {
        // 予定されている通知を解除する
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
        //アラート
        let alertController = self.common.originalAlert(title: "アラームを解除しました", message: "")
        self.present(alertController, animated: true, completion: nil)
    }
}

ローカル通知を設定しているのは、5行目〜52行目です。

コードのコメントに説明が書いてあるので詳しい説明は省きますね!
コピペでOKだと思います!

通知のサブタイトルとか本文はまだ未設定にしています!
タイトルも多分変更すると思います。

11行目〜13行目は設定した時間を保存しています。

例えば11時13分にアラームをセットしたとして、再びアラーム設定画面を開い時に11時13分を表示した状態にする為です。


あと、60行目で通知解除してます!

UIDatePickerの値が変更された場合

ON状態で、UIDatePickerを動かしたら自動的にOFFにしてもう一度ONにしないとアラームがセットされないようにしたいと思います。

layout()の中に下記コードを追加してメソッドをセットします。
コードは下記です!

datePicker.addTarget(self, action: #selector(changeDatePicker), for: UIControl.Event.valueChanged)

次にそのメソッド内でUIDatePickerの値が変更されたらSwitchの状態をOFFに変更します。

@objc func changeDatePicker(_ sender: Any) {
    //DatePickerの値が変更されて、SwitchがオンだったらSwitchをオフにして
    //アラーム設定を解除する
    if self.notificationSwitch.isOn == true {
        self.notificationSwitch.isOn = false
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
    }

}

予定されている通知の取得

viewDidLoad()時に既にローカル通知が設定されている場合、SwitchをONの状態に変更しておきます!

ついでに、datePickerの保存した時刻をセットします!

override func viewDidLoad() {
super.viewDidLoad()
//レイアウト
layout()
//datePickerに時刻をセット
if let value = UserDefaults.standard.object(forKey: "Date") as? Date {
    datePicker.date = value
}
// これから予定されている通知を取得
UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
    // これから予定されている通知がある=通知の設定は行われている
    if requests.count > 0 {
        // UIの変更を伴うので、メインスレッドで処理を行わせる
        DispatchQueue.main.async {
            // スイッチをオンに変更
            self.notificationSwitch.isOn = true
        }
    }
}
}

これで完了です!
一度ビルドして確認してみて下さい!
動画のようになってると思います!

まとめ

なんとかローカル通知を実装できました!

個人的に前回のアプリで断念していたので今回実装できて良かったです!

次は広告かアイコンの作成あたりをしたいと思います!

コード全部

NotificationViewController.swift

import UIKit

class NotificationViewController: UIViewController {
//Commonクラスのインスタンス生成
let common = Common()
//Cancelボタン
var cancelBtn: UIBarButtonItem!
//トップラベルを入れるビュー
let topView: UIView = UIView()
//トップのラベル
let topLabel: UILabel = UILabel()
//通知設定のラベル
let notificationLabel: UILabel = UILabel()
//Switch
let notificationSwitch: UISwitch = UISwitch()
//datePicker
let datePicker: UIDatePicker = UIDatePicker()

override func viewDidLoad() {
super.viewDidLoad()
//レイアウト
layout()
//datePickerに時刻をセット
if let value = UserDefaults.standard.object(forKey: "Date") as? Date {
    datePicker.date = value
}
// これから予定されている通知を取得
UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
    // これから予定されている通知がある=通知の設定は行われている
    if requests.count > 0 {
        // UIの変更を伴うので、メインスレッドで処理を行わせる
        DispatchQueue.main.async {
            // スイッチをオンに変更
            self.notificationSwitch.isOn = true
        }
    }
}
}

//Cancelボタンのメソッド
@objc func cancelBtnTapped() {
    //前の画面に戻る
    dismiss(animated: true, completion: nil)
}


func layout() {
    //バックグランドカラー設定
    self.view.backgroundColor = UIColor(hex: common.background , alpha: 1)

    //オブジェクト追加
    self.view.addSubview(topView)
    topView.addSubview(topLabel)
    self.view.addSubview(notificationLabel)
    self.view.addSubview(notificationSwitch)
    self.view.addSubview(datePicker)

    //トップビューのレイアウト
    topView.translatesAutoresizingMaskIntoConstraints = false
    topView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 1).isActive = true
    topView.heightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.08).isActive = true
    topView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
    topView.backgroundColor = UIColor(hex: common.white , alpha: 1)

    //トップラベルのレイアウト
    topLabel.translatesAutoresizingMaskIntoConstraints = false
    topLabel.leftAnchor.constraint(equalTo: topView.leftAnchor, constant: 20.0).isActive = true
    topLabel.centerYAnchor.constraint(equalTo: topView.centerYAnchor).isActive = true
    topLabel.font = UIFont(name: "HiraMaruProN-W4", size: 16)
    topLabel.textColor = UIColor(hex: common.text , alpha: 1)
    topLabel.text = "貯金忘れ防止のために通知設定ができます"

    //アラートラベルのレイアウト
    notificationLabel.translatesAutoresizingMaskIntoConstraints = false
    notificationLabel.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor, constant: 20.0).isActive = true
    notificationLabel.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: 30.0).isActive = true
    notificationLabel.font = UIFont(name: "HiraMaruProN-W4", size: 16)
    notificationLabel.textColor = UIColor(hex: common.text , alpha: 1)
    notificationLabel.text = "通知設定"

    //Switchのレイアウト
    notificationSwitch.translatesAutoresizingMaskIntoConstraints = false
    notificationSwitch.rightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.rightAnchor, constant: -20.0).isActive = true
    notificationSwitch.centerYAnchor.constraint(equalTo: notificationLabel.centerYAnchor).isActive = true
    //オンにした時の色
    notificationSwitch.onTintColor = UIColor(hex: common.sub, alpha: 1)
    //UISwitch値が変更された時に呼び出すメソッドの設定
    notificationSwitch.addTarget(self, action: #selector(changeSwitch), for: UIControl.Event.valueChanged)//追加
    //一旦オフ・操作不可にする
    notificationSwitch.isOn = false//追加

    //datePickerのレイアウト
    datePicker.translatesAutoresizingMaskIntoConstraints = false
    datePicker.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 1).isActive = true
    datePicker.heightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.4).isActive = true
    datePicker.topAnchor.constraint(equalTo: notificationLabel.bottomAnchor, constant: 30).isActive = true
    //スタイル
    datePicker.preferredDatePickerStyle = .wheels
    //表示させるモードの設定。今回は時間だけを表示
    datePicker.datePickerMode = UIDatePicker.Mode.time
    //テキストカラ-
    datePicker.setValue(UIColor(hex: common.text, alpha: 1), forKey: "textColor")
    //背景色
    datePicker.backgroundColor = UIColor.white
    datePicker.addTarget(self, action: #selector(changeDatePicker), for: UIControl.Event.valueChanged)
    //ナビゲーションコントローラーまわり
    //タイトル
    self.title = "アラーム設定"
    //背景色
    self.navigationController?.navigationBar.barTintColor = UIColor(hex: self.common.main , alpha: 1)
    //セーフエリアとの境目の線を消す
    self.navigationController?.navigationBar.shadowImage = UIImage()
    //フォントの設定
    self.navigationController?.navigationBar.titleTextAttributes
        = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "HiraMaruProN-W4", size: 20)!]
    //Cancelボタンを追加
    cancelBtn = UIBarButtonItem(title: "Cancel", style: .done, target: self, action: #selector(self.cancelBtnTapped))
    cancelBtn.tintColor = UIColor(hex: self.common.white , alpha: 1)
    self.navigationItem.leftBarButtonItem = cancelBtn
}

//追加
@objc func changeSwitch(_ sender: Any) {

    if (sender as AnyObject).isOn {

        // 通知を管理するクラスのシングルトンを取得
        let center = UNUserNotificationCenter.current()

        // datePickerで指定された時間を取得
        let date = self.datePicker.date

        //datePickerに時刻を保存
        let valueToSave = self.datePicker.date
        UserDefaults.standard.set(valueToSave, forKey: "Date")

        // 予定されている全ての通知の設定を削除してから通知の設定を行う
        center.removeAllPendingNotificationRequests()

        // 通知の内容を設定 ======
        let content = UNMutableNotificationContent()

        // 通知のタイトル
        content.title = "貯金箱に貯金してや〜"

        // 通知のサブタイトル(iOS10から使用可能)
        //content.subtitle = ""

        // 通知の本文
        //content.body = ""

        // 通知音の設定
        content.sound = UNNotificationSound.default

        // カレンダーのインスタンスを生成
        let calendar = Calendar.current

        // 日付や時間をを数値で取得できるDateComponentsを作成
        // 今回はdatePickerで設定した時間を基に時間、分のみを取得
        let dateComponents = calendar.dateComponents([.hour, .minute], from: date)

        // どの時間で通知をするかを設定するか、繰り返し通知するかの設定
        // dateComponentsで設定した時間で通知。今回は繰り返し通知を行うので、repeatsはtrue
        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents,repeats: true)

        // 通知の識別子を設定
        let identifier = "Notification"

        // 通知の内容と時間を基にリクエストを作成
        let request = UNNotificationRequest(identifier:identifier,
                                            content:content,
                                            trigger:trigger)
        // 通知を設定する
        center.add(request, withCompletionHandler: nil)

        //アラート
        let alertController = self.common.originalAlert(title: "アラームをセットしました", message: "")
        self.present(alertController, animated: true, completion: nil)

    } else {
        // 予定されている通知を解除する
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
        //アラート
        let alertController = self.common.originalAlert(title: "アラームを解除しました", message: "")
        self.present(alertController, animated: true, completion: nil)
    }
}
@objc func changeDatePicker(_ sender: Any) {
    //DatePickerの値が変更されて、SwitchがオンだったらSwitchをオフにして
    //アラーム設定を解除する
    if self.notificationSwitch.isOn == true {
        self.notificationSwitch.isOn = false
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
    }

}
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

アプリ