web-dev-qa-db-ja.com

iOS:アプリをサービスのように実行し続ける

IOSでは、フォアグラウンドになくなったアプリを実行し続けるようにOSに指示するにはどうすればよいですか?

さらに多くのアプリがこれを行います。

26

基本的に、iOSにはサービスタイプのアプリや機能などはありません。 「バックグラウンド」アプリ(UIBackgroundMode)でさえ、完全に無料で実行することはできず、他のOSのサービスやデーモンなどの制限なしには実行できません。

バックグラウンドでの実行、通知、タイマーなどに関する状況は次のとおりです。

1)アプリはバックグラウンドで実行できません:

a)OSに追加の時間を要求します。これは、beginBackgroundTaskWithExpirationHandlerを使用して行われます。 (意図的に)Appleこの余分な時間の長さは指定されていませんが、実際には約10分です。

b)アプリにはバックグラウンドモードがあり、モードはVoIP、音声、場所、ニューススタンドです。これらのタイプのいずれかがあったとしても、アプリは制限なく実行できません。これ以降の説明では、アプリにバックグラウンドモードがないことを前提としています。これらのバックグラウンドモードのいずれかを使用してアプリをバックグラウンドで実行できるようにしようとしたが、アプリが特定の機能を正当に使用しない場合、アプリはアプリストアへの送信時に拒否されます(つまり、UIBackgroundMode VoIPアプリ、継続的な位置情報の更新が必要、バックグラウンドで音声を継続的に再生する機能が基本的な機能、またはニューススタンドアプリのいずれかである必要があります。

2)アプリが一時停止されている場合、アプリ自体を直接起動することはできません。 NSTimerを以前にスケジュールすることはできません。performSelector:afterDelayなどを使用することはできません。等.

アプリが再びアクティブになる唯一の方法は、ユーザーがそれをアクティブにするために何かをする場合です。ユーザーは、次の方法でこれを実行できます。

a)アイコンからアプリを直接起動する

b)アプリがアクティブな間に以前にスケジュールされたローカル通知に応じてアプリを起動します。

c)サーバーから送信されたリモート通知に応じてアプリを起動します。

d)他のいくつか:アプリがURL経由の起動に対処するために登録されている場合のURL起動など。または、特定の種類のコンテンツを処理できるように登録されている場合。

ローカル/リモート通知が発生したときにアプリがフォアグラウンドにある場合、アプリはそれを直接受信します。

ローカル/リモート通知が発生したときにアプリが現在フォアグラウンドにない場合、アプリはそれを受信しません。通知が発生したときに実行されるコードはありません!

ユーザーが通知を選択した場合にのみ、アプリがアクティブになり、実行できます。

ユーザーは、デバイス全体または特定のアプリケーションに対してのみ通知を無効にできることに注意してください。この場合、ユーザーには通知が表示されません。通知が火災によるものであるときにデバイスの電源が切れると、デバイスは失われます。

IOS 7

1)バックグラウンドフェッチなどの新しいバックグラウンドモードがいくつかあります(ただし、OSによって確定的な方法で起動することはできません)。

2)バックグラウンドのプッシュ通知があります

3)beginBackgroundTaskWithExpirationHandlerの時間が10分から約3に短縮されました。

45
Gruntcakes

iOS7でベータ版になりました

Appleの開発者ポータル から:

IOS 7の新しいマルチタスクAPIを採用することにより、アプリのコンテンツを最新の状態に保ちます。新しいサービスにより、アプリは情報を更新し、バックグラウンドでコンテンツをダウンロードすることができます。更新は日和見的なタイミングで行われ、使用状況に応じてインテリジェントにスケジュールされるため、アプリはユーザーが必要なときにコンテンツをバックグラウンドで更新できます。

2
null

はい、できます。

プライベートフィールドを作成して、ステータスを追跡します。

UIBackgroundTaskIdentifier _bgTask;

次に、このメソッドを呼び出して、サービスのようにアプリを実行します

if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)]) 
{
   _bgTask = UIBackgroundTaskInvalid;
   [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(doBackground:)
name:UIApplicationDidEnterBackgroundNotification object:nil];
}

セレクターを作成します-

- (void) doBackground:(NSNotification *)aNotification
{
   UIApplication *app = [UIApplication sharedApplication];

   if ([app respondsToSelector:@selector(beginBackgroundTaskWithExpirationHandler:)])
   {
      _bgTask = [app beginBackgroundTaskWithExpirationHandler:^
      {
         dispatch_async(dispatch_get_main_queue(), ^
         {
            if (_bgTask != UIBackgroundTaskInvalid)
            {
               [app endBackgroundTask:_bgTask];
               _bgTask = UIBackgroundTaskInvalid;
            }
         });
      }];
   }
}

タスクが完了したら、以下のコードを呼び出します

UIApplication *app = [UIApplication sharedApplication];
if ([app respondsToSelector:@selector(endBackgroundTask:)]) 
{
   if (_bgTask != UIBackgroundTaskInvalid)
   {
      [app endBackgroundTask:_bgTask];
      _bgTask = UIBackgroundTaskInvalid;
   }
}
1
Zoeb S

Swift @Zoeb Sの回答のバージョン。たぶんOPに対する正しい答えではありません。しかし、これはアプリがバックグラウンドに入るたびに_background task_を開始するのに役立ちます。そして、しばらくしてからiOSによって自身が殺されます(処理が終了した後)。

変数を宣言する

_fileprivate let backgroundTaskStarter = {
  // TODO: If this doesn't work, switch to willResignActiveNotification.
  UIApplication.didEnterBackgroundNotification.observe() { _ in
    UIApplication.shared.beginBackgroundTask {
      NSLog("endBackgroundTask called by iOS")
    }
  }
}()
_

そして、_Filename.Swift_のinit()メソッドで、次のようにします。

__ = backgroundTaskStarter
_
1
Ajo