2014년 3월 7일 금요일

[iOS7] Background Fetch in iOS7

오늘 정리할 내용은, Background Fetch에 대한 것입니다.
이 기능은 iOS7에서 추가 되었고, Background Fetch 는 앱이 백그라운드에 있을 때, 간헐 적으로 iOS에서 호출해서, 앱이 실행 될 수 있도록 해주는 것입니다.

그럼 얼마나 자주 호출이 될까요?

- iOS의 문서에는 "the system uses available information to determine the best time to launch or wake apps. For example, it does so when networking conditions are good or when the device is already awake. "라고 되어 있습니다.
- iPhone 5s에서 테스트를 해보니, 대략 8~10분 정도에서 호출이 되기도 하고,
- 8~10분 정도 지난 후에 파워 키로 화면을 켜고, 패스워드를 입력해서, Main화면이 표시되면, Background Fetch가 호출 되기도 합니다.
- 일정한 시간으로 주기적으로 호출되지 않습니다. 간헐적으로 시스템에서 지금이 최적이다라고 생각하는 시간, 즉 배터리를 사용하기 좋은 시간이라고 생각할 때 호출이 됩니다.

호출 된 후에 얼마나 계속 실행이 될까요?

실행 될 때,  completionHandler를 파라미터로 받습니다.
모든 패치를 끝내면, 이 함수를 호출 해서, Fetch가 끝났음을 시스템에 알려줘야 합니다.
약 30초 안에, 모든 패치를 끝내고, handler를 호출해줘야 합니다. 만약 호출하지 않거나, 시간이 많이 걸리다던지 하는 것에 의해서, 다음 Fetch가 언제 호출 될지 영향을 받는 것 같습니다.
 간단하게 끝날 것 같으면, NSURLRequest를 사용하고, 시간이 걸리면, NSURLSession을 사용하라고 권고하고 있습니다.

Background Fetch를 사용하려면?


1. App에 Background Mode에 설정을 추가합니다.
- Helloworld-Info.plist 에 "Required background modes"항목을 추가하고, Item으로 "App downloads content from the network"를 추가하면 된다.

- 다른 방법으로 Project의 Capability에서 Background Mode를 On하고 background fetch를 체크합니다.

2. 앱이 시작될 때, 시스템에 background fetch시간을 설정합니다.
- 일정 간격을 설정할 수는 없고, Minimum과 Never를 선택할 수 있습니다.
source code
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    
    //Background Fetch 초기화 함. 가장 짧은 주기로 설정함.
    [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

    return YES;
}

3. Fetch가 실행되는 시간을 알아보기 위해서, Background로 들어갈 때와, Fetch가 실행될 때, Local Notification을 보내도록 합니다.
source code
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    UILocalNotification *noti = [[UILocalNotification alloc] init];
    if(noti)
    {
        noti.repeatInterval = 0.0f;
        noti.alertBody = [NSString stringWithFormat:@"Backgournd:%@", [NSDate date]];
        NSLog(@"%@", noti.alertBody);
        [[UIApplication sharedApplication] presentLocalNotificationNow:noti];
    }
    [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
}

4. Fetch가 호출 되면, 웹사이트에 접속합니다.
source code
#pragma mark - Background Fetch
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSLog(@"Received Background Fetch");
    //데이터를 받아오거나 호출할 URL
    NSURL *url = [NSURL URLWithString:@"http://hidavidbae.blogspot.kr"];
    
    //URL객체가 잘 만들어졌을 경우
    if (url != nil) {
        // URL로 호출할 때 사용할 request객체임.
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        //데이터 로드 실패 시 주소를 받아올 에러 포인터
        NSError *error = nil;
        //해당 URL의 데이터를 가져옴
        NSData *data = [NSURLConnection sendSynchronousRequest:request
                                             returningResponse:nil error:&error];
        //데이터가 로딩이 되었을 경우
        if (data != nil) {
            //사용자에게 notification을 보냄.
            UILocalNotification *noti = [[UILocalNotification alloc] init];
            if(noti)
            {
                noti.repeatInterval = 0.0f;
                noti.alertBody = [NSString stringWithFormat:@"Fetch Success:(%d):%@",
                                  (int)data.length, [NSDate date]];
                [[UIApplication sharedApplication] presentLocalNotificationNow:noti];
            }            
            //성공했음을 알림
            completionHandler(UIBackgroundFetchResultNewData);
        }else{
            //에러를 로그로 찍음.
            NSLog(@"%@", error);
            //실패했음을 알림.
            completionHandler(UIBackgroundFetchResultFailed);
        }
    }else{
        //실패했음을 알림.
        completionHandler(UIBackgroundFetchResultFailed);
    }
}


실제 동작은 어떻게 될까요?


- Simulator에서 동작하는지 먼저 테스트를 할 수 있습니다.
 시뮬레이터에 앱을 설치해서 동작시키고, Home키로 앱을 Background로 보냅니다.
 이후, Xcode의 debug > Simulate background fetch 를 선택해서 동작을 바로바로 테스트해 볼 수 있습니다.

- 실제 iPhone 5s 디바이스에서는 아래와 같이, 8~10분 쯤에, 아이폰을 켜고, 비밀번호 력후 Main화면에 들어가면, Fetch가 실행이 되었습니다.
 이렇게 몇번 화면이 동작하고 Fetch된 이후 약 8분 정도에 자동으로 Fetch도 된 경우가 있었습니다.
 그리고는 2~3시간 후, 한번, 그리고 1시간 후 한번 정도 실행이 되었습니다.
 특별하게 화면이 꺼져 있는데, 동작한 적은 없는것 같고, 내가 화면을 켜고, Home화면에 들어가면, 위치 정보를 읽고 있음이 화면에 표시되고, Fetch가 실행되는 것으로 보입니다.


마치며..


- Fetch는 언제 일어날까요? 
  - 사용자가 iPhone을 어떤 형태로 사용하는 가에 따라서 달라지는 것 같습니다.
  - 밤에는 Fetch를 하지 않고, 낮에 사용자가 자주 iPhone을 켜면, Fetch도 일어나는 것 같습니다.

- Fetch는 사용자의 편의를 위해서 만들어졌습니다.
   패치가 필요한 이유는 사용자가 iPhone을 켜고, 앱을 실행하기 전에, 데이터가 딱!!! 들어와 있기를 위해서 만들어진 것입니다.
  즉, 필요 없는 시간, 혹은 사용자가 많이 안쓰는 앱에 대해서 불 필요하게 자주 Fetch를 하지 않습니다.
 그리고, 패치하는데 시간이 오래 걸리거나, 응답이 잘 없는 앱에 대해서는 Fetch 스케쥴을 뒤로 미뤄버리는 것 같습니다.

- 어떻게 사용하면 좋을까요?
  실시간은 아니지만, 사용자가 앱을 실행하기 전에, 데이터가 미리 다운로드 받으면, 사용자가 편리하게 이용할 수 있도록 장치를 마련해 놓는 용도로 사용하면 되겠습니다.

[소스코드]

https://github.com/davidbae/iOS7-background-fetch

[추가 분석 자료]

3월 9일 새벽부터, 오후 9시쯤 까지 Fetch가 실행 된 시간을 분석해 보았습니다.
제 iPhone 5s에서는 오전 3시~ 오후1시까지 9시간 동안은 Fetch가 진행이 되지 않았고, 그외의 시간에는 약 8~20분 사이를 오락가락 하며 Background Fetch가 실행이 된 것을 볼 수 있습니다.
 아마도 제가 오후에 iPhone을 많이 사용해서, 점심먹고부터 Fetch가 주기적으로 실행이 되는 것 같습니다.

 2014-03-09 01:42:47 (Background Fetch Start)
 2014-03-09 01:43:12 (00:00:25)
 2014-03-09 01:43:42 (00:00:29)
 2014-03-09 01:44:11 (00:00:29)
 2014-03-09 01:54:26 (00:10:14)
 2014-03-09 02:16:57 (00:22:31)
 2014-03-09 02:39:17 (00:22:20)
 2014-03-09 02:49:21 (00:10:04)
 2014-03-09 03:01:36 (00:12:14)
 2014-03-09 03:31:21 (00:29:44)
 2014-03-09 13:09:56 (09:38:34
      ==>오전에는 한번도 실행이 안되었습니다.
      ==>제가 오전에 사용을 잘 안해서 그런지, 아니면, 중간에 내가 앱을 종료했는지 잘 모르겠네요.
      ==> 며칠 더 자료를 모아보면 알 수 있을 것 같습니다.
 2014-03-09 13:19:40 (00:09:44)
 2014-03-09 13:30:16 (00:10:35)
 2014-03-09 13:40:01 (00:09:45)
 2014-03-09 13:49:46 (00:09:45)
 2014-03-09 13:58:52 (00:09:05)
 2014-03-09 14:07:52 (00:09:00)
 2014-03-09 14:21:36 (00:13:43)
 2014-03-09 14:29:17 (00:07:41)
 2014-03-09 14:30:02 (Background Fetch Start)
 2014-03-09 14:30:22 (Background Fetch Start)
 2014-03-09 14:54:38 (00:24:16)
 2014-03-09 15:02:17 (00:07:38)
 2014-03-09 15:12:01 (00:09:44)
 2014-03-09 15:26:43 (00:14:42)
 2014-03-09 15:41:27 (00:14:43)
 2014-03-09 15:50:51 (00:09:24)
 2014-03-09 16:02:04 (00:11:12)
 2014-03-09 16:15:32 (00:13:28)
 2014-03-09 16:23:53 (00:08:21)
 2014-03-09 16:36:04 (00:12:11)
 2014-03-09 16:45:46 (00:09:41)
 2014-03-09 16:57:40 (00:11:54)
 2014-03-09 17:05:34 (00:07:54)
 2014-03-09 17:18:53 (00:13:19)
 2014-03-09 17:31:16 (00:12:22)
 2014-03-09 17:41:01 (00:09:44)
 2014-03-09 17:50:46 (00:09:45)
 2014-03-09 18:04:46 (00:13:59)
 2014-03-09 18:15:11 (00:10:24)
 2014-03-09 18:23:30 (00:08:19)
 2014-03-09 18:34:16 (00:10:45)
 2014-03-09 18:45:21 (00:11:04)
 2014-03-09 18:53:31 (00:08:10)
 2014-03-09 19:03:46 (00:10:15)
 2014-03-09 19:13:31 (00:09:44)
 2014-03-09 19:21:03 (00:07:32)
 2014-03-09 19:30:26 (00:09:22)
 2014-03-09 19:45:31 (00:15:05)
 2014-03-09 19:55:39 (00:10:07)
 2014-03-09 20:03:54 (00:08:14)
 2014-03-09 20:13:23 (00:09:29)
 2014-03-09 20:23:06 (00:09:42)
 2014-03-09 20:30:56 (00:07:49)
 2014-03-09 20:50:39 (00:19:42)
 2014-03-09 21:08:18 (00:17:38)
 2014-03-09 21:28:46 (00:13:37)
 2014-03-09 21:38:31 (00:09:45)
 2014-03-09 21:48:16 (00:09:44)
 2014-03-09 22:15:36 (00:27:20)

 2014-03-09 23:10:19 (00:54:43)

아래는 3월 10일 자료 입니다.
 2014-03-10 00:30:58 (01:20:38)
 2014-03-10 04:45:58 (04:15:00
 2014-03-10 12:33:41 (07:47:43) //오후 1시이후, 약10분단위로 실행
  ==> 이것으로 미뤄봐서, iOS7에서는 사용자의 사용 형태에 따라서, Fetch를 적당한 시간에 실행하는 것으로 보입니다.

 2014-03-10 12:45:00 (00:11:18)
 2014-03-10 12:53:26 (00:08:26)
 2014-03-10 13:05:01 (00:11:35)
 2014-03-10 13:14:45 (00:09:44)
 2014-03-10 13:31:21 (00:16:35)
 2014-03-10 13:40:11 (00:08:50)
 2014-03-10 13:55:26 (00:15:14)
 2014-03-10 14:05:11 (00:09:45)
 2014-03-10 14:14:56 (00:09:44)
 2014-03-10 14:27:24 (00:12:28)
 2014-03-10 14:35:57 (00:08:32)
 2014-03-10 14:46:11 (00:10:14)
 2014-03-10 14:55:56 (00:09:45)
 2014-03-10 15:05:27 (00:09:30)
 2014-03-10 15:14:24 (00:08:57)
 2014-03-10 15:22:26 (00:08:01)
 2014-03-10 15:32:12 (00:09:46)
 2014-03-10 15:41:46 (00:09:34)
 2014-03-10 15:51:31 (00:09:44)
 2014-03-10 16:01:16 (00:09:45)
 2014-03-10 16:11:01 (00:09:44)
 2014-03-10 16:22:00 (00:10:59)
 2014-03-10 16:33:16 (00:11:15)
 2014-03-10 16:48:01 (00:14:45)
 2014-03-10 16:57:46 (00:09:44)
 2014-03-10 17:07:31 (00:09:45)
 2014-03-10 17:16:40 (00:09:09)
 2014-03-10 17:26:26 (00:09:45)
 2014-03-10 17:36:11 (00:09:44)
 2014-03-10 17:44:43 (00:08:31)
 2014-03-10 17:54:56 (00:10:13)
 2014-03-10 18:02:50 (00:07:53)
 2014-03-10 18:12:31 (00:09:41)
 2014-03-10 18:22:16 (00:09:44)
 2014-03-10 18:31:23 (00:09:07)
 2014-03-10 18:40:01 (00:08:38)
 2014-03-10 18:51:46 (00:11:44)
 2014-03-10 19:01:30 (00:09:44)
 2014-03-10 19:12:47 (00:11:17)
 2014-03-10 19:20:18 (00:07:30)
 2014-03-10 19:30:20 (00:10:01)
 2014-03-10 19:39:49 (00:09:28)
 2014-03-10 19:49:01 (00:09:12)
 2014-03-10 19:56:45 (00:07:44)
 2014-03-10 20:13:16 (00:16:30)
 2014-03-10 20:24:36 (00:11:20)
 2014-03-10 20:33:41 (00:09:05)
 2014-03-10 20:41:34 (00:07:53)
 2014-03-10 20:49:46 (00:08:12)
 2014-03-10 21:02:32 (00:12:46)
 2014-03-10 21:12:22 (00:09:49)
 2014-03-10 21:20:39 (00:08:17)
 2014-03-10 21:30:46 (00:10:06)
 2014-03-10 21:38:47 (00:08:00)
 2014-03-10 21:48:56 (00:10:08)
 2014-03-10 22:00:01 (00:11:05)
 2014-03-10 22:08:20 (00:08:19)
 2014-03-10 22:15:57 (00:07:36)
 2014-03-10 22:28:51 (00:12:54)

 2014-03-10 22:43:56 (00:15:05)

[참고자료]

- iOS7 : What's new in iOS7
- [iOS] :iOS Programming Guide - App State and Multitasking
- [Double Encore]: http://www.doubleencore.com/2013/09/ios-7-background-fetch/
- [Hayageek] : http://hayageek.com/ios-background-fetch/
- [Tuts+] : http://code.tutsplus.com/tutorials/ios-7-sdk-working-with-background-fetch--mobile-20520

댓글 없음:

댓글 쓰기