Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ SJOPaperboy
An easy to use library that lets you implement background updates in your app that run
whenever the user enters or exits a specified location.

![SJOPaperboyViewController](https://raw.github.com/blork/SJOPaperboy/master/screenshot.png)
![SJOPaperboyViewController](screenshot.png)


Dependancies
Expand Down
11 changes: 11 additions & 0 deletions SJOPaperboyExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
22261C0516D1153C00AD9271 /* IPInsetLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 22261C0316D1153C00AD9271 /* IPInsetLabel.m */; };
22261C0716D1156100AD9271 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22261C0616D1156100AD9271 /* CoreLocation.framework */; };
22261C0916D1156600AD9271 /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22261C0816D1156600AD9271 /* AddressBookUI.framework */; };
F43CAE9716DD031600532F0F /* SJOReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = F43CAE9616DD031600532F0F /* SJOReachability.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
F43CAE9916DD044700532F0F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F43CAE9816DD044700532F0F /* SystemConfiguration.framework */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -47,13 +49,17 @@
22261C0416D1153C00AD9271 /* IPInsetLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IPInsetLabel.h; sourceTree = "<group>"; };
22261C0616D1156100AD9271 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; };
22261C0816D1156600AD9271 /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; };
F43CAE9516DD031600532F0F /* SJOReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SJOReachability.h; sourceTree = "<group>"; };
F43CAE9616DD031600532F0F /* SJOReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SJOReachability.m; sourceTree = "<group>"; };
F43CAE9816DD044700532F0F /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
22261BD816D1150300AD9271 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F43CAE9916DD044700532F0F /* SystemConfiguration.framework in Frameworks */,
22261C0916D1156600AD9271 /* AddressBookUI.framework in Frameworks */,
22261C0716D1156100AD9271 /* CoreLocation.framework in Frameworks */,
22261BDF16D1150300AD9271 /* UIKit.framework in Frameworks */,
Expand Down Expand Up @@ -85,6 +91,7 @@
22261BDD16D1150300AD9271 /* Frameworks */ = {
isa = PBXGroup;
children = (
F43CAE9816DD044700532F0F /* SystemConfiguration.framework */,
22261C0816D1156600AD9271 /* AddressBookUI.framework */,
22261C0616D1156100AD9271 /* CoreLocation.framework */,
22261BDE16D1150300AD9271 /* UIKit.framework */,
Expand Down Expand Up @@ -129,6 +136,8 @@
22261BFC16D1152300AD9271 /* SJOPaperboyViewController.h */,
22261BFD16D1152300AD9271 /* SJOPaperboyLocationManager.m */,
22261BFE16D1152300AD9271 /* SJOPaperboyLocationManager.h */,
F43CAE9516DD031600532F0F /* SJOReachability.h */,
F43CAE9616DD031600532F0F /* SJOReachability.m */,
);
name = Paperboy;
sourceTree = "<group>";
Expand Down Expand Up @@ -205,6 +214,7 @@
22261C0016D1152300AD9271 /* SJOPaperboyViewController.m in Sources */,
22261C0116D1152300AD9271 /* SJOPaperboyLocationManager.m in Sources */,
22261C0516D1153C00AD9271 /* IPInsetLabel.m in Sources */,
F43CAE9716DD031600532F0F /* SJOReachability.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -319,6 +329,7 @@
22261BFA16D1150300AD9271 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
Expand Down
1 change: 1 addition & 0 deletions SJOPaperboyExample/Paperboy.strings
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"region_monitoring_not_available_cancel" = "Okay";

"background_updates" = "Background Updates";
"mobile_updates" = "Use Mobile Data";
"getting_location" = "Getting Location...";
"add_location" = "Add Current Location";
"clear_locations" = "Clear Locations";
51 changes: 50 additions & 1 deletion SJOPaperboyExample/SJOPaperboyLocationManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
//

#import "SJOPaperboyLocationManager.h"
#import "SJOPaperboyViewController.h"
#import "SJOReachability.h"

@interface SJOPaperboyLocationManager (){
UIBackgroundTaskIdentifier backgroundTask;
}

@property (nonatomic, strong) SJOReachability *wifiReachability;
@end

@implementation SJOPaperboyLocationManager

Expand All @@ -17,6 +26,8 @@ - (id)init
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
backgroundTask = UIBackgroundTaskInvalid;
self.wifiReachability = [SJOReachability reachabilityForLocalWiFi];
}
return self;
}
Expand Down Expand Up @@ -65,9 +76,47 @@ -(void)locationChanged
}
}

if (self.locationChangedBlock) {
if ([self canCallLocationChangedBlock]) {
self.locationChangedBlock();
} else {
// Start a Reachability notifier to let us know when we're back on wifi
[self.wifiReachability startNotifier];

__weak SJOPaperboyLocationManager *weakSelf = self;
id observer = nil;
observer = [[NSNotificationCenter defaultCenter] addObserverForName:kSJOReachabilityChangedNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
// This will be called when we're back on wifi
[weakSelf.wifiReachability stopNotifier];
[[NSNotificationCenter defaultCenter] removeObserver:observer];
weakSelf.locationChangedBlock();
}];
if (backgroundTask == UIBackgroundTaskInvalid){
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[weakSelf.wifiReachability stopNotifier];
[[NSNotificationCenter defaultCenter] removeObserver:observer];

[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
}];
}
}
}

- (BOOL) canCallLocationChangedBlock
{
BOOL requiresWifi = ![SJOPaperboyViewController isMobileUpdatingEnabled];
BOOL isOnWifi = ([self.wifiReachability currentReachabilityStatus] == ReachableViaWiFi);

BOOL canUpdate = YES;

if (requiresWifi && !isOnWifi){
canUpdate = NO;
}

return (self.locationChangedBlock != nil && canUpdate);
}

@end
1 change: 1 addition & 0 deletions SJOPaperboyExample/SJOPaperboyViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

@property (nonatomic, strong) CLLocationManager *locationManager;
+ (BOOL) isBackgroundUpdatingEnabled;
+ (BOOL) isMobileUpdatingEnabled;
+ (NSArray*) locationsForUpdate;

@end
76 changes: 60 additions & 16 deletions SJOPaperboyExample/SJOPaperboyViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#define kBackgroundUpdates @"paperboy_background_updates"
#define kLocations @"paperboy_location_array"
#define kMobileUpdates @"paperboy_mobile_updates"

@interface SJOPaperboyViewController ()

Expand Down Expand Up @@ -108,7 +109,11 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger
{
switch (section) {
case 0:
return 1;
if ([SJOPaperboyViewController isBackgroundUpdatingEnabled]){
return 2;
} else {
return 1;
}
case 1:
return 2;
case 2:{
Expand All @@ -135,21 +140,40 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
switch (indexPath.section) {
case 0:
{
UISwitch* toggleSwitch = [[UISwitch alloc] init];

cell.userInteractionEnabled = [CLLocationManager regionMonitoringAvailable];
toggleSwitch.userInteractionEnabled = [CLLocationManager regionMonitoringAvailable];

toggleSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:kBackgroundUpdates];
cell.accessoryView = toggleSwitch;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = NSLocalizedStringFromTable(@"background_updates", @"Paperboy", nil);
cell.imageView.image = nil;
cell.textLabel.textAlignment = NSTextAlignmentLeft;
cell.textLabel.font = [UIFont boldSystemFontOfSize:16];
cell.textLabel.textColor = [UIColor blackColor];
[toggleSwitch addTarget:self action:@selector(toggleBackgroundUpdates:) forControlEvents:UIControlEventValueChanged];

switch (indexPath.row) {
case 0:
{
UISwitch* toggleSwitch = [[UISwitch alloc] init];

cell.userInteractionEnabled = [CLLocationManager regionMonitoringAvailable];
toggleSwitch.userInteractionEnabled = [CLLocationManager regionMonitoringAvailable];

toggleSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:kBackgroundUpdates];
cell.accessoryView = toggleSwitch;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = NSLocalizedStringFromTable(@"background_updates", @"Paperboy", nil);
cell.imageView.image = nil;
cell.textLabel.textAlignment = NSTextAlignmentLeft;
cell.textLabel.font = [UIFont boldSystemFontOfSize:16];
cell.textLabel.textColor = [UIColor blackColor];
[toggleSwitch addTarget:self action:@selector(toggleBackgroundUpdates:) forControlEvents:UIControlEventValueChanged];
break;
}
case 1:
{
UISwitch* toggleSwitch = [[UISwitch alloc] init];
toggleSwitch.on = [SJOPaperboyViewController isMobileUpdatingEnabled];
cell.accessoryView = toggleSwitch;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = NSLocalizedStringFromTable(@"mobile_updates", @"Paperboy", nil);
cell.imageView.image = nil;
cell.textLabel.textAlignment = NSTextAlignmentLeft;
cell.textLabel.font = [UIFont boldSystemFontOfSize:16];
cell.textLabel.textColor = [UIColor blackColor];
[toggleSwitch addTarget:self action:@selector(toggleMobileUpdates:) forControlEvents:UIControlEventValueChanged];
break;
}
}
break;
}
case 1:
Expand Down Expand Up @@ -365,17 +389,31 @@ -(void) toggleBackgroundUpdates:(id)sender
[userDefaults synchronize];

NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 2)];
NSIndexPath *mobileDataIndexPath = [NSIndexPath indexPathForRow:1 inSection:0];

[self.tableView beginUpdates];
if (backgroundUpdatesEnabled) {
self.numberOfSections = 3;
[self.tableView insertRowsAtIndexPaths:@[mobileDataIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView insertSections:indexes withRowAnimation:UITableViewRowAnimationAutomatic];
} else {
self.numberOfSections = 1;
[self.tableView deleteRowsAtIndexPaths:@[mobileDataIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView deleteSections:indexes withRowAnimation:UITableViewRowAnimationAutomatic];
}
[self.tableView endUpdates];

[self updateGeofencedLocations];
}

-(void) toggleMobileUpdates:(id)sender
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
BOOL mobileUpdatesEnabled = ![userDefaults boolForKey:kMobileUpdates];
[userDefaults setBool:mobileUpdatesEnabled forKey:kMobileUpdates];
[userDefaults synchronize];
}

#pragma mark Static helpers

+ (BOOL) isBackgroundUpdatingEnabled
Expand All @@ -397,4 +435,10 @@ + (NSArray*) locationsForUpdate
return [NSArray arrayWithArray:locations];
}

+ (BOOL) isMobileUpdatingEnabled
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
return [userDefaults boolForKey:kMobileUpdates];
}

@end
89 changes: 89 additions & 0 deletions SJOPaperboyExample/SJOReachability.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*

File: Reachability.h
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.

Version: 2.2

Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.

In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under
Apple's copyrights in this original Apple software (the "Apple Software"), to
use, reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions
of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
to endorse or promote products derived from the Apple Software without specific
prior written permission from Apple. Except as expressly stated in this notice,
no other rights or licenses, express or implied, are granted by Apple herein,
including but not limited to any patent rights that may be infringed by your
derivative works or by other works in which the Apple Software may be
incorporated.

The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.

IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Copyright (C) 2010 Apple Inc. All Rights Reserved.

*/


#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>

typedef enum {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} SJONetworkStatus;
#define kSJOReachabilityChangedNotification @"kSJONetworkReachabilityChangedNotification"

@interface SJOReachability: NSObject
{
BOOL localWiFiRef;
SCNetworkReachabilityRef reachabilityRef;
}

//reachabilityWithHostName- Use to check the reachability of a particular host name.
+ (SJOReachability*) reachabilityWithHostName: (NSString*) hostName;

//reachabilityWithAddress- Use to check the reachability of a particular IP address.
+ (SJOReachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;

//reachabilityForInternetConnection- checks whether the default route is available.
// Should be used by applications that do not connect to a particular host
+ (SJOReachability*) reachabilityForInternetConnection;

//reachabilityForLocalWiFi- checks whether a local wifi connection is available.
+ (SJOReachability*) reachabilityForLocalWiFi;

//Start listening for reachability notifications on the current run loop
- (BOOL) startNotifier;
- (void) stopNotifier;

- (SJONetworkStatus) currentReachabilityStatus;
//WWAN may be available, but not active until a connection has been established.
//WiFi may require a connection for VPN on Demand.
- (BOOL) connectionRequired;
@end


Loading