xcode4.2+iPhone iOS5でGoogleCalendarのデータを読み込む【Calendarへアクセス編】

GoogleCalendarにアクセスする手順はこんな感じ。

  1. GoogleCalendarにログインしてカレンダー情報の取得を要求する
  2. カレンダー情報要求の返信が来たら、返信内容からカレンダー情報を取得し、カレンダーに属するイベント情報の取得を要求する
  3. イベント情報要求の返信が来たら、返信内容からカレンダーのイベント情報を取得

プロジェクトファイル一式はここに置いているので詳細を知りたい方はどうぞ。
yuriken27/GoogleCalendarAccessTest · GitHub

1.GoogleCalendarにログインしてカレンダー情報の取得を要求する

まずは以下のようなコードを実行。

    GDataServiceGoogleCalendar *gDataSrviceCalendar;
    gDataSrviceCalendar = [[GDataServiceGoogleCalendar alloc] init];

    // ログイン情報
    [gDataSrviceCalendar setUserCredentialsWithUsername:@"ユーザ名@gmail.com"
                                               password:@"パスワード"];
    
    // http://code.google.com/p/gdata-objectivec-client/wiki/PerformanceTuning
    [gDataSrviceCalendar setServiceShouldFollowNextLinks:YES];
    [gDataSrviceCalendar setShouldServiceFeedsIgnoreUnknowns:YES];
    
    // 全てのカレンダーを取得するURL
    NSURL *feedURL = [NSURL URLWithString:kGDataGoogleCalendarDefaultAllCalendarsFeed];
    
    GDataServiceTicket *ticket;
    ticket = [gDataSrviceCalendar fetchFeedWithURL:feedURL
                                          delegate:self
                                 didFinishSelector:@selector(ticket:finishedWithFeed:error:)];

最後の「gDataSrviceCalendar fetchFeedWithURL」メソッドでカレンダー情報の取得を要求している。

ここでは、「didFinishSelector」の引数として「@selector(ticket:finishedWithFeed:error:)」を指定しており、GoogleCalendarから返信があったときに「ticket」メソッドが自動的に呼び出される。

2.カレンダー情報要求の返信が来たら、返信内容からカレンダー情報を取得し、カレンダーに属するイベント情報の取得を要求する

カレンダー情報の取得が成功すると、ticketメソッドが呼び出される。

-(void)ticket:(GDataServiceTicket *) ticket
finishedWithFeed:(GDataFeedCalendar *)feed
        error:(NSError *)error {
    if (error || [[feed entries] count] == 0) {
        NSLog(@"fetch error: %@", error);
        return;
    }
    
    // カレンダーデータがある場合
    for (GDataEntryCalendar *calendar in [feed entries]){
        
        GDataTextConstruct *titleTextConstruct = [calendar title];
        
        NSString *calendarTitle = [titleTextConstruct stringValue];
        GDataLink *link = [calendar alternateLink];
        
        if (link == nil) {
            continue;
        }
        
        // CalendarManagerにCalendarを追加作成
        m_CalendarData = [self createCalendar:calendarTitle];                     // カレンダー名
        m_CalendarData.calendarLocation    = [[calendar locations] description];  // カレンダーの場所
        m_CalendarData.calendarDescription = [calendar.title stringValue];        // カレンダーの説明
        
        // イベントデータの表示色
        GDataColorProperty *colorProp = [calendar color];
        m_CalendarData.calendarColor = [colorProp stringValueForAttribute:[colorProp attributeName]];
        // タイムゾーン取得
        GDataTimeZoneProperty *timezoneProp = [calendar timeZoneName];
        NSString *timeZoneString = [timezoneProp stringValueForAttribute:[timezoneProp attributeName]];
        m_CalendarData.timezone = [NSTimeZone timeZoneWithName:timeZoneString];
        
        NSURL *calendarURL = [link URL]; // カレンダーから取得したalternateLink
        
        // イベントデータ取得定義開始
        GDataQueryCalendar *query = [GDataQueryCalendar calendarQueryWithFeedURL:calendarURL];

        // 取得するイベントの最大日時
        NSCalendar *nsCalendar = [NSCalendar currentCalendar];
        //NSCalendar *nsCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
        NSDateComponents *comps = [[NSDateComponents alloc] init];
        [comps setDay:startDay]; // 開始日 [0日後から]
        NSDate *minDate = [nsCalendar dateByAddingComponents:comps toDate:[NSDate date] options:0];
        [comps setDay:endDay]; // 終了日 [180日後まで]
        NSDate *maxDate = [nsCalendar dateByAddingComponents:comps toDate:[NSDate date] options:0];
        // タイムゾーン
        NSTimeZone *tz = [NSTimeZone localTimeZone];
        
        GDataDateTime *MinimumDate = [GDataDateTime dateTimeWithDate:minDate timeZone:tz];
        GDataDateTime *MaximumDate = [GDataDateTime dateTimeWithDate:maxDate timeZone:tz];
        
        [query setMinimumStartTime:MinimumDate];
        [query setMaximumStartTime:MaximumDate];
        
        // 開始日でソート 返ってきたデータがソートされていないため、コメント化
        //[query setOrderBy:@"starttime"];
        //[query setMaxResults:2];
        
        // イベントデータ取得をリクエスト
        [gDataSrviceCalendar fetchFeedWithQuery:query 
                                       delegate:self 
                              didFinishSelector:@selector(eventsTicket:finishedWithFeed:error:)];
        
    }
}


メソッドの引数「(GDataFeedCalendar *)feed」にカレンダー情報が格納されているので、一つずつ取り出してカレンダー情報を取得する。
カレンダー毎のイベント情報へのアクセスURLが「link URL」に入っているので、このURLにイベント情報の取得要求を行う。
カレンダー毎に行うため、ここで取得要求を行わないカレンダーのイベント情報は返ってこない。

3.イベント情報要求の返信が来たら、返信内容からカレンダーのイベント情報を取得

イベント情報の返信が来たら、「eventsTicket」が呼び出される。

-(void) eventsTicket:(GDataServiceTicket *)ticket
    finishedWithFeed:(GDataFeedCalendar *)feed
               error:(NSError *) error {
    
    if (error || [[feed entries] count] == 0) {
        NSLog(@"fetch error: %@", error);
        // 通知を作成する
        NSNotification *notice = [NSNotification notificationWithName:notifyMessage object:self];
        // 通知実行
        [[NSNotificationCenter defaultCenter] postNotification:notice];
        return;
    }
    // カレンダー名を取得
    NSString *calendarTitle = [[feed title] stringValue];
    m_CalendarData = [self getCalendarDataByName:calendarTitle];
    
    //GDataEntryCalendar *gDataCalendar;
    GDataEntryCalendarEvent *gDataEvent;
    GDataTextConstruct *titleTextConstruct;
    
    for (GDataFeedCalendar* feedCalendars in [feed entries]) {
        
        // Get Event Infos
        m_EventData = [[EventData alloc] init];
        gDataEvent = (GDataEntryCalendarEvent *)feedCalendars;
        
        titleTextConstruct = [gDataEvent title];
        
        NSString *title = [titleTextConstruct stringValue];
        m_EventData.eventTitle = title;
        m_EventData.eventDescription = [[gDataEvent content] stringValue];
        NSLog(@"EventsTitle:%@", m_EventData.eventTitle);
        // イベントの日時取得
        NSArray *times = [gDataEvent times];
        GDataWhen *when = nil;
        
        if ([times count] > 0) {
            when = [times objectAtIndex:0];
            
            m_EventData.startTime = [[when startTime] date];
            m_EventData.endTime   = [[when   endTime] date];
            // 時間(時、分、秒)が無いとき、終日と判定
            m_EventData.allDay = !([[when startTime] hasTime]) && !([[when endTime] hasTime]);
        }
        
        // イベントの場所取得
        NSArray *location = [gDataEvent locations];
        GDataWhere *where = nil;
        
        if ([location count] > 0) {
            where = [location objectAtIndex:0];
            m_EventData.eventLocation = [where stringValue];
        }
        // 更新日付取得
        m_EventData.updateDate = [[gDataEvent updatedDate] date];
        
        [m_CalendarData setEventData:m_EventData];
    }
    
    // objectをソート
    [m_CalendarData sortEventsByDate];
    
    // 通知を作成する
    NSNotification *notice = [NSNotification notificationWithName:notifyMessage object:self];
    // 通知実行
    [[NSNotificationCenter defaultCenter] postNotification:notice];
    
}

最後に通知を作成しているが、これは「MasterViewController.m」にカレンダーのイベント情報取得が終了したことを通知していて、通知を受け取った「MasterViewController.m」側でテーブル情報の更新を行っている。

NSNotificationを使った通知はどこからでも送ることができて、どのクラスでも受け取ることができる。
とても簡単なのですごい便利。

GoogleCalendarへのアクセス方法はこんな感じ。
慣れればそんなに難しくないけど、分からないことは英語でしか情報が無いことが多いので調べ物は難しい。