[iOS] Local Notification(지역알림, 내부통지). APNS와 비교

2011/03/22 17:19
이 글은 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)  
저작자 표시 비영리 동일 조건 변경 허락

iOS , , , , , , , , , , , , , ,

  1. 좋은 글 감사합니다. ;)

  2. 모르는 영역이지만 좋은 정보라는 것을 알 수 있군요.
    이렇게 정리하면서 자신의 시간을 투자한다는 것은 쉬운 일이 아니죠.

    글을 읽으면서 항상 느끼는 것이지만,
    좋은 정보를 공개하는 당신은 최고입니다. ^^

  3. 별말씀을... 정보공개는 진우님도 하시면서 ^^
    저도 항상 많이 배워갑니다.

  4. Blog Icon
    nury_dev

    좋은글 감사합니다. 한가지 여쭈워 볼게 있는데요. 예제로 해주신 부분은 시간으로 되어 있는데요 Local Notification을 이용할 때, 시간이 아닌 GPS도 가능한가 해서 질문드립니다.
    서울 버스같은 어플을 보면 지정한 버스정류장 근처에 오면 울리는 그런 기능이 있던데요.
    Local Notification에 GPS위치를 등록해 놓고 해당 위치에 도착하면 알려주는 그런 기능이
    가능한지요^^. 좋은 글에 귀찮게 시리 질문 올려서 죄송합니다.

  5. 아~ 글쎄요. 그것까지는 잘 모르겠어요. 연구해볼만하겠어요 ^^

  6. 알람 어플 제작중에 검색하다가 지돌스타님 블로그까지 찾아왔네요.
    친절한 정리 감사드립니다. ^^

  7. Blog Icon
    블로

    좋은글 감사합니다~ 좀 퍼갈께요~

  8. 퍼가지는 마시고 간단한 요약문과 함께 링크를 걸어주시는게 네티켓입니당 ^^

  9. Blog Icon
    달쿠

    감사합니다 ^^ 꼭 필요한 정보였는데, 이런 깔끔한 설명이라니~

  10. 아 정말 좋은 글이네요!!!
    지금 구현할려고 코딩하다가.... 검색했는데
    너무나 잘 나와있어서~ 순조롭게 구현될 수 있을 듯 하네요!
    감사합니다 ^^

  11. Blog Icon
    라돌

    좋은 자료 정말 감사합니다 !!

    구현하려는 부분 자료도 없고 너무 이해가 안가서 힘들었는데 덕분에

    일이 잘 풀렸습니다!!

    수고하세요 ~~~

  12. 질문이 하나 있습니다
    local notification으로 작업을하면 아이폰의 설정 -알림 화면에서
    알림설정[사운드,뱃지,경고] 를 할수가 없는데요[ 아예 화면에 나오지 않네요..ㅠ.ㅠ]
    이건 APNS를 사용하지 않는이상 설정할수 없는것인가요?

    구글링을 통해 알람기능을 on/off 했는지를 알아내는 코드를 찾긴했습니다만
    UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
    int IsAlert = 1 ;
    if (types == UIRemoteNotificationTypeNone)
    IsAlert = 0;
    NSLog(@"-------------ALRAM-- On/Off------------ %d ", IsAlert );

    아이폰 - 설정 - 알림 에 가도 제가 만든 app은 아예 설정하는 곳에 나타나질 않으니 테스트 할수도 없네요.... ㅠ.ㅠ
    알림 자체를 on/off 해봐도 IsAlert = 0 만 나오네요..

    질문내용을 요약하면요
    1. local notification으로 작업을하면 아이폰의 설정 -알림 화면에서 알람 on/off 를 사용 못하나요?
    2. 혹시 전체 알람의 on/off 여부를 알수 있는 방법이 있을까요?

  13. APNS와 Local Notification은 다른 영역입니다. 그점을 참고하시면 답이 나올듯하네요. ^^

  14. 좋은 정보 감사드립니다. 많은 도움이 되었습니다.

  15. Blog Icon
    얼렁뚱당

    좋은글 감사합니다 링크걸어놓고 자주 봐야겠네요

  16. Blog Icon
    홍승현

    정말 유용한 정보 감사합니다. ^^ 덕분에 개념이 잘 잡혔네요

  17. Blog Icon
    iOS Developer

    좋은 자료 감사합니다!!!!!!!

  18. Blog Icon
    연주아범

    푸시 서비스 관련해서 정보를 찾아보다 이렇게 문의하게 되었습니다.

    모바일 웹을 폰갭을 이용해 앱으로 만들어서 사용중인데요,
    앱 실행시 동작하는 웹에서 디바이스로 직접 푸시를 할 수 없는지,(따로 서버를 두지 않고)
    궁금합니다. 혹시 방법이 있을까요??

  19. 없습니다. 정확하게는 실행중일때 빼놓고는 방법이 없습니다. APNS를 사용하셔야 합니다.

  20. Blog Icon
    앱좋아

    잘 보고 갑니다 감사합니다.....

  21. 좋은 글 감사합니다. 송구스럽지만 한가지 질문이 하나 있습니다. 로컬 푸쉬에 제한 개수에 대해서 혹시 알고 계신가요? 로컬 푸쉬를 300개 이상 설정하면 문제가 있는 것 같은데 맞나요?
    그리고 보통 앱들을 보면 푸쉬 알림에 대한 승인을 받던데 그것도 따로 구현하는 방법이 있나요?

  22. 갯수제한은 금시초문입니다. 그런게 있군요.
    로컬푸시는 APNS와 다릅니다. 로컬푸시는 따로 승인절차가 없습니다.

  23. 답변 감사합니다.^^

  24. Blog Icon
    감사합니다

    정보 감사합니다...
    죄송한대요ㅠㅠ
    혹시 카카오톡처럼 알림이 오는 걸 어떻게 구현하는 건지 가르쳐주실수 있으세요?ㅠㅠ
    앱개발 초짜라ㅜㅜㅜㅜ

  25. Blog Icon
    몽키

    remote APNS 를 이용하면 됩니다.

  26. Blog Icon
    장지연

    혹시 로컬 노티피케이션에서 알람처럼 매일매일 같은시간에 시간 설정 하는 방법이 있나요??

  27. 매일 같은 시간은 완벽하게 못하고요. 한꺼번에 날자별로 다 등록하는 방법밖에 없을겁니다.