이 글은 iOS에서 Local Notification에 대한 전반적인 이해를 돕기위한 글이다. 그래서 유사형태인 APNS와 비교해보기도 했다. 검색해보면 Local Notification에 대한 문의는 있어도 이에 대해서 설명된 한글문서가 없는 것 같아 정리해보았다.

Local Notification에 대해
iOS 4.0 이상부터 Local Notification(지역알림, 내부통지, http://goo.gl/jFFsT)을 지원한다.  그러므로  iOS 4.0 미만 버전을 지원하는 어플의 경우 호환성을 유지할 수 있도록 개발해야할 것이다.

Local Notification은 어플이 실행중이 아니거나 Background, Foreground 상태에 관계없이 지정된 날짜와 시간에 필요한 최소한의 데이터를 전송하여 어플에게 전달해 실행하거나 다른 행동을 취할 수 있도록 구현할 수 있다. 심지어 Local Notification을 예약하고 iOS를 재부팅해도 정상적으로 동작한다.  이러한 형태가 가능한 것은 Local Notification 관리는 iOS 자체에서 하기 때문이다. 

Local Notification과 APNS(Apple Push Notification Service, http://goo.gl/fWknl)의 큰 차이점은 Notification을 위한 서버가 필요한가 아닌가의 차이에 있다. APNS는 서버가 준비가 되어 있어야 하고 Push를 위한 인증서도 발급해야한다. 처음 테스트 환경을 만들고 운용하는게 복잡한 편이다. 반면 Local Notification은 이런 절차가 전혀 필요없이 간단하게 코드상에서 처리할 수 있다. 이처럼 Local Notification을 사용하는 방법은 꽤 간단한 편이다. 하지만 APNS에 비해서 테스트하기가 좀 까다로운 면이 있다. 왜냐하면 Local Notification은 시간기반으로 하는 통지가 되는 형태이기 때문에 통지에 대한 제어권이 iOS에 있으며 개발자에게 있다고 볼 수 없기 때문이다. 반면에 APNS는 서버측에서 어떤 시간에 상관없이 개발자가 원하는데로 바로 통지를 할 수 있다. 

Local Notification와 APNS가 이처럼 차이점이 있지만 넘겨주는 데이터나 동작하는 방식은 거의 유사한 편이다.  그래서 어플내에서 동작하는 형태를 하나의 인터페이스로 만들어 운영할 수 있다. 이것이 가능한 이유는 둘다 PayLoad(http://goo.gl/mulVQ)가 유사한 형태를 가지며 통지되었을때 같은 동작을 하기 때문이다. (PayLoad는 일종의 메시지 데이터를 보유하는 패킷이나 프레임의 부분을 말한다.) PayLoad에는 Notification Type과 Custom Data를 담는다. Notification Type은 메시지 ,버튼 제목, 아이콘뱃지숫자, 사운드등으로 구성되어 있고 Custom Data에는 이외에 데이터가 필요한 경우  Dictionary형태로 구성된다. 하지만 APNS와 Location Notification간에 PayLoad데이터 관리의 차이는 있다. APNS는 Dictionary로 관리되며, Location Notification은 UILocalNotification 클래스(http://goo.gl/3TyTg)로 관리 된다. 

Local Notification은 APNS와 다르게 시간기반으로 운용된다. 이것은 iOS에서 스케쥴링을 해준다는 말과 같다. 그래서 통지가 일어나야하는 날짜와 시간을 정해줘야한다. 

Local Notification 사용법 
지금까지  Local Notification을 설명하면서 APNS와의 차이점도 알아보았다. 이러한 내용을 미리 언급하는 것은 처음 이를 접근할 때 Local Notification에 대한 전반적인 이해가 필요하기 때문이다. 여러가지로 복잡하고 잘 이해가 안되겠지만 실제로 해보면 이보다 쉬울 순 없다. 

Local Notification을 학습하기 위해서  Apple문서를 먼저 참고하는 것이 좋겠다.
 - About Local Notifications and Push Notifications : http://goo.gl/jFFsT

그럼 간단하게 Local Notification을 사용하는 방법을 알아보자. 크게 등록과 처리하는 방법을 구분해서 정리했다.

1. Local Notification 등록하기

Xcode상에서 Window Based 어플 프로젝트를 생성한뒤 AppDeleage 소스코드내에 application:didFinishLaunchingwithOptions: 메시지에 다음 코드를 넣는다.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    

    // Override point for customization after application launch.

    

    [self.window makeKeyAndVisible];


    //통지시간 정하기 

NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];

NSDateComponents *dateComps = [[NSDateComponents alloc] init];

[dateComps setYear:2011];

[dateComps setMonth:3];

[dateComps setDay:22];

[dateComps setHour:15];

[dateComps setMinute:30];

[dateComps setSecond:0];

NSDate *date = [calendar dateFromComponents:dateComps];

[dateComps release];

UILocalNotification *localNotif = [[UILocalNotification alloc]init];

if (localNotif != nil

{

//통지시간 

localNotif.fireDate = date;

localNotif.timeZone = [NSTimeZone defaultTimeZone];

//Payload

localNotif.alertBody = [NSString stringWithFormat:@"내부통지 %@",date];

localNotif.alertAction = @"상세보기";

localNotif.soundName = UILocalNotificationDefaultSoundName;

localNotif.applicationIconBadgeNumber = 1;

//Custom Data

NSDictionary *infoDict = [NSDictionary dictionaryWithObject:@"mypage" forKey:@"page"];

localNotif.userInfo = infoDict;

//Local Notification 등록

[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];

}

[localNotif release];

    return YES;

}


이게 끝이다. Local Notification을 등록하는 시점은 어디라도 상관없다. 필요할 때 등록하면 된다. UILocalNotification 객체를 생성하고 통지시간, Payload, Custom Data를 설정한뒤 등록하면 지정된 시간에 통지가 발생할 것이다. APNS럼 APNS 서버에 DeviceToken을 받는 과정이 모두 생략되기 때문에 등록절차는 매우 쉬운 것을 알 수 있다. 

이 코드에서 Local Notification 등록을 scheduleLocalNotification을 사용했다. 필요한 경우에 스케쥴링 필요없이 즉각적으로 Local Notification을 줄 필요가 있는 경우에는 다음 메시지를 사용하면 되겠다. 

[[UIApplication sharedApplication] presentLocalNotificationNow:localNotif];


만약 fireDate를 현재시간보다 이전시간으로 등록하면 iOS는 바로 통지해버린다. 이 말이 그냥 쉽게 넘어갈 수 있는 문제인데 경험상 현재시간보다 이전시간으로 가는 경우는 없기 때문에 왠만하면 이전시간으로 등록하는 경우가 없도록 코딩을 해야 버그를 유발시키지 않을 것이다.

만약 이전에 등록된 Local Notification을 삭제하고 싶은 경우가 발생할 수 있다. 그런 경우에는 다음 메시지 중에 하나를 사용하면 되겠다.

[[UIApplication sharedApplication] cancelAllLocalNotifications];

[[UIApplication sharedApplication] cancelLocalNotification:localNotif];




2. Local Notification 처리하기 
앞서 Local Notification을 등록하는 방법을 알았다. 등록된 통지는 iOS에서 스케쥴링해준다.  어플의 실행여부, 및 iOS재부팅에 전혀 상관없이 동작하기 때문에 개발자는 이런부분에 대해 별다른 노력없이 통지 처리에 대한 로직만 만들면 된다.

내부 통지는 다음 3가지 형태로 처리가 가능하다. 이는 APNS와 유사하다.

[경우 1] 어플이 실행중이지 않은 경우 
이 경우에 iOS에 등록된 통지를 정해진 시간에 발생하면 자동으로 Alert창을 띄워준다. 거기에는 UILocalNotification에 Payload로 등록한 alertBody, alertAction이 반영되어 있으며 주어진 사운드를 들려준다. 어플의 아이콘에도 정해진 badge숫자가 표시된다. 


위의 경우 특별히 AppDelegate에서 application:didFinishLaunchingWithOptions: 메세지 내에서 통지된 UILocalNotification객체를 참고할 수 있다. Local Notification을 통해 어플이 실행되는 경우 별다른 작업이 필요하다면 이를 이용하면 유용할 것이다. 접근방법은 간단한다. 아래처럼 접근해서 사용하면 되겠다.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    

    // Override point for customization after application launch.

    

    [self.window makeKeyAndVisible];

UILocalNotification *notif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];

if (notif != nil

{

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"알림" 

message:[NSString stringWithFormat:@"didFinishLaunchingWithOptions %@",notif.alertBody

  delegate:nil 

  cancelButtonTitle:nil 

  otherButtonTitles:@"확인",nil];

[alert show];

[alert release];

}

    return YES;

}


이 경우 다음과 같은 화면을 볼 수 있을 것이다. 



또한 AppDelegate 상에 application:didReceiveLocalNotification: 메시지를 구현하면 Local Notification을 처리할 수 있다. 이 메시지는 다음에 나오는 [경우2], [경우3]에도 동일하게 동작한다. 아래처럼 구현해보자.

-(void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification

{

application.applicationIconBadgeNumber = 0;

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"알림" 

message:[NSString stringWithFormat:@"didReceiveLocalNotification %@",notification.alertBody

  delegate:nil 

  cancelButtonTitle:nil 

  otherButtonTitles:@"확인",nil];

[alert show];

[alert release];

}


다음은 위코드가 실행될 때 화면이다.



[경우2]어플이 실행중이나 background에 위치해 있는 경우 
[경우1]과의 유일한 차이점은 application:didFinishLaunchingWithOptions: 를 통해 UILocalNotification 객체정보를 얻을 수 없다는 것이다. 이 경우에는 이미 어플이 실행중이기 때문에 어플이 처음 실행할때 최초 한번만 호출되는 AppDeleage의 application:didReceiveLocalNotification:가 실행될 수 없기 때문이다. 이 의미는 application:didFinishLaunchingWithOptions: 와 application:didReceiveLocalNotification: 에서 얻어지는 UILocalNotification 객체정보가 같더라도 서로 다른 일을 할 수 있도록 한다는 점을 시사한다.  

application:didReceiveLocalNotification: 메시지는 여전히 호출되므로 이때 UILocalNotification 객체를 처리하면 되겠다.


[경우3]어플이 실행중이며 foreground에 위치해 있는 경우
마지막으로 어플이 화면위에 실행중인 경우이다. 이때도 [경우1], [경우2]와 차이점은 iOS에서 직접적으로 Alert창을 띄워주지 않는다는 점이다. application:didFinishLaunchingWithOptions: 는 당연히 호출되지 않으며 application:didReceiveLocalNotification:  만 호출된다. 


Local Notification 처리에 대한 경우 1, 2, 3을 표로 정리하면 다음과 같을 것이다. 
   경고창   didFinishLaunchingWithOptions를 통한 UILocalNotification참고  didReciveLocalNotification메시지를 통해 UILocalNotification 참고
 경우 1 (어플 실행X)  O
 경우 2 (어플 background)  O
 경우 3 (어플 foreground)


지금까지 설명한 내용 대해서 더 자세히 알고 싶다면 다음 문서를 참고한다.
Scheduling, Registering, and Handling Notifications : http://goo.gl/qHVPi


팁(Tip)
Local Notification을 사용하면서 이런 점은 알아둘 필요가 있다. 

1. 등록시 현재 시간보다 빠른 시간을 등록하면 바로 통지가 된다. 이 점은 어플 버그를 유발할 수 있으므로 각별히 주의하길 바란다. 개발 경험상에서 말씀드린다. (여기서 버그는 실제 버그가 아니라 의도하지 않는 동작을 유발시킨다는 말이다.)

2. 테스트를 위해서는 아이폰 자체 시간설정 기능을 적극 활용하면 되겠다. Local Notification의 통지는 iOS가 스케쥴링을 해주기 때문에 개발자가 통제할 수 없다. 그러므로 아이폰 자체 시간설정 기능을 활용해 테스트할 수 있겠다.

3. PayLoad대신 Custom Data를 사용하는 방법은 별도로 설명을 안했지만 UILocalNotification상에 userInfo속성을 활용하면 된다는 점을 설명하지 않아도 여러분은 잘 사용할 수 있을 것이라 생각한다. ^^


정리하며
Local Notification에 대해서 전반적인 내용을 다뤄보았다. 생각보다 개념자체는 간단하지만 어느 경우에 어떻게 사용하고 동작하는지에 대한 명확한 지식이 없으면 오용할 여지는 많다. 또한 잘못 사용하면 뜻하지 않는 동작을 유발할 수 있기 때문에 등록시 시간을 잘 설정해야하는 것은 꼭 염두해야 한다. 또한 클라이언트 베이스로 등록/처리를 해야하는 부분은 이에 대한 적절한 설계를 바탕으로 하지 않으면 로직이 복잡해져 관리가 어려워질 수 있다는 점도 개인적인 경험이다. 

아무튼 회사에서 이를 이용한 관련 어플을 만들면서 처음 사용해 봤는데 자세히 알지 않고 사용하면 문제가 될 것 같아 정리를 해보았다.


관련글
About Local Notifications and Push Notifications : http://goo.gl/jFFsT
The Notification Payload : http://goo.gl/mulVQ
UILocalNotification 클래스 : http://goo.gl/3TyTg
Scheduling, Registering, and Handling Notifications : http://goo.gl/qHVPi
내가 만든 어플에 Push Notification 적용하기 : http://goo.gl/kH7BQ 
APNS 개발버전과 배포버전의 차이점. : http://blog.jidolstar.com/726
APNS Device Token을 못받아올때 : http://blog.jidolstar.com/725
 
글쓴이 : 지돌스타(http://blog.jidolstar.com/758)  

+ Recent posts