I am trying to save my data when I exit or minimize my application, but it seems like applicationwillenterbackground is never called. Do I need to do anything specific?
I have set the <UIApplicationDelegate> in detailview.h class but still no luck.
By the way, I am using Master-DetailView templete if this is relavent.
Use -applicationDidEnterBackground: to save user data. This should also be done in -applicationWillTerminate: which might get called if the battery dies, I guess. See this question for more info: ApplicationWillTerminate in iOS 4.0
For my app, I extensively researched this issue and I found out that besides implementing both above mentioned methods I had to check whether the device supported multi-tasking, otherwise data would get saved twice (e.g. on an iPhone 3G). So here is how that part of my code looks like:
- (void) applicationDidEnterBackground:(UIApplication*)application
{
// This is called on all iOS 4 devices, even when they don't support multi-tasking.
// But we want to avoid saving data twice, so we check.
if ([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)])
[model serializeEntries];
}
- (void) applicationWillTerminate:(UIApplication*)application
{
// This is always called on devices that don't support multi-tasking,
// but also in low-memory conditions and when the app has to be quit for some
// other reason.
[model serializeEntries];
}
Related
While working in an iOS app, I found two ways to detect protected data available incident. One using callbacks and other using notifications. I need to know if they provide exact same functionalities or not. From the documentation I am unable to differentiate. So,
What are the differences between,
- (void) applicationProtectedDataDidBecomeAvailable:(UIApplication *)application {}
callback and
UIApplicationProtectedDataDidBecomeAvailable
notification?
applicationProtectedDataDidBecomeAvailable - On a device that uses content protection, protected files are stored in an encrypted form and made available only at certain times, usually when the device is unlocked. This notification lets your app know that the device is now unlocked and that you may access certain types of protected files again.
UIApplicationProtectedDataDidBecomeAvailable - Posted when the protected files become available for your code to access.
They provide the identical functionalities.
applicationProtectedDataDidBecomeAvailable is a UIApplicationDelegate method, and UIApplicationProtectedDataDidBecomeAvailable is a NSNotification Name.
An analogy is applicationDidBecomeActive: and UIApplicationDidBecomeActiveNotification, the former is a delegate method will be called when become active, meanwhile the latter will be post.
Every time security of Apps comes up, it turns out a lot of people are unaware of this being an issue. For instance, iOS takes screen-shot of visible screen every time our App gets backgrounded and it is stored in local storage.
Now that's the thing I want to get rid of. I am developing an App that does online financial transactions and I want my App be very powerful in terms of security aspect. Here is the path where the screenshot is being stored when my App gets backgrounded.
Path: /private/var/mobile/Applications/15980ADD-B269-4EBE-9F52- B6275AFB195A/Library/Caches/Snapshots/com.ABC.myAppName/screenshotName.PNG
This is the image which is being stored that looks very critical:
Even more critical scenario will be if user has entered his/her Credit/Debit card number including CVV2 number and other essential information and might have forced App in background for a while.
I have been doing a little search on that and I got to know that, for an attacker to be able to leverage this attack, there are two ways for him to gain access to that:
The attacker needs physical access to the device with the intent of
jail breaking.
Needs to be on the same network as user who has jail broken the
device and attempt to access the device remotely.
What could have I done to avoid this being possible? Is there any solution that can avoid an attacker getting access to the sensitive information in this way?
Also I have gotten advice to enable a blank screenshot or delete the screenshot for the application, when the application is backgrounded. But, I don't have any idea what to choose and how to do it properly. Is there any other alternative?
I can suggest a couple of things:
1) you know when your app is about to be put into the background, via the application delegate method:
- (void) applicationDidEnterBackground:(UIApplication *)application
That's the exact moment the snapshot is generated. Why not change your view to be something different or more "secure"?
2)
If you want the "secure" (or bogus) snapshot to be ignored when you bring the app back to foreground, you can use "[UIApplication ignoreSnapshotOnNextApplicationLaunch]".
3)
You can also add "UIApplicationExitsOnSuspend" into your app's Info.plist when putting your app into the background, which will kill your app entirely and not save a snapshot.
Apple told us to hide secure info before going to background, so just give it a image to hide everything:
-(void)applicationWillResignActive:(UIApplication *)application
{
if(needToHide){
_imageView = [[UIImageView alloc]initWithFrame:[self.window frame]];
[_imageView setImage:[UIImage imageNamed:#"HideME.png"]];
[self.window addSubview:_imageView];
}
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(_imageView != nil) {
[_imageView removeFromSuperview];
_imageView = nil;
}
}
I'm creating an online-shop-style app where users can browse different products on their iPad and order these products. The ordering process consists of creating an xml-file with the user's data and the relevant products he would like to order. But sometimes there might be the case, that users don't have an internet connection right now and I would like to create some mechanism, which checks every x minutes for an active internet connection and then tries to deliver the order-xml. It should repeat this step until it gets connected to the web and then just stop it, when all offline carts have been sent.
I have already been searching the web but only found ways to do this on iOS 7 (with UIBackgroundModes - fetch). But I don't want to use iOS 7 because the app is already done and I'm not planning to redesign it for iOS 7 (it's an Enterprise App). As far as I know, the current Background Execution time on iOS 6 is limited to something like 15 minutes, is that correct?
Any ideas on how to solve that?
Thanks.
EDIT:
I have tried the following in - (void)applicationDidEnterBackground:(UIApplication *)application
self.queue = [[NSOperationQueue alloc] init];
[self.queue addOperationWithBlock:^{
[[InstanceHolder getInstance] startNetworkTimer];
}];
and here is what should happen next:
- (void) startNetworkTimer{
if ([CommonCode getAllOfflineCartsForClient:nil].count > 0){
NSTimer *pauseTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(offlineCartLoop:) userInfo:nil repeats:YES];
}
}
- (void) offlineCartLoop:(id)sender{
if([CommonCode isInternetConnectionAvailable]){
[self sendOfflineCarts];
[sender invalidate];
}
}
startNetworkTimer gets called as it should, but then it doesn't call the offlineCartLoop function :-(
EDIT 2:
I think the timer-thing was the problem. I'm now calling the offlineCartLoop function like this:
self.queue = [[NSOperationQueue alloc] init];
[self.queue addOperationWithBlock:^{
[[InstanceHolder getInstance] offlineCartLoop:nil];
}];
and changed the offlineCartLoop function to this:
- (void) offlineCartLoop:(id)sender{
if([CommonCode isInternetConnectionAvailable]){
[self sendOfflineCarts];
}else{
[NSThread sleepForTimeInterval:10.0];
[self offlineCartLoop:nil];
}
}
Seems to work, but will this run forever? Is there anything else I need to take care of?
There is no solution to what you want - there is no such thing as being able to periodically check every N minutes in the background unless it is within the time window granted by beginBackgroundTaskWithExpirationHandler.
However that only permits 10 minutes of execution time for iOS6 and earlier, or approximately 3 minutes for iOS7.
You cannot cheat and try and use a background mode if your app does not need it, and even the background modes do not permit you to freely run whenever you want.
Even the new background modes in iOS 7 do not permit you to run on a scheduled basis.
Your best best actually is iOS7 even though you don't want to migrate to iOS7 - the background fetch being the relevant mode (even though you are pushing not fetching). With that background mode you will be able to have the opportunity to execute but not when you decide, only when the OS decides - and the frequency of that depends upon how the user uses your app.
With iOS6 your options are even less restricted.
See iOS: Keep an app running like a service
Basically there just is no such thing as continuous background execution, nor periodic background execution, nor the app deciding when it wants to run when in the background.
If the user does not have an internet connection at the time they use your app to place the order then you should be notifying them of that anyway (if you don't then your app risks rejection from the app store) and maybe tell them to try again later.
If they are in flight mode the user will know they are in flight mode, if there is a temporary interruption (such as the phone is in an elevator or tunnel) then your app could keep on trying for as long as it is able - keep trying every minute while in the foreground, then when you switch to the background you know you have 10 minutes left, keep trying until the 10 minutes has nearly expired then post a local notification to the user notifying them that the app was unable to place the order due to lack of connectivity. If the user clicks on the notification and your app launches then the app will have the chance to retry again at that point.
If you still cannot make a connection then so be it, but you will have the chance to start the retry algorithm again. But at least you have notified the user their order has not gone through.
If what you need to know is if and when a data connection is available, I recommend inverting the process: rather then querying for a data connection, let your app be notified when a data connection is available. It's more efficient.
On this subject, I suggest using Reachability: you can make a call to know if a specific URL is accessible, and execute a block of code as soon as a connection is available.
Reachability *reach = [Reachability reacabilityWithHostName:#"www.myservice.com"];
...
reach.reachableBlock = ^(Reachability *reach) {
// Process the requests queue
// You should implement the method below
[self processQueue];
}
...
if ([reach isReachable]) {
// Upload the XML file to the server
// You should implement the method below
[self uploadToServer:myRequest];
} else {
// Enqueue your request somewhere, for example into an NSArray
// You should implement the method below
[self addToQueue:myRequest];
}
The above code is meant to be a showcase (it doesn't work as is), use it as reference. I can just say that the reach variable should be a class property or data member, and that it should be initialized once.
Also, if you enqueue your requests into an NSArray, be sure to do it in thread safe mode
Alternatively, Reachability can also notify via NSNotification when a connection is available - a different way to achieve the same result. Up to you to decide which one better fits with your needs.
I have a application running in background and I need to know if device is sleeping in order to start a sincronisation process, but I didn't find information about this.
Does anyone know if it is posible and how do it?
Thanks.
You cannot know if the device is asleep because you have no control over the OS.
You can, otherwise, use the App Delegate method:
- (void)applicationWillResignActive:(UIApplication *)application
{
//your code goes here
}
if you want to wait till your app goes to background
I believe you can't do this using public API. The only thing which you can check whether your application is active or in background (using AppDelegate callbacks). And as Luke pointed out in comments, checking whether device "falls asleep" isn't iOS best design practice.
There are some private API's to do what you want, you can look at following questions:
Is there a way to check if the iOS device is locked/unlocked?
Detect screen on/off from iOS service
However, you should be aware that your app won't be accepted in AppStore in such case.
I'm very simply trying to be notified when a Pass is added to a passbook.
One thing to note is that I'm also attempting to use a Pass that I generated using a different apple dev account than what my app is using. I'm trying to figure out if that is part of the problem or not.
This is one VC in a 3-tab application.
ViewController.m:
#interface ViewController ()
{
PKPassLibrary *_passLibrary;
NSArray *_passes;
}
#end
"viewDidLoad":
- (void)viewDidLoad
{
//init passbook
_passLibrary = [[PKPassLibrary alloc] init];
_passes = [_passLibrary passes];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(passLibraryDidChange:) name:PKPassLibraryDidChangeNotification object:_passLibrary];
}
and my notification handler:
- (void)passLibraryDidChange:(NSNotification *)notification
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%#", #"passes added");
});
}
When I run the app in the iOS Simulator, all works as expected and I can see the log output to the console in Xcode.
When I run on the device, the notification is not called when the Pass is added. On the device, I can't even list any passes.
What's even more strange, is that when I go to delete the Pass from passbook, then re-enter the app, the notification will be called.
ps: I really hope it's something simple I'm missing here.
EDIT: updated with more information and a more complete code sample
You don't seem to be retaining a handle to your PKPassLibrary instance. Create a strong #property on your UIViewController subclass. Alloc+Init the property and configure the notification listening in the viewDidLoad (so it'll only get done once).
It might be more appropriate to set this on the UIApplication somewhere, but that depends on the app logic and how your ViewController fits into your UI (for example does it get replaced or released while you still need access to PassKit notifications?)…
Nick.
P.S. Any reason you're NSLogging on the GCD main queue so explicitly? Is that just left over from some UI feedback?
P.P.S. Seeing the notification when you re-enter the app makes perfect sense since that's when viewWillAppear will get called and a new PKPassLibrary instance will immediately fire the notification that's waiting. Not sure why it worked in the simulator - must be accidental.
It came down to having the pass type identifiers created from the same source that the provisioning profile came from.
I then had to take the new Pass Certificates and add them to my keychain, then re-create the actual passes using the new pass type identifiers.
Meanwhile, In Xcode..in the summary section of my target in the Entitlements section, I can refresh the Passes and see the new pass type id's come in.
Once the app runs, I now get properly notified of any change (addition/subtraction/etc).
I also needed to make sure my _passLibrary was being properly retained.