[iOS] 로컬 알림 (Local Notifications)

iOS는 로컬 알림(Local Notifications)과 푸쉬 알림(Push Notifications – Remote Notifications 라고도 함) 방법을 제공하여 앱이 Foreground (iOS App State 참고) 에서 실행 중이 아닐 때에도 사용자에게 정보가 전달되도록 한다.

두 가지 알림 방법 중 Local Notification에 대해 이번 포스팅에서 정리한다. iOS Developer Library  -글 하단 Reference 링크 참고 – 에 알람 등록/처리 등 관련 내용이 잘 설명되어져 있다. 그러나 문서 내용 중에는 본인을 헷갈리게 한 부분도 있다. 그 부분도 같이 정리한다.

Local Notifications

사용자 측면에선 본인에게 온 알림이 로컬 알림인지 푸쉬 알림인지 구별하기 어렵다. 즉, 두 가지 알림 방법이 사용자에게 보여지는 경험은 거의 동일하다.

로컬 알림과 푸쉬 알림의 차이는 개발에 있다. 푸쉬 알림은 별도의 서버에서 모바일 디바이스로 알림을 전송한다. 반면 로컬 알림은 모바일 디바이스의 앱이 알림을 등록하고 iOS가 이를 전달한다.

로컬 알림은 iOS 4 이후 부터 지원하며 Mac OS X에서는 지원하지 않는다. (푸쉬 알림은 iOS, Mac OS X 모두 지원한다.)

로컬 알림은 시간 기반(time-based) 특성이 강하다. 즉, 사용자에게 전달하고자 하는 메시지와 메시지를 전송하는 시간이 기본이 된다.

등록된 알림은 앱이 Foreground에서 실행되는 경우엔 표시되지 않는다. 그러나 화면에 알림이 나타나지만 않을 뿐 코드상에서 처리할 수 있다. (추가적인 내용은 아래에서 다룸)

Local Notification 등록

로컬 알림은  UILocalNotification 과 UIApplication을 사용한다.

UILocalNotification의 속성은 크게 3가지로 분류한다.

  • Scheduled time : 알람 발생 시각. 주기를 정하여 반복 설정 가능. 타임존 설정 가능.
  • Notification type : 알림 메시지, 액션 버튼 타이틀, 뱃지 아이콘, 알림 사운드.
  • Custom data : 알림 처리 로직에서 사용할 수 있는 사용자 정보.

로컬 알림을 등록하는 위치나 시점에 대해서는 특별한 제약은 없다. 앱이 백그라운드로 진입 시 또는 사용자가 특정 버튼을 눌렀을 때 등 대부분 가능하다. 다음은 로컬 알림을 등록하는 샘플 코드이다.

// 알림 등록 메소드
-(void)fireLocalNotification{

    // UILocalNotification 객체 생성
    UILocalNotification *noti = [[UILocalNotification alloc]init];

    // 알람 발생 시각 설정. 5초후로 설정. NSDate 타입.
    noti.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];

    // timeZone 설정.
    noti.timeZone = [NSTimeZone systemTimeZone];

    // 알림 메시지 설정
    noti.alertBody = @"Just Do It";

    // 알림 액션 설정
    noti.alertAction = @"GOGO";

    // 아이콘 뱃지 넘버 설정. 임의로 1 입력
    noti.applicationIconBadgeNumber = 1;

    // 알림 사운드 설정. 자체 제작 사운드도 가능. (if nil = no sound)
    noti.soundName = UILocalNotificationDefaultSoundName;

    // 임의의 사용자 정보 설정. 알림 화면엔 나타나지 않음
    noti.userInfo = [NSDictionary dictionaryWithObject:@"My User Info" forKey:@"User Info"];

    // UIApplication을 이용하여 알림을 등록.
    [[UIApplication sharedApplication] scheduleLocalNotification:noti];
}

등록 코드는 간단하다. UILocalNotification 객체를 생성하여 각 속성에 적당한 값을 넣고 UIApplication을 이용하여 알림을 등록하면 된다.

timeZone의 경우 systemTimezone을 설정하였다. systemTimeZone은 디바이스에 설정된 시각대를 말하며 defaultTimeZone은 개발자가 직접 설정해서 사용할 수 있는 시각대를 의미한다. 예를 들어 해외 여행을 하는 경우, 아이폰의 변경된 시각대를 적용하려면 systemTimeZone을 쓰면 된다. (참고 : Difference among time zone convenience methods).

UIApplication의 scheduleLocalNotification: 메소드 외에 presentLocalNotificationNow: 메소드로 알림을 등록할 수 있다. 이 메소드는 UILocalNotification의 fireDate는 무시하고 앱에 바로 알림이 전달되도록 한다.

UIApplication의 scheduledLocalNotifications 속성을 이용하여 한 번에 여러 UILocalNotification을 등록할 수도 있다. 이 속성은 iOS 4.2버전 이전에는 read-only 였으나 setter 메소드가 추가되어 NSArray타입으로 한 번에 등록할 수 있다. 이 속성이 설정되면 이전의 로컬 알림은 다 취소되므로 사용에 주의해야 한다.

Local Notification 알림 메시지 타입

본인이 헷갈렸던 부분 중 하나다. 알림 등록 시 설정하는 UILocalNotification 속성값과 이 값들이 실제로 화면에 보여지는 모습에 대해 알아보자.

우선 위 코드를 iOS Simulator에서 동작시키면 아래 그림과 같이 배너 형태로 나타난다. (본인의 개발환경은 Xcode 4.5.2, iOS 6). 참고로 본인은 버튼의 클릭 이벤트에 위 코드를 실행시켰으며 5초가 되기 전에 홈버튼을 눌러 앱을 백그라운드 상태로 만들었다. 앱이 전면에서 실행 중이면 알림이 표시되지 않는다.

Local Notification Test in Simulator

iPhone을 써본 사용자라면 알림은 배너와 알림창 타입이 있다는 것은 알고 있을 것이다. 그렇다면 이것은 어디서 결정되어지는 것일까? iOS Developer Library에서는 푸쉬 알림 설명 부분에서만 “설정앱 → 알림”에서 이를 설정할 수 있다고 언급하고 있다.

그러나 실제로 로컬 알림도 설정앱에서 알림 스타일 설정이 가능하다. 아이폰에 연결시켜 코드를 실행하고 설정앱을 확인해 보면 알림 스타일이 ‘배너’로 설정되어 있음이 확인된다. iOS Simulator의 설정앱에는 알림 설정 부분이 없다. iOS Simulator에 배너 스타일로 알림이 오는 것을 보면 현 iOS 버전에서는 배너가 기본 스타일인 것 같다.

alertAction은 알림이 알림창 타입인 경우 버튼 ‘View’를 대체 – 알림창엔 ‘Cancel’과 ‘View’ 버튼이 있다 – 하는 문자열을 나타낸다. 디바이스가 잠겨 있는 경우에는 잠금 해제에 나타나는 메시지를 의미한다.  (nil이 설정되면 디폴트 값이 적용됨)

아래는 위에서 등록한 알림이 잠금 상태에서 왔을 때의 모습이다. alertAction에 설정한 “GoGo”가 어떻게 적용되는지 확인된다. 설정앱을 통해 알림스타일을 알림창으로 변경해도 디바이스 잠금상태에서는 아래와 같이 표시된다.

Local Notification test in Simulator when device locked

알림 효과음은 soundName으로 설정하며 직접 제작한 사운드도 설정할 수 있다. nil을 설정하면 소리가 나지 않는다 .

iOS Developer Library를 보면 아래 그림과 같이 버튼이 하나인 알림창을 띄울 수 있다고 설명되어져 있다.

< from iOS developer library >

그러나 UILocalNotification 속성 중  hasAction = NO, alertAction = nil 설정을 하여도 위와 같은 효과를 얻을 수 없었다. 푸쉬 알림에서는 어떨지 모르겠으나 로컬 알림에서는 기본적으로 버튼 하나의 알림창은 지원하지 않는 듯 하다.

UILocalNotification의 applicationIconBadgeNumber을 설정한다고 해서 앱 우측 상단에 숫자가 표시되는 것은 아니다. 실제로 앱의 뱃지 아이콘 숫자는 UIApplication의 applicationIconBadgeNumber에 의해 결정된다. 로컬 알림 등록시에 설정한 UILocalNotification의 applicationIconBadgeNumber는 알림 처리부에서 UIApplication의 applicationIconBadgeNumber를 수정할 때 사용되기도 한다. 설정하지 않아도 상관없다.

할일 앱의 경우 로컬 알림과 상관없이 미완료 항목 숫자에 맞게 직접 UIApplication의 applicationIconBadgeNumber를 설정할 수 있다.

Local Notification 응답

알림을 처리할 때, 다음의 경우를 고려하여야 한다.

  • 앱 미실행 (종료) 상태일 때,
  • 앱 실행 중 (Background 또는 Foreground) 일 때

앱 종료상태에서 알림 액선(알림창의 버튼 or 잠금상태의 잠금 해제)  또는 디바이스의 알림 센터에 보이는 알림을 클릭할 경우, application delegate의 didFinishLaunchingWithOptions: 이 호출된다.

이 메소드는 알림과 무관하게 앱이 종료상태에서 실행될 때에도 호출되는데, 파라미터인 launchOptions를 통해서 알림을 통한 앱 실행인지 구분 가능하다.


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

    // 알림을 통한 진입인지 확인
    UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
    if(localNotif){
        // 알림으로 인해 앱이 실행된 경우라면..
        // localNotif.userInfo 등을 이용하여
        // 알림과 관계된 화면을 보여주는 등의 코드를 진행할 수 있음.
    }
}

앱이 종료 상태이고 UIApplication의 applicationIconBadgeNumber가 설정되어 있을 때, 앱 아이콘을 클릭하여 앱을 샐행시키는 경우는 어떨까? 알림 액션으로부터 실행된 경우와 동일할까?

이 경우엔 알림과 무관하게 실행되는 경우와 동일하다. 즉 위 코드에서 localNotif 는 nil 이다.

앱이 실행 중인 경우는 Background/Foreground와 상관없이 application delegate의 didReceiveLocalNotification: 메소드가 호출된다. 파라미터는 UILocalNotification 타입이다.

Foreground 경우 알림이 화면에 나타나지 않지만, 위 메소드가 실행은 되므로 필요에 맞게 처리해야 한다.

Foreground와 Background 상태일 때 처리하는 로직이 달라야 한다면, UIApplication의 applicationState를 이용하면 구분한다. (Background 경우는 UIApplicationStateBackground가 아닌 UIApplicationStateInactive 로 확인한다.)


// application delegate method
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    if(application.applicationState == UIApplicationStateActive){

        // Foreground에서 알림 수신
    }

    if(application.applicationState == UIApplicationStateInactive){

        // Background에서 알림 액션에 의한 수신
        // notification.userInfo 이용하여 처리
    }
}

Local Notification 취소

UIApplication의 cancelAllLocalNotifications 메소드와 cancelLocalNotification: 메소드를 이용하면 로컬 알림을 취소할 수 있다.

로컬 알림은 전달 예정 중인 알림과 이미 전달된 알림으로 나눌 수 있다.

전달된 알림은 위에서 설명한 application delegate 메소드에 의해 처리된 후, 취소를 하지 않으면 아이폰의 알림 센터에 그대로 보여지게 된다.

알림 확인 즉시 확인된 알림이 알림센터에서 보여지지 않게 하기 위해서는, application delegate 메소드의 파라미터로 전달된 UILocalNotification 객체를 이용하여 cancelLocalNotification: 를 호출한다.

아직 전달되지 않은 로컬 알림을 취소할 때도 동일한 메소드를 사용한다. 이 경우에는 등록한 UILocalNotification 객체를 어딘가에 저장시켜  필요 시점에 사용할 수 있어야 취소가 가능하다.

cancelAllLocalNotification 메소드는 인자가  없다. 이 메소드는 알림 센터에 보이거나 또는 앞으로 전달 예정인 로컬 알림 모두를 취소 시키므로 사용에 주의해야 한다.

그 밖에

iOS 디바이스는 알림을 최신 64개 알림으로 제한한다.  iOS는 이를 초과하는 알림은 폐기한다. 또한 설정앱에서 확인해보면 각 앱마다 알림 센터에서 보여지는 알림은 기본 5개, 최대 10개로만 설정 가능하다. 알림이 남발하지 않도록 알림 메시지 디자인에 신경 쓸 필요가 있다.

로컬알림을 학습하며 이런 저런 경우를 테스트해보니, iOS에서 알림 관련 API가 상대적으로 부족한 느낌이 들었다. 개발자가 제어할 수 있는 부분이 좀 더 많았으면 한다.

특히 알림센터 활용에 대한 부분이 아쉬웠다. 실제 알림(배너, 메시지) 없이 알림 센터에 표시만 할 수 있다던가, 아니면 알림 센터에 남아있는 알림 리스트를 받아 온다던가, 아니면 사용자가 알림센터에서 알림을 클리어 하는 이벤트를 처리할 수 있다던가 하는 기능들이 추가된다면 알림센터를 더 잘 활용할 수 있지 않을까 싶다.

* Reference :

Advertisements
Leave a comment

8 Comments

  1. 두근두근

     /  August 5, 2014

    되게 잘 정리 하셨네요
    많이 배우고 갑니다 ^^

    Reply
  2. Hello~

     /  January 30, 2015

    도움 많이 받았어요!^^

    Reply
  3. bawoking

     /  September 22, 2015

    도움되었습니다. 감사…

    그런데… 기기능 재부팅하면 등록한 노티가 발생하지 않는데.. 이런 경우는 어떻게 하나요.??

    Reply
    • 제가 확인한 바로는 기기 재부팅, OS 업데이트시에도 등록한 로컬 알림이 발생합니다. 좀 더 자세하게 알려주시면 도움드릴 수 있을 것 같습니다.

      Reply
    • bawoking

       /  September 22, 2015

      답변 감사드립니다. 이제 시작한지 두어달되는 초보라서요 ㅜㅜ 좀더 확인해 보고.. 도움필요하면 부탁드릴게요… 다시한번 감사합니다. ^^; 좋은 하루 보내세요…

      Reply
      • 참고로 등록된 로컬 알림 확인은 [UIApplication sharedApplication].scheduledLocalNotifications 를 통해 확인 가능합니다. 재부팅 후에 저 메소드를 통해서 확인할 수 있습니다.

  1. [iOS] 로컬 알림 취소 – UILocalNotification 저장 및 취소 « Park's Park

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: