iBeacon App Development with CoreLocation on Apple iOS 7/8
来源:互联网 发布:c语言中定义数组 编辑:程序博客网 时间:2024/05/23 19:14
UPDATE (7/2/2014): We've just made a couple of minor changes to the tutorial so it now also works with iOS 8. Specifically, you now need to request Always location authorization, which is covered in the steps below. We've also just added a Swift version of this tutorial.
We're going to do a detailed tutorial of how to build an iBeacon app from scratch on Apple iOS 7, complete with background ranging and notifications. However, before getting started building your app or working through the tutorial, you'll need to complete a few prerequisite tasks:
- Join the Apple iOS developer program
- Install the latest version of XCode
- Provision an iOS device for testing
The basic getting started page from Apple covering these and other topics can be found here, but we'll dive into a little more detail of the various steps to help you get up and running as quickly as possible. Then we'll dive in headfirst to our code tutorial, including how to implement ranging while you're app is in the background.
If you need iBeacon hardware, take a look at our selection. We offer two different iBeacon transmitter modules, both with fast (same-day on orders placed before 3pm eastern time), free first-class shipping from Brooklyn, NY to anywhere in the world! If you don't see what you need, drop us a line at sales@ibeaconmodules.us.
Once you have your hardware, be sure to visit the product pages for simple activation instructions before using your beacons for the first time.
If all this is over your head, but you still have an idea for using iBeacon technology, contact our development team for information and pricing on custom application design and development services.
On the other hand, if you are already all set up with an Apple iOS Developer account and a provisioned device, you can skip to the main tutorial.
Let's get started!
Join Apple iOS Developer Program
The Apple iOS Developer Program gives you access to the necessary tools to build and test iOS applications on physical devices as well as the ability to distribute your applications on the App Store.
You can find an introduction to the program here. Click the "Enroll Now" button to start the enrollment process. Membership costs $99/year and requires a bit of background information about you (and your business if you're starting a business account). It also can take 24 hours for membership to be approved, so it's a good idea to get started on this step right away, even if you haven't yet received your iBeacon transmitter modules.
Install XCode
With the latest releases of Mac OSX, XCode can be easily installed via the Mac App Store. Just install it, or if you previously installed it, be sure that any updates are installed.
Provision Device
Provisioning your device authorizes it to be used on behalf of your Apple iOS Developer Program account to test the applications you build with XCode.
Apple has a step by step walkthrough in the developer library.
You may also find this video helpful:
iBeacon Template Application Tutorial
You can download the template project from GitHub, but sometimes it's more illuminating to walk through the steps yourself:
1. Create the project
Create a new project in XCode using the "Single View Application" template.
2. Configure the project options
You can name things whatever you like, but here are the settings we used for the template.
3. Add the CoreLocation framework to the project.
Click on the main project entry in the file browser. Then make sure the General tab is selected. Scroll to the bottom and click the + to add a Linked Framework. Then find CoreLocation.framework in the list, select it, and click the Add button.
4. Configure Background Capabilities
In order to perform background ranging and monitoring and receive notifications, your app needs to register its need to use Location updates and Bluetooth LE accessories in the background. To do this, click the main project entry in the file browser. Then select the Capabilities tab and find Background Modes. Turn the switch ON, and then check Location updates and Uses Bluetooth LE accessories.
5. Define a region to be monitored
For now, we're going to set things up in the -application:didFinishLaunchingWithOptions method in the App Delegate. First, we need to import the header, and then we will set up the UUID for our beacon(s). A UUID is just an identifier that identifies a beacon or set of beacons. Any beacons you buy from us will come with the same UUID. They can be differentiated by another pair of IDs, called major and minor, but we'll get to that at another time. You also need to define an identifier for the region. This will let you distinguish between sets of beacons should your application ever track more than one. For now, the top part of your App Delegate implementation should look like this:
#import "IMAppDelegate.h"#import <CoreLocation/CoreLocation.h>@implementation IMAppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions{ // Override point for customization after application launch. NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString: @"EBEFD083-70A2-47C8-9837-E7B5634DF524"]; NSString *beaconIdentifier = @"iBeaconModules.us"; CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID: beaconUUID identifier:beaconIdentifier]; return YES;}
6. Set up plist entry for LocationAlways
iOS 8 requires special permission for always-on location monitoring, which includes iBeacon ranging. You need to include a specific plist entry that enables iOS to tell the user why you want this permission.
In the file browser under Supporting Files, open Info.plist. Select the top row "Information Property List". Click the small plus sign to Add a Row. Give it the key (in the left column) NSLocationAlwaysUsageDescription. Make sure the type is set to String, and then set its value to whatever string you'd like to use to inform the user when they are prompted for location permissions.
7. Set up CLLocationManager for foreground/background monitoring and ranging
Now we have a region defined, but it won't do anything until we tell the device to monitor it. To do this, we need to create an instance of CLLocationManager and tell it to start monitoring the region we just created. We also need to define a "delegate" which is an object that gets notified whenever something happens with the location manager. We'll just use the App Delegate for now.
We need to modify the .h file for the App Delegate to do a few things. First, we need to import CoreLocation headers. Then we need to declare that the class implements the CLLocationManagerDelegate protocol, and declare a property to hold our CLLocationManager object so that it survives for the entire lifetime of the application. After this, the header (.h) file should look like this:
#import <UIKit/UIKit.h>#import <CoreLocation/CoreLocation.h>@interface IMAppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>@property (strong, nonatomic) UIWindow *window;@property (strong, nonatomic) CLLocationManager *locationManager;@end
Then, back in the implementation (.m) file, we need to create the CLLocationManager instance and tell it to start monitoring the region, start ranging the beacons, and start updating location. All three of these are required to receive range information updates when the app is in the background. After this, -application:didFinishLaunchingWithOptions: should look like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions{ // Override point for customization after application launch. NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString: @"EBEFD083-70A2-47C8-9837-E7B5634DF524"]; NSString *regionIdentifier = @"us.iBeaconModules"; CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID identifier:regionIdentifier]; self.locationManager = [[CLLocationManager alloc] init]; // New iOS 8 request for Always Authorization, required for iBeacons to work! if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [self.locationManager requestAlwaysAuthorization]; } self.locationManager.delegate = self; self.locationManager.pausesLocationUpdatesAutomatically = NO; [self.locationManager startMonitoringForRegion:beaconRegion]; [self.locationManager startRangingBeaconsInRegion:beaconRegion]; [self.locationManager startUpdatingLocation]; return YES;}
8. Define what happens when the region is entered
The device is now monitoring the beacon, but we still haven't told it what to do when it sees it. Because we set our App Delegate as the CLLocationManager instance's delegate back in the previous step, it's going to look for methods here to call when various events happen. You can find a list of methods in theCLLocationManagerDelegate Protocol Reference.
-locationManager:didRangeBeacons:inRegion: looks interesting. Let's tell it to do something. Add the following methods to your App Delegate implementation:
-(void)sendLocalNotificationWithMessage:(NSString*)message { UILocalNotification *notification = [[UILocalNotification alloc] init]; notification.alertBody = message; [[UIApplication sharedApplication] scheduleLocalNotification:notification];}-(void)locationManager:(CLLocationManager *)manager didRangeBeacons: (NSArray *)beacons inRegion:(CLBeaconRegion *)region { NSString *message = @""; if(beacons.count > 0) { CLBeacon *nearestBeacon = beacons.firstObject; switch(nearestBeacon.proximity) { case CLProximityFar: message = @"You are far away from the beacon"; break; case CLProximityNear: message = @"You are near the beacon"; break; case CLProximityImmediate: message = @"You are in the immediate proximity of the beacon"; break; case CLProximityUnknown: return; } } else { message = @"No beacons are nearby"; } NSLog(@"%@", message); [self sendLocalNotificationWithMessage:message];}
When a beacon range is updated, this code looks to see if beacons were found. If there is at least one, the first one is chosen, and depending upon its proximity a message is logged and a local notification is scheduled. The notification will appear once per second when the application is running in the background.
9. Clean up
This will work as is, but let's tidy things up just a bit. Since we've implemented background ranging with background notifications, you'll get a lot of redundant alerts (one per second while the app is in the background), so we should modify things to only alert us when the range changes. First, we need to add a place to store the last proximity reading. Add the following property to the header (.h) file of the App Delegate:
@property CLProximity lastProximity;
Then, back in the implementation (.m) file, add this before the switch statement that handles the proximity reading:
if(nearestBeacon.proximity == self.lastProximity || nearestBeacon.proximity == CLProximityUnknown) { return; } self.lastProximity = nearestBeacon.proximity;
If the proximity hasn't changed or is temporarily unknown, the method returns and doesn't re-alert us.
That's great, but now what happens if we leave the beacon range entirely? The device will keep trying to range beacons that are no longer in range which just wastes power. Luckily, the CLLocationManager will tell us via a different method when we have entered and exit the range, and we can start and stop the more detailed ranging operations accordingly. Add these methods to the App Delegate implementation:
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region { [manager startRangingBeaconsInRegion:(CLBeaconRegion*)region]; [self.locationManager startUpdatingLocation]; NSLog(@"You entered the region."); [self sendLocalNotificationWithMessage:@"You entered the region."];}-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region { [manager stopRangingBeaconsInRegion:(CLBeaconRegion*)region]; [self.locationManager stopUpdatingLocation]; NSLog(@"You exited the region."); [self sendLocalNotificationWithMessage:@"You exited the region."];}
This also logs and alerts us of the system-level region entry/exit.
10. Foreground Display
OK, things are great in background mode, but when the app is foregrounded, all we have is a plain white screen and no indication of what's happening. Let's fix that by adding a UITableView and populating it with information about all of the beacons in range.
Open the Main.storyboard file. Then select the main view to give it focus. Then, in the list in the bottom right (you may need to use the buttons in the top right corner of the screen to open the tray on the right side of the window), find a Table View. Drag it onto the view and position and scale it so that it takes up the entire view except the area taken up by the status bar at the top.
When you're done, it should look like this:
Now open up your View Controller header file (.h) (NOTE: this is NOT the same file you were editing before). In there, we need to declare a property to reference the table view we just created:
@property IBOutlet UITableView *tableView;
Next, open the storyboard file again. Then option-click (or right-click) on the table view you just added. In the context menu that pops up, drag from the little circle to the right of dataSource over to the View Controller entry in the left portion of the storyboard view:
Do the same for delegate and New Referencing Outlet. When you drop the connection for New Referencing Outlet, you'll get a pop-up asking which variable the table view should map to. Select tableView, which matches the name of the property we just created.
Now we need to declare our View Controller to implement the protocols required by the above connections, UITableViewDataSource and UITableViewDelegate. Add them to the declaration of your view controller in the header file, like this:
@interface IMViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
Create a beacons NSArray property in the view controller header file:
@property (strong) NSArray *beacons;
When the beacons are ranged in the app delegate, now we need to pass the array of beacons to the View Controller and tell the table view to update itself. Add the following code to the top of locationManager:didRangeBeacons:inRegion in the App Delegate:
IMViewController *viewController = (IMViewController*)self.window.rootViewController; viewController.beacons = beacons; [viewController.tableView reloadData];
Now we just need to implement -tableView:numberOfRowsInSection: and -tableView:cellForRowAtIndexPath: in our View Controller. These methods are called by the table view so it can update itself with the latest data:
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.beacons.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyIdentifier"]; cell.selectionStyle = UITableViewCellSelectionStyleNone; } CLBeacon *beacon = (CLBeacon*)[self.beacons objectAtIndex:indexPath.row]; NSString *proximityLabel = @""; switch (beacon.proximity) { case CLProximityFar: proximityLabel = @"Far"; break; case CLProximityNear: proximityLabel = @"Near"; break; case CLProximityImmediate: proximityLabel = @"Immediate"; break; case CLProximityUnknown: proximityLabel = @"Unknown"; break; } cell.textLabel.text = proximityLabel; NSString *detailLabel = [NSString stringWithFormat: @"Major: %d, Minor: %d, RSSI: %d, UUID: %@", beacon.major.intValue, beacon.minor.intValue, (int)beacon.rssi, beacon.proximityUUID.UUIDString]; cell.detailTextLabel.text = detailLabel; return cell; }
There's a very good explanation of the table view functionality in this Stack Overflow answer.
Conclusion
Now we've built an iBeacon app that can range beacons in the foreground and background and display the data and push alerts, so we're going to stop there for now. You can also download the entire project from GitHub if you'd rather not build it up piece by piece. I hope this helps you get up and running and hopefully understand a bit more about iBeacon and how it's used with iOS7. If you have questions or feedback on this tutorial, leave us a comment!
If you need iBeacon hardware, take a look at our catalog. We offer a range of iBeacon transmitter modules, all with fast, free domestic shipping within the U.S. If you don't see what you need, drop us a line atsales@ibeaconmodules.us.
- iBeacon App Development with CoreLocation on Apple iOS 7/8
- iBeacon App Development with CoreLocation on Apple iOS 7/8
- Swift based iBeacon App Development with CoreLocation on Apple iOS 7/8
- Apple iOS Development
- iOS Apple Development Document 详解
- Apple Blocked The 41 App URL Scheme on iOS 10
- Build your OWN Apple iBeacon with a Raspberry Pi
- Apple 官方教程:App Development Process
- Memory issues on iOS development
- Apple Development
- HiBeacons——演示iOS 7新的API iBeacon功能的demo app
- IOS CoreLocation
- IOS CoreLocation
- IOS CoreLocation
- IOS-corelocation
- app development with static initialization opencv
- Working with Apple’s App Transport Security
- iOS 定位 <CoreLocation/CoreLocation.h>
- 阿里一面(电话面试)
- UNIX环境编程学习——反思认识
- 执行root.sh 提示Deconfigure the existing cluster configuration before starting
- HDOJ 18岁生日 (水)
- 立博宣言
- iBeacon App Development with CoreLocation on Apple iOS 7/8
- 150723培训心得(queue)
- mac下安装xampp后mysql无法启动的问题
- rails join left结合使用
- pulltorefreshlistview显示最开始一页时有时不显示的问题解决
- 自定义互斥变量
- 脏读、不可重复读 共享锁、悲观锁 和 事务五种隔离级别
- Jsr181HandlerMapping
- 时间不同步问题导致hive 只能select* 不能select count(*)select 某个字段 ,是因