iOSプログラミング with Swift 2


2016.07.11: created by

SwiftでLocal Notificationを使う

指定した時間が来たらプログラムを呼び出すには Local Notification を使います。 アプリが起動していなくても、通知を受け取って アプリを起動することができます。

  1. Xcode を起動して "Create a new Xcode project" で "Single View Application" として新しいプロジェクトを開きます。 ここではプロジェクト名を SwiftLocalNotification としています。



  2. Storyboard上の ViewController 上に Button を配置します。



  3. Storyboard上のViewController 上に配置した Button を ViewController.swift 中に Action (Touch Up Inside) で tapButton関数にconnectします。



  4. ViewController.swift を変更します。
  5. ViewController.swiftに追加するコード(赤字部分)
    import UIKit
    
    class ViewController: UIViewController {
    
        @IBAction func tapButton(sender: AnyObject) {
            let app = UIApplication.sharedApplication()
            app.cancelAllLocalNotifications();
            app.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge], categories: nil))
            
            let date = NSDate().dateByAddingTimeInterval(NSTimeInterval(5.0))
            let notification = UILocalNotification()
            notification.alertBody = "Time has reached"
            notification.alertAction = "OK"
            notification.soundName = UILocalNotificationDefaultSoundName
            notification.timeZone = NSTimeZone.defaultTimeZone()
            notification.fireDate = date
            app.scheduleLocalNotification(notification)
        }
            
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    }
    
  6. AppDelegate.swift を変更します。
  7. AppDelegate.swiftに追加するコード(赤字部分)
    import UIKit
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
        func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
            let alert: UIAlertController = UIAlertController(title:"Local Notify",
                                                           message: notification.alertBody,
                                                    preferredStyle: UIAlertControllerStyle.Alert)
            alert.addAction(UIAlertAction(title:"Cancel",style:UIAlertActionStyle.Cancel,handler:nil))
            self.window!.rootViewController!.presentViewController(alert, animated: true, completion: nil)
        }
        
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            return true
        }
    
        func applicationWillResignActive(application: UIApplication) {
        }
    
        func applicationDidEnterBackground(application: UIApplication) {
        }
    
        func applicationWillEnterForeground(application: UIApplication) {
        }
    
        func applicationDidBecomeActive(application: UIApplication) {
        }
    
        func applicationWillTerminate(application: UIApplication) {
        }
    }
    
  8. プログラムを実行します。 画面が表示されるので、 ボタンをタップして数秒待つと Local Notification を受け取って Alert が表示されます。
  9. -->
    最初にプログラムを実行するときは、通知を有効にしてもよいか聞いてくるので OKをタップする必要があります(iOS8以降)。


  10. プログラムを実行してボタンをタップしてから、 通知が来るまでの間にプログラムの実行を停止しておくと、 通知はホーム画面の上に表示されます。 このとき、通知をタップするとプログラムが再度アクティブになります。
  11. -->
  12. サンプルのプロジェクトはこちら。(Xcode 7.3.1版)

通知情報を画面に反映する

  1. Storyboard上の ViewController 上に Label を追加します。



  2. Storyboard上のViewController 上に配置した Label を ViewController.swift 中に IBOutlet で myLabel 変数にconnectします。



  3. ViewController.swift を変更します。
  4. ViewController.swift(myLabel変数の宣言は増えたが、自分で追加するコードなし)
    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var myLabel: UILabel!
        @IBAction func tapButton(sender: AnyObject) {
            let app = UIApplication.sharedApplication()
            app.cancelAllLocalNotifications();
            app.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge], categories: nil))
            
            let date = NSDate().dateByAddingTimeInterval(NSTimeInterval(5.0))
            let notification = UILocalNotification()
            notification.alertBody = "Time has reached"
            notification.alertAction = "OK"
            notification.soundName = UILocalNotificationDefaultSoundName
            notification.timeZone = NSTimeZone.defaultTimeZone()
            notification.fireDate = date
            app.scheduleLocalNotification(notification)
        }
            
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    }
    
  5. AppDelegate.swift を変更します。
  6. AppDelegate.swiftに追加するコード(緑字部分)
    import UIKit
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
        func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
            let vc: ViewController = self.window!.rootViewController as! ViewController
            vc.myLabel.text = notification.alertBody
            let alert: UIAlertController = UIAlertController(title:"Local Notify",
                                                           message: notification.alertBody,
                                                    preferredStyle: UIAlertControllerStyle.Alert)
            alert.addAction(UIAlertAction(title:"Cancel",style:UIAlertActionStyle.Cancel,handler:nil))
            self.window!.rootViewController!.presentViewController(alert, animated: true, completion: nil)
        }
        
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            return true
        }
    
        func applicationWillResignActive(application: UIApplication) {
        }
    
        func applicationDidEnterBackground(application: UIApplication) {
        }
    
        func applicationWillEnterForeground(application: UIApplication) {
        }
    
        func applicationDidBecomeActive(application: UIApplication) {
        }
    
        func applicationWillTerminate(application: UIApplication) {
        }
    }
    
  7. プログラムを実行します。 画面が表示されるので、 ボタンをタップして数秒待つと Local Notification を受け取って Alert が表示されます。 Label の表示は通知内容に変更され、Alertが消えてもLabelの表示そのままです。

  8. --> -->

  9. プログラムを実行してボタンをタップしてから、 通知が来るまでの間にプログラムの実行を停止しておくと、 通知はホーム画面の上に表示されます。 このとき、通知をタップするとプログラムが再度アクティブになります。 ただし、この場合はLabelの表示は通知内容にはなりません。

  10. -->

  11. サンプルのプロジェクトはこちら。(Xcode 7.3.1版)

通知情報を画面に反映する2

アプリが非アクティブな状態のときに Local Notification が通知されると AppDelegateのapplication:didFinishLaunchingWithOptions: 経由で起動されます。 このときに、起動オプションの中にLocalNotificationの情報があれば そこから情報を取り出します。

この段階ではまだ self.window.rootViewController などが生成されていないので、 取り出した通知情報は AppDelegate の変数に保持します。

  1. ViewController.swift を変更します。
  2. ViewController.swif(マゼンタ色の部分を追加)
    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var myLabel: UILabel!
        @IBAction func tapButton(sender: AnyObject) {
            let app = UIApplication.sharedApplication()
            app.cancelAllLocalNotifications();
            app.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge], categories: nil))     
            let date = NSDate().dateByAddingTimeInterval(NSTimeInterval(5.0))
            let notification = UILocalNotification()
            notification.alertBody = "Time has reached"
            notification.alertAction = "OK"
            notification.soundName = UILocalNotificationDefaultSoundName
            notification.timeZone = NSTimeZone.defaultTimeZone()
            notification.fireDate = date
            app.scheduleLocalNotification(notification)
        }
            
        override func viewDidLoad() {
            super.viewDidLoad()
            let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
            if let msg = appDelegate.notifiedMessage {
                myLabel.text = msg
            }
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    }
    
  3. AppDelegate.swift を変更します。
  4. AppDelegate.swiftに追加するコード(マゼンダ色の字部分)
    import UIKit
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
        var notifiedMessage: String?
    
        func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
            let vc: ViewController = self.window!.rootViewController as! ViewController
            vc.myLabel.text = notification.alertBody
            let alert: UIAlertController = UIAlertController(title:"Local Notify",
                                                           message: notification.alertBody,
                                                    preferredStyle: UIAlertControllerStyle.Alert)
            alert.addAction(UIAlertAction(title:"Cancel",style:UIAlertActionStyle.Cancel,handler:nil))
            self.window!.rootViewController!.presentViewController(alert, animated: true, completion: nil)
        }
        
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
           if let option = launchOptions {
                let notification = option[UIApplicationLaunchOptionsLocalNotificationKey] as! UILocalNotification?
                notifiedMessage = notification?.alertBody
            }
            return true
        }
    
        func applicationWillResignActive(application: UIApplication) {
        }
    
        func applicationDidEnterBackground(application: UIApplication) {
        }
    
        func applicationWillEnterForeground(application: UIApplication) {
        }
    
        func applicationDidBecomeActive(application: UIApplication) {
        }
    
        func applicationWillTerminate(application: UIApplication) {
        }
    }
    
  5. プログラムを実行します。 プログラムを実行してボタンをタップしてから、 通知が来るまでの間にプログラムの実行を停止しておくと、 通知はホーム画面の上に表示されます。 このとき、通知をタップするとプログラムが再度アクティブになります。 このとき、Labelの表示は変更されています。

  6. -->

  7. サンプルのプロジェクトはこちら。(Xcode 7.3.1版)

指定された日時に通知する

上記の例では、現在時刻から数秒後に通知を設定していました。 特定の日時にローカル通知が来るように設定してみます。

  1. Storyboard上の ViewController 上に DatePicker を配置します。



  2. Main.Storyboard上の DatePicker を、IBOutlet で ViewController.swift中の myDatePicker変数にconnect します。



  3. ViewController.swift を変更します。
  4. ViewController.swiftの変更点(水色の字部分)(黄色の文字部分はなくても動きます)
    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var myDatePicker: UIDatePicker!
        @IBOutlet weak var myLabel: UILabel!
        @IBAction func tapButton(sender: AnyObject) {
            let app = UIApplication.sharedApplication()
            app.cancelAllLocalNotifications();
            app.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge], categories: nil))
            
            let date = myDatePicker.date
            print(date)
            let format = NSDateFormatter()
            format.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
            format.timeZone = NSTimeZone(abbreviation: "JST")
            print(format.stringFromDate(date))
    
            let notification = UILocalNotification()
            notification.alertBody = "Time has reached"
            notification.alertAction = "OK"
            notification.soundName = UILocalNotificationDefaultSoundName
            notification.timeZone = NSTimeZone.defaultTimeZone()
            notification.fireDate = date
            app.scheduleLocalNotification(notification)
        }
            
        override func viewDidLoad() {
            super.viewDidLoad()
            let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
            if let msg = appDelegate.notifiedMessage {
                myLabel.text = msg
            }
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    
    }
    
  5. 実行すると DatePicker の初期値は起動時刻になっています。 これで日時を指定してボタンをタップすると、指定した時刻に通知がきます。

  6. --> -->

  7. ここで、Xcodeの下に表示されているlogを見ると、DatePicker.date をそのまま表示した部分では 9時間遅い時刻 (07:18:24) が表示されているのがわかります。 すなわち、UTC (世界標準時)で時刻を表しているのです。 これを日本の時刻で表示するには NSDateFormatter を使って、タイムゾーンに JST を指定してStringに変換(16:18:24)します。 これを行っているのが上のViewController.swift の黄色い字の部分です。
  8. サンプルのプロジェクトはこちら。(Xcode 7.3.1版)


http://karel.tsuda.ac.jp