App for jailbroken iOS device: Consistent background operation
Asked Answered
A

2

2

I am the author of a Cydia tweak called AirFloat. An app that implements the AirPlay audio protocol (previously known as AirTunes), making it possible to stream audio to your iOS device. AirFloat is originally an App Store app, until it got booted by Apple from the App Store.

I've since that made it available for free in Cydia. Currently the app stands in Cydia exactly as the previous App Store version. As a result of this I get a lot of requests to make it work in the background. But I cannot get it to work.

Basically I am thinking of two approaches.

Note: AirFloat displays the currently playing track on the iOS lock screen.

  1. Create a daemon, which runs the actual AirPlay implementation, and communicates with a UI app using notify. This works. Kind of. It runs and plays the audio, but the MPNowPlayingInfoCenter does not seem to be updatable from a non-UI application. Also when the daemon is running as user mobile.

  2. Second approach is to just have it all work in a UI application. But I am having difficulties not having it be suspended. I've set the "Required Background Modes" to audio and continuous. The server might still be running, but then the Bonjour advertising is brought down, because the run loop is brought to a halt when in background. Secondly the app should be launched automatically with SpringBoard and relaunched on abnormal exit.

Personally I prefer the second approach, because I would avoid doing interprocess communication. And for this approach to work I would need full background execution (including run loops) and have it both launched on SpringBoard launch and relaunched on abnormal exit.

Anyone have any suggestions on how to solve this?

Airliner answered 16/3, 2013 at 11:46 Comment(0)
A
2

First thank you for your amazing works with AirFlow RAOP is pretty hard thing!

So what you could do is to

1. Create a background task handlers as dispatch_block_t, let's say

     dispatch_block_t myDummyBackgroundTaskBlock = {
        [[UIApplication sharedApplication] endBackgroundTask:myDummyBackgroundTask];
        myDummyBackgroundTask = UIBackgroundTaskInvalid;
        myDummyBackgroundTask = [app beginBackgroundTaskWithExpirationHandler:myDummyBackgroundTask];
    };

2. Define somewhere this background and foreground tasks handler

        // foreground
        -(void)handleTasksForApplicationInForeground {
        if(myDummyBackgroundTask) { // reset that task
           [[UIApplication sharedApplication] endBackgroundTask: myDummyBackgroundTask];
           myDummyBackgroundTask = UIBackgroundTaskInvalid;
         }
        }

         // background
         -(void) handleTasksForApplicationInBackground {
             UIDevice *device = [UIDevice currentDevice];
             BOOL backgroundSupported = NO;
            if ([device respondsToSelector:@selector(isMultitaskingSupported)])
             backgroundSupported = device.multitaskingSupported;
            if(backgroundSupported && backgroundEnabled) { // perform a background task

                myDummyBackgroundTaskBlock = ^{
                    [[UIApplication sharedApplication] endBackgroundTask: myDummyBackgroundTaskBlock];
                    myDummyBackgroundTaskBlock = UIBackgroundTaskInvalid;
               };

               SEL sel = @selector(doDummyBackgroundTask);
               [self doBackgroundTaskAsync:sel];

               [self performSelector:@selector(doBackgroundTaskAsync:) withObject:nil afterDelay:500.0f]; /// LP: this is the funny part since iOS will kill the task after 500 sec.
                 }
               }

3. Now let's handle in the application delegate the background mode (As defined before you can activate background mode with different options in your app .plist):

        -(void)applicationDidEnterBackground:(UIApplication *)application {
           [self handleTasksForApplicationInBackground];
         }

        -(void)applicationWillEnterForeground:(UIApplication *)application {
           [self handleTasksForApplicationInForeground];
         }

4. Let's see what the background async task selector does

            -(void) doBackgroundTaskAsync:(SEL)selector {

            @try {
                 if( [[UIApplication sharedApplication] backgroundTimeRemaining] < 5 ) { 
                   return;
                 }

               if(!myDummyBackgroundTaskBlock) { // need to create again on-the-fly
                    myDummyBackgroundTaskBlock = ^{
                          [[UIApplication sharedApplication] endBackgroundTask:myDummyBackgroundTask];
                         myDummyBackgroundTask = UIBackgroundTaskInvalid;
                    };
                 }

                myDummyBackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:myDummyBackgroundTaskBlock];
              dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

               while ([[UIApplication sharedApplication] backgroundTimeRemaining] > 5.0) {
                  int delta = 5.0;
                  [self performSelector: selector ];
                  sleep(delta);
              }
            });
          }
           @catch (...) {
         }
        }

I know that this solution works nice but I know that sometimes it happens that iOS will kill the app background task anyway. Anyway if the users suddenly switches the app between foreground and background it will works indefinitely.

Antirachitic answered 17/4, 2013 at 19:10 Comment(2)
Thanks a lot! I will test this out with the upcoming version. Thanks!Airliner
From iOS7 the background activity was reduced from 600 sec. (5min) to 180 secs. (3min), so the selector calling the doBackgroundTaskAsync with delay must be called after >= 180.0fAntirachitic
C
1

Partial answer. If you add "voip" as Background Mode, it gets started automatically by SpringBoard.

Conjurer answered 16/3, 2013 at 18:53 Comment(1)
This works. It gets started automatically. All is fine. But there must be some way of making it run always in background. Like the MobilePhone.app or MobileMail.app.Airliner

© 2022 - 2024 — McMap. All rights reserved.