9

So with iOS 7 supporting a broader background mode, is it possible to finally have an equivalent to Android Service on iOS?

What I am after is essentially running app A in the background and have one or more apps B and C talk to that app (without showing the GUI of app A).

Please note that using connectivity and push notifications may not be an option although this is the recommended way of doing so. Any ideas?

Eloy_007
  • 226
  • 1
  • 2
  • 9
  • 6
    I recommend you ask this question elsewhere since iOS 7 is not released yet. The best place for this kind of thing is the Apple developer forums. I doubt Apple will ever simply just let your app run in the background though. Too many idiot programmers will write crap services that suck down the battery. – borrrden Aug 20 '13 at 07:54
  • Hey, I have a similar problem to solve.... If you solved your problem please tell me how you did it? – Darth Vader Jan 19 '21 at 06:52

4 Answers4

6

EDIT: Not working as expected. See this answer for best solution: Push Notifications


EDIT: The next solution is only useful while the user is in the app to maintain it synced.

There is no way to perform tasks in the background permanently, but you can use the finite-length tasks to do that, when you make a finite-length, this gonna run always while the app is active, but when you click home button, ios gives you only 10 min to perform your task and invalidate it, but it gives you a chance to make a 'invalidate handler block' where you can do last actions before finish definitely.

So, if you use that handler block to call a finite-length task other time, you can simulate a service by run a task for 10 min and when its end, call its same for other 10 min and consequently.

I use that in a project creating a interface 'Service'. I let you here the code:


  • Service.h

//
//  Service.h
//  Staff5Personal
//
//  Created by Mansour Boutarbouch Mhaimeur on 30/09/13.
//  Copyright (c) 2013 Smart & Artificial Technologies. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Service : NSObject

@property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
@property (nonatomic) NSInteger frequency;
@property (nonatomic, strong) NSTimer *updateTimer;

- (id) initWithFrequency: (NSInteger) seconds;
- (void) startService;
- (void) doInBackground;
- (void) stopService;
@end

  • Service.m

//
//  Service.m
//  Staff5Personal
//
//  Created by Mansour Boutarbouch Mhaimeur on 30/09/13.
//  Copyright (c) 2013 Smart & Artificial Technologies. All rights reserved.
//

#import "Service.h"

@implementation Service
@synthesize frequency;

-(id)initWithFrequency: (NSInteger) seconds{
    if(self = [super init]){        
        self.frequency = seconds;
        return self;
    }
    return nil;
}
- (void)startService{
    [self startBackgroundTask];
}

- (void)doInBackground{
    //Español //Sobreescribir este metodo para hacer lo que quieras
    //English //Override this method to do whatever you want
}

- (void)stopService{
    [self.updateTimer invalidate];
    self.updateTimer = nil;
    [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
    self.backgroundTask = UIBackgroundTaskInvalid;
}

- (void) startBackgroundTask{
    self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:frequency
                                                        target:self
                                                      selector:@selector(doInBackground)
                                                      userInfo:nil
                                                       repeats:YES];
    self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self endBackgroundTask];
    }];
}
- (void) endBackgroundTask{
    [self.updateTimer invalidate];
    self.updateTimer = nil;
    [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
    self.backgroundTask = UIBackgroundTaskInvalid;
    [self startBackgroundTask];
}

@end

With this class i perform my services, but i don't test it for a really long time. The best test i does lasted 16 hours in simulator and everything works fine!

EDIT: That was tested on the simulator, but in phone doesnt work after the application has been terminated.

I let you a example:


// SomeService.h
@interface SomeService : Service

@end


// SomeService.m
#import "SomeService.h"

@implementation SomeService

// The method to override
- (void)doInBackground{
    NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
    NSLog(@"Service running at %.1f seconds", [self getCurrentNetworkTime]);
}
// Your methods
- (long) getCurrentNetworkTime{
    return ([[NSDate date] timeIntervalSince1970]);
}

@end

And in your app delegate or where you need to raise the service, you write the next line:

Service myService = [[SomeService alloc] initWithFrequency: 60]; //execute doInBackground each 60 seconds
[myService startService];

And if you need to stop it:

[myService stopService];

May have explained more than necessary, but i want to keep it clear for anyone! I hope its help and sorry for my english.

Community
  • 1
  • 1
IgniteCoders
  • 4,834
  • 3
  • 44
  • 62
  • I test my solution in a real device and everything works good for more than 16 hours. But i got a problem, if you set the frequency for more than 10 min, the service run but the timer execute the code when the frequency time passes, so if the service is invalidate before execute the code, never gonna do it while your app its in background. So i am trying to solve it, if someone do it, leave a comment with the solution plz! – IgniteCoders Oct 09 '13 at 15:12
  • is this solution apple approval friendly? – Ahmed Nov 01 '13 at 11:35
  • I don't know, still developing the app. Just got problems with that because i test the app on a iPhone 5C and services stop after 10 min. :S – IgniteCoders Nov 04 '13 at 11:15
  • 1
    Thanks. I tried that on iPhone 4S with iOS 6.1. The job stops at ten minutes. Though the code is re-calling the background task after time finishes. Any help :O – Ahmed Nov 04 '13 at 14:29
  • @Ahmed take a look to this answer: [Push Notifications](http://stackoverflow.com/a/19766719/2835520) – IgniteCoders Nov 19 '13 at 10:57
  • Did anyone get the solution so that we can schedule a task which will be occurred lets say after 5 day and the app also should not run in the background. Is there a way we can use the internal scheduler of the ios which is used in Reminder? – Saty Dec 10 '13 at 10:21
  • There´s no way @Saty, i search for a month for that, but finally got to implement the Push Notifications. – IgniteCoders Dec 15 '13 at 13:11
2

No, there is no equivalent to an Android Service. MansApps code does not work, at least not on iOS7. A call of [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask]; in the expiration handler will only return when the app comes back to the foreground, i.e., the call of [self startBackgroundTask]; will not be executed when the app stays in the background.

CryptoPaul
  • 21
  • 2
  • I used push notification to solve it and everythig work better, and the service that i made, i keep it for refresh or fetch things while user is using app. – IgniteCoders Oct 26 '16 at 15:52
2

Basically it's impossible if your app doesn't implement any of the functionalities listed bellow. And they hardly investigate your app before upload it to the store, you need to justify the use of that permissions

This is what Apple say about that:

Implementing Long-Running Tasks

For tasks that require more execution time to implement, you must request specific permissions to run them in the background without their being suspended. In iOS, only specific app types are allowed to run in the background:

  • Apps that play audible content to the user while in the background, such as a music player app
  • Apps that record audio content while in the background
  • Apps that keep users informed of their location at all times, such as a navigation app
  • Apps that support Voice over Internet Protocol (VoIP)
  • Apps that need to download and process new content regularly
  • Apps that receive regular updates from external accessories

Apps that implement these services must declare the services they support and use system frameworks to implement the relevant aspects of those services. Declaring the services lets the system know which services you use, but in some cases it is the system frameworks that actually prevent your application from being suspended.

IgniteCoders
  • 4,834
  • 3
  • 44
  • 62
0

I found the best and standard solution:

Push notifications

(original post by Matthijs Hollemans, update by Ali Hafizji).

In iOS, apps can’t do a lot in the background. Apps are only allowed to do limited set of activities so battery life is conserved. But what if something interesting happens and you wish to let the user know about this, even if they’re not currently using your app? For example, maybe the user received a new tweet, their favorite team won the game, or their dinner is ready. Since the app isn’t currently running, it cannot check for these events. Luckily, Apple has provided a solution to this. Instead of your app continuously checking for events or doing work in the background, you can write a server-side component to do this instead. And when an event of interest occurs, the server-side component can send the app a push notification! There are three things a push notification can do:

  • Display a short text message
  • Play a brief sound
  • Set a number in a badge on the app’s icon

Tutorial link: http://maniacdev.com/2011/05/tutorial-ios-push-notification-services-for-beginners

Community
  • 1
  • 1
IgniteCoders
  • 4,834
  • 3
  • 44
  • 62
  • The original question explicitly states that push notifications may not be an option, and they are far from the 'best' solution for many sustained background processing or communication solutions. – Opsimath Dec 21 '15 at 17:04