ホーム

aguuu

iOS 標準アプリの時計の様に指定時間・曜日にメッセージを通知する方法

  • 投稿者: tochi
  • 2011/9/12 月曜日 15:50:09
  • iPhone
  • このエントリーをはてなブックマークに追加

iOS標準の時計アプリでは時間と曜日を指定して、その時間にアラームを通知する方法があります。
今回は同じような方法でメッセージを通知する方法がないかなぁ〜と思って調べました。(仕事で使う予定があるから)

やりたいことはこんな感じ

  • アプリでメッセージを通知したい曜日と時間を設定
  • アプリを終了(バックグラウンドでもOK)
  • 指定した曜日と時間になったらメッセージを通知
  • 「OK」ボタンを押下するとアプリが起動

で調べたけど、メッセージを通知するのはUIRemoteNotification、UILocalNotificationというのを使うらしい。
UIRemoteNotificationはサーバーを立ててそこからメッセージを一括送信する場合などに使うみたい。
UILocalNotificationは指定時間にメッセージを表示する方法で端末内で完結できる。
ということで、今回はUILocalNotificationを使う。

で今回最も悩んだのが、UILocalNotificationに指定曜日にメッセージを通知する方法。
repeatIntervalというプロパティがあるのですが、毎日とか毎時ならこれでOKなんだけど、指定曜日(毎週月・火・木)となると、できないみたい。(多分)

で色々と調べた結果、簡単に設定できるプロパティはないのではないかと。。。

Notification系のものは内部にカレンダー形式でローカル通知の予定を登録しているようなので、ぐるぐる回しながら自分で曜日を判断して登録するという方法を取りました。困ったときは回せば良い。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[[UIApplication sharedApplication] cancelAllLocalNotifications];

NSInteger repeartCount = 7;

for (NSInteger i = 0; i < repeartCount; i++) {
  date = [today dateByAddingTimeInterval:i * 24 * 60 * 60];
  dateComponents = [calendar components:NSWeekdayCalendarUnit fromDate:date];

  if ([selectedWeek containsObject:[NSNumber numberWithInteger:dateComponents.weekday - 1]]) {
  // Adding the local notification.
  dateString = [NSString stringWithFormat:@"%@ %@",
  [dateFormat stringFromDate:date],
  [timeFormat stringFromDate:notificationTime]];

  if ([today compare:[format dateFromString:dateString]] == NSOrderedAscending) {
    notification.fireDate = [format dateFromString:dateString];
    notification.timeZone = [NSTimeZone localTimeZone];
    notification.alertBody = [NSString stringWithFormat:@"Notify:%@", dateString];
    notification.soundName = UILocalNotificationDefaultSoundName;
    notification.alertAction = @"Open";
    notification.repeatCalendar
    [[UIApplication sharedApplication] scheduleLocalNotification:notification];
  }
}

1行目の「[[UIApplication sharedApplication] cancelAllLocalNotifications]」で現在登録されているメッセージ通知のカレンダーを全クリアします。これは後で何度もこの処理を実行するので重複してローカル通知が登録されないようにするためです。

3行目で繰り返しを行う日数を今日から含めて指定します。今回は今日から7日間に指定しました。最大で7日分のローカル通知の予定を登録します。UILocalNotificationは最大で60前後のカレンダーが登録できるみたいです。

5行目から指定回数分ループで回します。

6行目で日付を取得して、9行目でその日付の曜日を取得してその曜日が登録すべき曜日かを判断しています。selectedWeekには日曜日〜土曜日までを0〜6の数値で保持しているので、containsObjectで配列内の要素の存在確認を行っています。

登録すべき曜日であれば、11〜22行目の処理によってメッセージ通知の登録が行われていきます。
ちなみに15行目では登録する日付が過去日付ならば登録をスキップしています。今日が月曜日の12時でローカル通知を月曜日の6持で設定すると過去日付になるので1回目の通知が即座に表示されてしまうので。

でこの方法だと登録されているローカル通知を全部通知し終わってしまうと通知されなくなります。
そこで、UILocalNotificationのデリゲートを使って起動の度に上記の処理を実行します。
デリゲートはメッセージ通知のアクションボタンが押下されてアプリが起動される度に呼び出されるみたい。

1
2
3
4
5
6
7
8
9
10
11
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  UILocalNotification *notification;
  notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
  if (notification) {
    [LocalNotificationManager addLocalNotification];
  }

  return YES;
}

でまずは、アプリが完全に終了(バックグラウンドで動作していない)している場合には、「application:didFinishLaunchingWithOptions:」から起動されます。

4〜8行目でこの起動がNotificationによるものなのか判断してもし、Notificationによるものだったら7行目でローカル通知の処理を実行しています。

1
2
3
4
5
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
  [LocalNotificationManager addLocalNotification];
}

でもう一個のデリゲートが「application:didReceiveLocalNotification:」でこちらはバックグラウンドでアプリが動作していた場合に呼ばれます。あとは先程と同様にローカル通知の処理を実行して完了です。

これでローカル通知が指定した曜日の時間に起動され、通知によってアプリが起動された場合には再度起動した日から7日間のスケジュールが再登録されるようになりました。

まあただこの方法だと、ローカル通知で呼び出しても起動されなかった場合には登録した通知を全て表示し終わった場合には通知されなくなりますね。
アプリ起動時に毎回ローカル通知の登録を行っても、やっぱり同じでアプリ起動もローカル通知による起動もまったく行われなかった場合にはいつか通知されなくなります。

永久的にローカル通知を表示することはできるのかな?(良い方法があればダレか教えて。)

ということで今回の確認に使ったサンプルをgithubに上げておきます。

LocalNotificationSample

もうちょっと使いやすい様にクラス化すればよかったんですけどね。。。それはオイオイということで。

rails generateで作成されるひな形をカスタマイズする方法

Railsではcontroller内で日本語などを使用する場合には先頭に「# coding: utf-8」というマジックコメントを記入しないといけないらしい。
でも毎回これを記述するのがメンドクサイ。

Controllerを作成する場合には「rails generate controller hoge」というRailsのコマンドを使って雛形を作るのですが、このひな形に最初から記述されていればマジックコメントを記述する手間が省ける訳で。
たった一行の為に探しましたよ色々と。「プログラマーの三大美徳 怠慢」

まずは下記のrakeコマンドでgenerateで使われるテンプレートをアプリフォルダーにコピーします。

1
rake rails:templates:copy

各種テンプレートは「MyApp/lib/templates」にコピーされるので、この中の「MyApp/lib/templates/rails/controller/controller.rb」をテキストエディタなどで開きます。
このファイルが「rails generate controller hoge」で使用されるテンプレートなのでこれを編集します。
マジックコメントを記述して、その他にもRDoc用のコメントも記述しておきます。
このテンプレート内では「class_name」「action」などの変数も使用出来るみたいなので自分好みにカスタマイズしてください。その他にも取得できる変数ってないんだろうか?

1
2
3
4
5
6
7
8
9
10
11
12
13
# coding: utf-8                                                                                                                                                                      

# Author:: tochi                                                                                                                                                                    
# Copyright 2011 aguuu Inc. All rights reserved.                                                                                                                                    
class < %= class_name %>Controller < ApplicationController
<% for action in actions -%>
  #                                                                                                                                                                                  
  def < %= action %>

  end

< % end -%>
end

あとは上記のテンプレートを保存していつも通りに「rails generate controller hoge」とコマンド入力すれば該当のテンプレートに沿ったひな形が作成されます。

その他にもテンプレートにはscaffoldのテンプレートや、Viewに関連するテンプレートがカスタマイズできるみたいです。

ただモデルに関連するテンプレートは無いですね。。。変更できないのか?

上記の事も下記の書籍に書いていました。
初心者〜中級者向けの書籍としてはとってもおすすめです。

iOSのUILabelで文字列の縦位置を調整する方法

  • 投稿者: tochi
  • 2011/8/8 月曜日 11:54:25
  • iPhone
  • このエントリーをはてなブックマークに追加

UIButtonなどのtitleLabelに文字列を設定した場合に上にずれることがあります。
UILabelで以前に同様の問題に悩まされてゴリゴリとやっていたのですが、少しだけシンプルな方法を見つけたのでメモしておきます。

IBを使ってUIButtonを配置して「Type=Cutom」として、Fontを「ヒラギノ角ゴ ProN W6」で指定すると下記の通り上にずれます。
ここで真っ先に考えるのがtitleLabelの縦位置(Vertical Alignment)をCenterに!っと考えるんですけど、無いんですよね。。。そんなプロパティ。(確かKeynoteでも縦位置の調整が無いんだよな。。。Apple的には縦位置は上揃えなんでしょうか。。。)

UIButtonの中身の位置を微調整する

そこで中身を下記のように微調整すると縦位置を強制的に変更することができます。
この方法の問題は文字サイズを変更した場合に再度微調整する必要があります。

1
button.contentEdgeInsets = UIEdgeInsetsMake(8.0f, 0.0f, 0.0f, 0.0f);

フォントの種類を変更する

で、もう1つの方法がtitleLabelのフォント種類を「Helvetica-Bold」で指定する方法。
こっちは「Helvetica-Bold」で指定しても表示するときは「ヒラギノ」になっているような気がする。。。

1
button.titleLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:18.0f];

これらの方法は最もベストでは無い気がしますが現状ではベターではある気がします。
できれば、UIButtonやUILabelにverticalAlignのプロパティを準備してほしいですけどね。。。

ホーム

検索
フィード
メタ情報

ページの上部に戻る