iOS7で可能になったAppのバックグラウンド更新を調べた

iOS7では、設定アプリに一般>Appのバックグラウンド更新というメニューが追加されています。

いろいろネットで検索してみると、「バッテリー浪費するかもしれないからOFFにした方が良い」というTipsブログのオンパレードだったりするのですが、エンジニア的にはこれってどういう機能で、どうすれば使えるの?という方が気になります。

これは、Xcode5(iOS SDK7)上でプロジェクトの設定を開き、CapabilitiesタブのBackground ModesをONにして、さらに、Modesの中からBackground fetchかRemote notificationsのいずれかをONにすると、Appのバックグラウンド更新にアプリが表示されるようになります。

iOS6までのマルチタスク

Background fetchとRemote notificationsで何が出来るかの説明の前に、iOS6までのマルチタスクについておさらいをしておきましょう。

iOS6では、アプリがバックグラウンドになった際の処理は、一部の機能を持つアプリに限定して許可されていました。それ以外のアプリはバックグラウンドになった後は10分間だけ処理が可能で、その後はサスペンドになってしまいます。
そのため、一般のアプリでは、サーバとのデータ同期処理等をバックグラウンドで自動的に行ったり、通知が来た際にバックグラウンドで何か処理を行うといったことが出来ません。

Background fetchで何が出来るか?

Background fetchはiOS7で追加された機能で、アプリがバックグラウンドになった際に、一定の間隔でデータの取得処理を行うものです。

「一定の間隔」といっても、指定できるのは「OSでサポートされる最小の間隔(UIApplicationBackgroundFetchIntervalMinimum定数)」か、「バックグラウンド更新をしない(UIApplicationBackgroundFetchIntervalNever定数)」のいずれかしかないようです。
データ取得にログインが必要なら、ログインしている場合はUIApplicationBackgroundFetchIntervalMinimum、ログアウトした場合はUIApplicationBackgroundFetchIntervalNeverを指定するといった感じにするのが良いのではないでしょうか。

[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

実際の取得処理は、performFetchWithCompletionHandlerです。

- (void) application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    //コンテンツの取得処理

    if (success) {
        //処理に成功した場合
        if (hasNewData) {
            completionHandler(UIBackgroundFetchResultNewData);
        } else {
            completionHandler(UIBackgroundFetchResultNoData);
        }
    } else {
        completionHandler(UIBackgroundFetchResultFailed);
    }
}

Remote notificationsで何が出来るか?

Remote notificationsもiOS7で追加された機能で、サーバからのPush通知をトリガーとして、バックグラウンドでデータの取得処理を行うものです。
サーバ側でのデータ更新があった際にPush通知が出来るのであれば、Remote notificationsを使った方がバッテリーの節約が出来そうです。

UIApplicationのdidReceiveRemoteNotificationメソッドに、fetchCompletionHandler引数が付いたものがあるので、それを使ってPush通知時のバックグラウンド更新を行います。

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    //コンテンツの取得処理

    if (success) {
        //処理に成功した場合
        if (hasNewData) {
            completionHandler(UIBackgroundFetchResultNewData);
        } else {
            completionHandler(UIBackgroundFetchResultNoData);
        }
    } else {
        completionHandler(UIBackgroundFetchResultFailed);
    }
}

これは開発者が上手く使ってあげれば、便利な機能だと思います。

<2013/10/18追記>
Remote Notificationでのバックグラウンド更新を行う場合、通知のペイロードにcontent-available=1という項目が必要です。詳細は、iOSのPUSH通知(APNs)の種類について、ざっくり。をどうぞ。

この記事を書いた人

井上 研一

株式会社ビビンコ代表取締役、ITエンジニア/経済産業省推進資格ITコーディネータ。AI・IoTに強いITコーディネータとして活動。2018年、株式会社ビビンコを北九州市に創業。IoTソリューションの開発・導入や、画像認識モデルを活用したアプリの開発などを行っている。近著に「使ってわかった AWSのAI」、「ワトソンで体感する人工知能」。日本全国でセミナー・研修講師としての登壇も多数。