8

私はその話題に大きな頭を悩ませています。新しいデータをチェックするために、Web サーバーを定期的にポーリングする必要があるアプリケーションに取り組んでいます。返された情報に基づいて、ローカル通知をユーザーにプッシュしたいと考えています。

このアプローチは、APNS に基づいてリモート サーバーが機能し、リモート通知をプッシュするという Apple のアプローチとは少し異なることを私は知っています。ただし、このアプローチを考慮に入れることができない多くの理由があります。その 1 つは、ユーザー認証メカニズムです。リモート サーバーは、セキュリティ上の理由から、ユーザーの資格情報を考慮することができません。私にできることは、ログインとフェッチのコアをクライアント (iPhone) に移動することだけです。

Apple が、アプリケーションがソケット接続 (つまり、VoIP アプリケーション) を起動して開いたままにする機会を提供していることに気付きました。

ということで、こんな感じで調べ始めました。plist に必要な情報を追加しました。appDelegate で次のようなものを使用して、アプリケーションを「起動」できます。

[[UIApplication sharedApplication] setKeepAliveTimeout:1200 handler:^{ 
    NSLog(@"startingKeepAliveTimeout");
    [self contentViewLog:@"startingKeepAliveTimeout"];
    MyPushOperation *op = [[MyPushOperation alloc] initWithNotificationFlag:0 andDataSource:nil];
    [queue addOperation:op];
    [op release];
}];

NSOperation は、次のブロック コードを使用してバックグラウンド タスクを開始します。

#pragma mark SyncRequests
-(void) main {
    NSLog(@"startSyncRequest");
    [self contentViewLog:@"startSyncRequest"];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
        NSLog(@"exipiration handler triggered");
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
        [self cancel];
    }];


        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSMutableURLRequest *anURLRequest;
            NSURLResponse *outResponse;
            NSError *exitError;
            NSString *username;
            NSString *password;

            NSLog(@"FirstLogin");
            anURLRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:webserverLogin, username, password]]];
            [anURLRequest setHTTPMethod:@"GET"];
            [anURLRequest setTimeoutInterval:120.00];
            [anURLRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];

            exitError = nil;
            NSData *tmpData = [NSURLConnection sendSynchronousRequest:anURLRequest returningResponse:&outResponse error:&exitError];
            [anURLRequest setTimeoutInterval:120.00];
            if(exitError != nil) { //somethings goes wrong
                NSLog(@"somethings goes wrong");
                [app endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
                [self cancel];
                return;
            }

            //do some stuff with NSData and prompt the user with a UILocalNotification

            NSLog(@"AlltasksCompleted");
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
            [self cancel];
        });
    }
}

上記のコードは (時々) 動作するように見えますが、他の多くの場合、アプリケーションがクラッシュし、次のログ情報が表示されます。

Exception Type:  00000020
Exception Codes: 0x8badf00d
Highlighted Thread:  3

Application Specific Information:
DemoBackApp[5977] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0xa9da0b0> identifier: UIKitBackgroundCompletionTask process: DemoBackApp[5977] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:5977 preventSuspend  preventIdleSleep 
)}

Elapsed total CPU time (seconds): 0.010 (user 0.010, system 0.000), 100% CPU 
Elapsed application CPU time (seconds): 0.000, 0% CPU

尋ねる人のために、はい。Async NSURLConnection アプローチも試しました。どんなに。タイムアウト ハンドラと didFinishLoading:WithError で非同期アプローチを使用しても、同じようにクラッシュします。

私は立ち往生しています。どんなヒントでも大歓迎です。

4

4 に答える 4

9

これは古いスレッドですが、更新が必要な場合があります。

iOS 6 の時点で、これはこのスレッドで説明されているように、VoIP タイマー バックグラウンド メソッドで見られる動作です。

  • VoIP BackgroundMode は、アプリ レビュー プロセスを通じて、AppStore アプリから引き続き厳しく禁止されています。
  • キープアライブの最小時間は 600 秒です。それ未満の場合、ハンドラーのインストールに失敗します (そして警告が NSLog に送信されます)。
  • keepAlive 時間を 600 秒よりも大幅に大きく設定すると、通常、ハンドラーが時間/2間隔ごとに起動されます。おまけ: これは、推奨される再登録間隔が 0.5*再登録時間である SIP REGISTER 要求と一致しています。
  • keepAlive ハンドラーが呼び出されると、次のことがわかりました。
    • 「フォアグラウンド」実行時間は約10 秒で、残りのバックグラウンド時間は無限です ( backgroundTimeRemainingによって返されます) 。
    • keepAlive ハンドラー内からbeginBackgroundTaskを開始した場合、 60 秒のバックグラウンド実行時間が得られることがわかりました ( backgroundTimeRemainingによって返されます)。これは、ユーザーがアプリをアクティブからバックグラウンドに移行するときに得られる600 秒とは異なります。この時間を延長する方法は見つかりませんでした(場所などの他のトリックを使用せずに)

それが役立つことを願っています!

于 2013-04-18T19:16:33.480 に答える
7

を呼び出すと-setKeepAliveTimeout:handler:、すべてを完了して中断するのに最大 30 秒しか与えられません。アプリケーションが最初にバックグラウンドに移行したときに与えられるのと同じバックグラウンド猶予期間は与えられません。これは、長時間実行されているタスクを終了したり、物事をシャットダウンしたりするためのものです。

VOIP コールバックを使用すると、サービスに送信する必要のある ping パケットを送信して、ネットワーク接続を維持し、タイムアウトしないようにするだけです。30 秒後、新しいバックグラウンド タスクの開始に関係なく、アプリケーションがまだ実行されている場合は終了します。

また、実際に VOIP アプリケーションではない場合、またはVOIP コールバック ウィンドウ中にネットワーク接続を開いたままにしておくことに関係のない操作を行った場合、アプリはアプリ ストアから拒否されることに注意してください。ステイアクティブ フラグ (VOIP、バックグラウンド ミュージック、ナビゲーション) を設定すると、かなり厳密にテストされ、バックグラウンドで実行するフラグが設定されていることだけが実行されることが保証されます。あらゆる種類の HTTP GET リクエストを実行し、大規模なデータの更新が戻ってくるのを待つと、ほぼ確実にアプリが拒否されます。

編集: コメントでパトリックが指摘したように、ブロックが実行される現在の時間は、iOS 5 では 30 秒から 10 秒に短縮されました。再リンクするときはいつでも、これらの時間を監視することをお勧めします。 SDK の新しいバージョンのアプリケーションを更新する場合は、ドキュメントが更新されている場合に備えて、ドキュメントを少なくともすばやく確認してください (iOS 6 が登場すると、この数は再び調整される可能性があります)。

于 2011-01-24T00:29:16.533 に答える
3

呼び出されたときに有限のバックグラウンド タスク実行の要求をピギーバックすることで、キープ アライブ タイムアウト ハンドラを組み合わせることができるようです。これにより、VOIP キープアライブ ハンドラーが呼び出されるたびに 10 分 (通常は 10 ~ 30 秒) の時間を確保できます。

上記と同じ問題 - 送信するには plist に VOIP フラグが必要であり、そのフラグがあり、実際には VOIP アプリケーションではなく、内部配布 (企業またはそれ以外の場合)、このソリューションはバックグラウンド時間を提供するためにうまく機能するはずです。

私のテストでは、VOIP ハンドラーが呼び出されるたびに 10 分間の有限実行タイマーがリセットされます (それ以降、ユーザーがアプリケーションを前面に出したかどうかに関係なく)。バックグラウンドは 600 秒 (10 分) ごとに 1 回実行され、ポーリング プロセスはスリープ状態になるまでに最大 10 分かかる場合があります (必要な場合は、ほぼ一定のバックグラウンド操作を意味します)。

繰り返しますが、あなたがVOIPであることを彼らに納得させることができない限り、App Storeのオプションではありません.

于 2012-09-06T23:58:32.537 に答える