iPhone - 一个后台轮​​询事件 [英] iPhone - Backgrounding to poll for events

查看:343
本文介绍了iPhone - 一个后台轮​​询事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

相当长一段时间我一直在寻找到我的iPhone应用程序的方式来轮询每隔X分钟检查数据计数器。背景执行文档和一些试验应用的大量的阅读之后,我会不会滥用背景的API驳回这是不可能的。

For quite a while I'd been looking into a way in my iPhone app to poll every X minutes to check the data counters. After much reading of the Background Execution documentation and a few trial apps I'd dismissed this as impossible without abusing the background APIs.

上周,我发现这个应用程序,它正是这么做的。 <一href=\"http://itunes.apple.com/us/app/dataman-real-time-data-usage/id393282873?mt=8\">http://itunes.apple.com/us/app/dataman-real-time-data-usage/id393282873?mt=8

Last week I found this application which does exactly that. http://itunes.apple.com/us/app/dataman-real-time-data-usage/id393282873?mt=8

它在后台运行,并跟踪你已经使用蜂窝/无线数据的计数。我怀疑开发商自己注册为应用程序跟踪位置的变化,但同时应用程序正在运行,我认为是位置服务的图标是不可见的要求。

It runs in the background and keeps track of the count of Cellular/WiFi data you've used. I suspect that the developer is registering his app as tracking location changes but the location services icon isn't visible while the app is running, which I thought was a requirement.

没有人有任何线索,这可怎么实现的呢?

Does anyone have any clues as to how this can be accomplished?

推荐答案

我已经看到了这种行为,太。尝试了很多之后,我发现了两件事情,这将有助于。但我仍不能肯定这会如何影响审核过程。

I have seen this behavior, too. After trying a lot I discovered two things, which could help. But I am still uncertain how this may influence the reviewing process.

如果您使用的一个后台的功能之一,应​​用程序将被iOS的后台再次发动一旦有人退出(系统)。这个我们会在后面滥用。

If you use one of the backgrounding features, the app will be launched by iOS in background again once it was quit (by the system). This we will abuse later.

在我来说,我用我的plist支持VoIP功能的一个后台。
所有$ C $这里C是AppDelegate中完成的:

In my case I used VoIP backgrounding enabled in my plist. All the code here is done in your AppDelegate:

// if the iOS device allows background execution,
// this Handler will be called
- (void)backgroundHandler {

    NSLog(@"### -->VOIP backgrounding callback");
    // try to do sth. According to Apple we have ONLY 30 seconds to perform this Task!
    // Else the Application will be terminated!
    UIApplication* app = [UIApplication sharedApplication];
    NSArray*    oldNotifications = [app scheduledLocalNotifications];

     // Clear out the old notification before scheduling a new one.
    if ([oldNotifications count] > 0) [app cancelAllLocalNotifications];

    // Create a new notification
    UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease];
    if (alarm)
    {
        alarm.fireDate = [NSDate date];
        alarm.timeZone = [NSTimeZone defaultTimeZone];
        alarm.repeatInterval = 0;
        alarm.soundName = @"alarmsound.caf";
        alarm.alertBody = @"Don't Panic! This is just a Push-Notification Test.";

        [app scheduleLocalNotification:alarm];
    }
}

和登记在完成

- (void)applicationDidEnterBackground:(UIApplication *)application {

    // This is where you can do your X Minutes, if >= 10Minutes is okay.
    BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
    if (backgroundAccepted)
    {
        NSLog(@"VOIP backgrounding accepted");
    }
}

现在,奇迹发生了:我甚至不使用VoIP的套接字。但是,这10分钟的回调提供了一个很好的副作用:10分钟后(有时更早)我发现我的定时器和previous运行胎面正在一小会儿执行。你可以看到这一点,如果你把一些的NSLog(..)到code。这意味着,这短短的唤醒执行code一段时间。据苹果,我们还剩下30秒执行时间。我认为,这样的背景下code像线程是近30秒执行。这是很有用code,如果你必须有时检查一番。

Now the magic happens: I don't even use VoIP-Sockets. But this 10 Minutes callback provides a nice side effect: After 10 Minutes (sometimes earlier) I discovered that my timers and previous running treads are being executed for a short while. You can see this, if you place some NSLog(..) into your code. This means, that this short "wakeup" executes the code for a while. According to Apple we have 30 seconds execution time left. I assume, that background code like threads are being executed for nearly 30 seconds. This is useful code, if you must "sometimes" check something.

该医生说,所有后台任务(网络电话,音频,位置更新)将在后台自动重新启动,如果该应用程序已终止。 VoIP的应用程序将在后台启动启动后自动!

The doc says that all background tasks (VoIP, audio, location updates) will be automatically restarted in background if the app was terminated. VoIP apps will be started in background automatically after bootup!

通过滥用这种行为,你可以让你的应用程序可以寻找像运行永远。
注册一个后台进程(即VoIP)的。这将导致您的应用程序终止后重新启动。

With abusing this behavior, you can make your app be looking like running "forever". Register for one background process (i.e. VoIP). This will cause your app to be restarted after termination.

现在写一些任务已完成code。据苹果你有一段时间(5秒?)留下来完成任务。我发现,这一定是CPU时间。因此,这意味着:如果你什么都不做,仍然在执行你的应用程序!苹果建议调用expirationhandler,如果你与你的工作完成了。在code下面你可以看到,我都不得不expirationHandler评论。这将导致您的应用程序运行,只要系统允许​​您的应用程序正在运行。所有定时器和线程保持运行,直到iOS的终止您的应用程序。

Now write some "Task has to be finished" code. According to Apple you have some time (5 seconds?) left to finish tasks. I discovered, that this must be CPU time. So that means: if you do nothing, your app is still being executed! Apple suggest to call an expirationhandler, if you are finished with your work. In the code below you can see, that i have a comment at the expirationHandler. This will cause your app running as long as the system allows your app to be running. All timers and threads stay running until iOS terminates your app.

- (void)applicationDidEnterBackground:(UIApplication *)application {

    UIApplication*    app = [UIApplication sharedApplication];

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];


    // Start the long-running task and return immediately.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // you can do sth. here, or simply do nothing!
    // All your background treads and timers are still being executed
    while (background) 
       [self doSomething];
       // This is where you can do your "X minutes" in seconds (here 10)
       sleep(10);
    }

    // And never call the expirationHandler, so your App runs
    // until the system terminates our process
    //[app endBackgroundTask:bgTask];
    //bgTask = UIBackgroundTaskInvalid;

    }); 
}

要非常有空闲的CPU时间在这里和你的应用程序运行更长!但有一件事是肯定的:您的应用程序将一段时间后终止。但是,因为你注册你的应用如VoIP或他人之一,系统重新启动应用程序在后台,这将重新启动后台进程;-)
有了这个乒乓我可以做很多的一个后台。但要记住是非常有空闲的CPU时间。并保存所有数据,恢复你的观点 - 你的应用程序将被终止后一段时间。使它看起来仍在运行,则必须跳回唤醒后您的最后一个国家。

Be very spare with CPU-Time here, and your app runs longer! But one thing is for sure: your app will be terminated after a while. But because you registered your app as VoIP or one of the others, the system restarts the app in background, which will restart your background process ;-) With this PingPong I can do a lot of backgrounding. but remember be very spare with CPU time. And save all data, to restore your views - your app will be terminated some time later. To make it appear still running, you must jump back into your last "state" after wakeup.

我不知道这是不是你前面提到的应用程序的方法,但它为我工作。

I don't know if this is the approach of the apps you mentioned before, but it works for me.

希望我能帮助

更新:

测量BG任务的时间后,出现了一个惊喜。对BG任务被限制为600秒。这是在VoIP的minimumtime的确切最小时间(setKeepAliveTimeout:600)

After measuring the time of the BG task, there was a surprise. The BG Task is limited to 600 seconds. This is the exact minimum time of the VoIP minimumtime (setKeepAliveTimeout:600).

所以这code通向后台无限的执行:

So THIS code leads into "infinite" execution in background:

标题:

UIBackgroundTaskIdentifier bgTask; 

code:

// if the iOS device allows background execution,
// this Handler will be called
- (void)backgroundHandler {

    NSLog(@"### -->VOIP backgrounding callback");

    UIApplication*    app = [UIApplication sharedApplication];

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    // Start the long-running task 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    while (1) {
        NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
           [self doSomething];
        sleep(1);
    }   
});     

- (void)applicationDidEnterBackground:(UIApplication *)application {

    BOOL backgroundAccepted = [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
    if (backgroundAccepted)
    {
        NSLog(@"VOIP backgrounding accepted");
    }

    UIApplication*    app = [UIApplication sharedApplication];

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];


    // Start the long-running task
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        while (1) {
            NSLog(@"BGTime left: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
           [self doSomething];
           sleep(1);
        }    
    }); 
}

您的应用程序已超时后,网络电话expirationHandler将被调用,您只需重新启动一个长期运行的任务。这个任务将在600秒后终止。但会有再次到期处理程序,它会启动另一个长时间运行的任务,等一个电话现在,你只需要查看天气应用程序是又回到了前台。然后关闭bgTask,就大功告成了。也许我们可以做某事。像这样从长期运行的任务的expirationHandler内。你不妨试试。使用您的控制台,看看会发生什么......玩得开心!

After your app has timed out, the VoIP expirationHandler will be called, where you simply restart a long running task. This task will be terminated after 600 seconds. But there will be again a call to the expiration handler, which starts another long running task, etc. Now you only have to check weather the App is getting back to foreground. Then close the bgTask, and you're done. Maybe one can do sth. like this inside the expirationHandler from the long running task. Just try it out. Use your Console, to see what happens... Have Fun!

更新2:

有时简化的东西帮助。我的新的方法是这样的:

Sometimes simplifying things helps. My new approach is this one:

- (void)applicationDidEnterBackground:(UIApplication *)application {

    UIApplication*    app = [UIApplication sharedApplication];

    // it's better to move "dispatch_block_t expirationHandler"
    // into your headerfile and initialize the code somewhere else
    // i.e. 
    // - (void)applicationDidFinishLaunching:(UIApplication *)application {
//
// expirationHandler = ^{ ... } }
    // because your app may crash if you initialize expirationHandler twice.
    dispatch_block_t expirationHandler;
    expirationHandler = ^{

        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;


        bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];
    };

    bgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler];


    // Start the long-running task and return immediately.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // inform others to stop tasks, if you like
        [[NSNotificationCenter defaultCenter] postNotificationName:@"MyApplicationEntersBackground" object:self];

        // do your background work here     
    }); 
}

这是工作的没有的VoIP的黑客攻击。根据该文件,如果执行时间是在到期处理程序(在这种情况下,我的'expirationHandler'块)将被执行。通过定义块成块的变量,可以再次递归到期处理程序中启动长时间运行的任务。这导致陷入无尽的执行了。

This is working without the VoIP hack. According to the documentation, the expiration handler (in this case my 'expirationHandler' block) will be executed if execution time is over. By defining the block into a block variable, one can recursively start the long running task again within the expiration handler. This leads into endless execution, too.

请注意,以终止任务,如果你的应用程序再次进入前景。并终止任务,如果你不需要它了。

Be aware to terminate the task, if your application enters foreground again. And terminate the task if you don't need it anymore.

有关我自己的经验,我测量的东西。
使用位置回调具有上下降非常迅速吸吮我的电池GPS无线电。使用我张贴的方法的更新2 的正在几乎没有能量。据userexperience这是一个更好的办法。也许其他的应用程序这样的工作,背后隐藏的GPS功能,其行为...

For my own experience I measured something. Using the location callbacks with having the GPS radio on is sucking my battery down very quickly. Using the approach which I posted in Update 2 is taking nearly no energy. According to the "userexperience" this is a better approach. Maybe other Apps work like this, hiding its behavior behind GPS functionality ...

这篇关于iPhone - 一个后台轮​​询事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆