原文鏈接http://www.lanou3g.com/news_show.php?id=478
如何使用iOS 7的iBeacons來提高你的應用
iBeacons是蘋果在WWDC 2013上有意無意透漏出來的一項重要功能,通過低功耗藍牙(BluetoothLowEnergy)技術進行十分精確的微定位和室內導航,據悉其定位精度可以以釐米計算。
實現iBeacons精準的微定位功能除了需要運行iOS 7且支持BLE的設備外,還需要在室內、店內或者其他公共環境中部署iBeacon基站。當用戶走進信號覆蓋區域內時,用戶就會收到相關的提醒和詢問。以梅西百貨爲例,當用戶走到商場某個店面附近時,安裝了相應app的用戶就會收到由iBeacons基站發出的產品信息或者打折信息。此外,美國職棒大聯盟(MLB)也已經測試使用了iBeacon 技術,蘋果更是在254間Apple Store 裏應用了iBeacon 技術。
對於開發者來說,可以創建一個更加具有交互性的博物館應用,當用戶在博物館內隨意行走時,通過信息提醒用戶某些特別的展覽。技術還可以用作室內導航,比如在地鐵站或者機場這些GPS信號不大好的地方更好地引導用戶。
文章目的有兩個,一是理解iBeacons,二是展示如何在app中使用iBeacons。
Demo
文中所用的demo是我們用來展示如何檢測和處理來自beacon的廣播,但首先我們需要創建另外一款app來擔當beacon的角色--沒有其他功能,只是用來廣播信號。最後,我們將有代表雙方溝通的兩款app。
注意:iBeacons是iOS 7引入的新技術,所以我們需要兩部運行iOS 7並支持BLE的設備,比如iPhone 4S以上設備,iPad mini以及iPad 3以後設備。同時,爲了在設備上部署app,你還需要是蘋果iOS開發者計劃(99美元)成員。
設置:Broadcasting App
beacon廣播的是什麼?它是一個UUID,類似:C293726B-63BF-420A-9D79-92C71F67536A。beacon會不斷地廣播該UUID,並且接收方app會用同樣的UUID檢測信號。
首先在Xcode中創建一個新的Single View Application,
點擊下一步,並給項目命名,你可以輸入“AppCoda”作爲組織名稱,把“com.appcoda”作爲bundle identifier:
下一步爲開啓廣播的按鈕添加圖片。
打開圖片資產庫(images.xcassets),找到資產列表,右鍵點擊並選擇“New Image Set”。
給圖片重新命名爲“BroadcastButton”。選擇圖片後,你會看到兩個spot,一個是用來添加2x圖片,一個是用來添加1x圖片。
把兩個按鈕圖片保存至文件系統,並把“[email protected]”和“BroadcastBtn.png”分別拖至2x spot和1x spot.
在Main.storyboard中,爲了添加一個UIButton按鈕,我們需要把其中一個從右下角的Objects pane中拖至視圖上。
在storyboard中選擇按鈕,並找到屬性面板,取消標題,並把圖片改爲我們之前添加的那個。
把按鈕放置在視圖中間,如下圖:
現在,在視圖中添加UILabel元素,這樣我們就知道app什麼時候廣播。從Objects pane中把一個UILabel元素拖至視圖上。然後,查看尺寸屬性,並把它設置爲居中對齊,寬度爲200。讓它在你的視圖中居中對齊,如下圖:
接下來,通過IBOutlet屬性連接把這個UILabel 添加到viewcontroller對象上。打開輔助編輯器(你也可以使用Xcode interface右上角的幫助編輯器按鈕來做這些)。
確定右窗格中展示的是ViewController.h,然後按着control鍵,點擊uilabel、拖動一條線放到“@interface” 和“@end”行之間。
鬆開鼠標,出現一個彈出對話框,給屬性指定一個名稱--“statusLabel”.
ViewController.h文件應該是這樣的:
@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet UILabel *statusLabel;
@end
現在把廣播按鈕連接至IBAction method handler。在輔助編輯器中,把右面板改爲ViewController.m。按住control鍵,從UIButton拖出一條線放在.m 文件中的“@implementation” 和 “@end”行中間。在彈出對話框中,爲該方法命名爲“buttonClicked”
ViewController.m 文件在結束時會有這個方法:
- (IBAction)buttonClicked:(id)sender {
}
添加需要的框架
在通過Bluetooth進行實際廣播前,我們需要爲項目添加適當的框架。
打開項目設置,滾動至底部。在“Linked Frameworks and Libraries”下點擊“+”按鈕添加CoreBluetooth.framework和CoreLocation.framework.
創建一個UUID
在Mac上打開Launchpad(或者僅打開應用程序文件夾),並打開Terminal app。在Launchpad中,它可能是一個被叫做“Other”的文件夾,圖標如下圖:
打開後,你會看見一個可以鍵入“uuidgen”的窗口,它會輸出一個可供使用的UUID!複製生成的UUID,我們將會用它進行廣播。
Beacon廣播
在ViewController.h中,我們要輸入先前添加的框架。
#import <CoreLocation/CoreLocation.h>
#import <CoreBluetooth/CoreBluetooth.h>
下一步,添加用以廣播的3個以上屬性,這樣你在ViewController.h file中會有4個屬性。
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
@property (strong, nonatomic) CLBeaconRegion *myBeaconRegion;
@property (strong, nonatomic) NSDictionary *myBeaconData;
@property (strong, nonatomic) CBPeripheralManager *peripheralManager;
這裏還有一件事要完成--讓ViewController類遵循“CBPeripheralManagerDelegate”協議,我們可以在class declaration中添加如下代碼
@interface ViewController : UIViewController<CBPeripheralManagerDelegate>
.h file完成後,打開.m file,
在viewDidLoad方法中添加如下代碼(替代我們之前生成的UUID)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Create a NSUUID object
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"A77A1B68-49A7-4DBF-914C-760D07FBB87B"];
// Initialize the Beacon Region
self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
major:1
minor:1
identifier:@"com.appcoda.testregion"];
}
在上邊的代碼中,我們創建了一個新的NSUUID對象。
然後,我們設置了一個CLBeaconRegion,並通過那個UUID進行初始化,major number,minor number 以及identifier。如果你所處的位置內有一大堆數據,major number和minor number就是用來識別你的beacons。在上邊梅西百貨的例子中,每個department會有一個特定的major number--識別一組beacons,在店內,每個beacon會有一個特定的minor number。
通過major number和minor number ,你將能精確識別哪個beacon被獲取了。最後,標識符是該區域唯一的ID。
在之前我們設置的buttonClicked method中,我們添加如下代碼:
- (IBAction)buttonClicked:(id)sender {
// Get the beacon data to advertise
self.myBeaconData = [self.myBeaconRegion peripheralDataWithMeasuredPower:nil];
// Start the peripheral manager
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
queue:nil
options:nil];
}
在上述代碼中,我們調用了“peripheralDataWithMeasuredPower:” ,它可以給我們提供即將進行廣播的beacon data。
第二行代碼啓動了外圍設備管理,並監控Bluetooth的狀態更新。
現在我們需要處理狀態更新方法來檢測Bluetooth何時打開和關閉。所以添加以下委託方法,因爲我們的ViewController類遵照“CBPeripheralManagerDelegate” protocol。
-(void)peripheralManagerDidUpdateState:(CBPeripheralManager*)peripheral
{
if (peripheral.state == CBPeripheralManagerStatePoweredOn)
{
// Bluetooth is on
// Update our status label
self.statusLabel.text = @"Broadcasting...";
// Start broadcasting
[self.peripheralManager startAdvertising:self.myBeaconData];
}
else if (peripheral.state == CBPeripheralManagerStatePoweredOff)
{
// Update our status label
self.statusLabel.text = @"Stopped";
當Bluetooth外圍設備狀態改變時會觸發該方法。所以在該方法中,我們要檢查當前設備處於什麼狀態。如果Bluetooth處於打開狀態,我們將會更新我們的標籤,調用“startAdvertising”方法,並把傳遞beacon data進行廣播。相反,如果Bluetooth處於關閉狀態,我們將會停止廣播。
現在把app部署至設備,打開Bluetooth並點擊按鈕,系統就會廣播你的UUID!現在我們要創建一個接收方的app來檢測和處理廣播。
注意:模擬器不能使用Bluetooth,所以不能通過模擬器進行廣播。爲了把app部署至支持BLE的真實設備上(iPhone 4S and up, iPad mini and iPad 3 and up),你需要加入蘋果開發者計劃。
檢測Beacon
設置另一個Single View Application,並命名爲“BeaconReceiver”
打開Main.storyboard,在view中添加單個UILabel,當檢測到用來更新狀態--當檢測到detected時。從 Objects pane中拖放一個UILable元素至你的視圖中。然後點擊UILable,打開屬性面板改爲居中對齊,並把寬度改爲200,如下圖:
添加CoreLocation框架
CoreLocation框架已經更新以支持beacon檢測,我們需要把它添加在我們項目中。打開項目屬性並點擊“Linked Libraries and Frameworks”下的“+”圖標。添加CoreLocation框架
現在,像之前那樣,通過IBOutlet屬性連接來添加UILabel。打開輔助編輯器,確保ViewController.h位於右邊窗格。按下“control”鍵並點擊UILabel,拖出一條線並放在 “@interface” 和 “@end”行之間。放開後,出現一個彈出對話框,你可以給屬性命名爲“statusLabel”。
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
@end
最後打開ViewController.h,在文件頂部添加該框架,並調整類聲明使之遵從CLLocationManagerDelegate協議,該協議包含一個delegate method,可以讓我們知道最新監測到的beacons。
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface ViewController : UIViewController<CLLocationManagerDelegate>
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
@end
監測Beacons
我們需要添加兩個屬性,一個是保持對beacon region(我們即將進行檢測)的跟蹤;另一個是保存locationmanager,它會更新發現的beacons,在ViewController.h添加以下代碼:
@interface ViewController : UIViewController<CLLocationManagerDelegate>
@property (strong, nonatomic) CLBeaconRegion *myBeaconRegion;
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
@end
現在打開ViewController.m,在“viewDidLoad” 方法中,我們將要初始化locationManager,把我們設置爲它的委託。我們也將開始監控想要的beacon,so have that UUID handy!
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Initialize location manager and set ourselves as the delegate
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Create a NSUUID with the same UUID as the broadcasting beacon
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"A77A1B68-49A7-4DBF-914C-760D07FBB87B"];
// Setup a new region with that UUID and same identifier as the broadcasting beacon
self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
identifier:@"com.appcoda.testregion"];
// Tell location manager to start monitoring for the beacon region
[self.locationManager startMonitoringForRegion:self.myBeaconRegion];
}
在第7和第8行代碼中,我們把locationManager初始化爲CLLocationManager的新實例,然後把我們設置爲它的委託,這樣當更新時就會通知我們。
在11行中,我們通過同樣的UUID設置了NSUUID對象,作爲一個被app(先前創建的那個)廣播的對象。
最後我們把region傳遞給location manager 以便於監視。
下一步,我們需要執行一些委託方法,當region被檢測時將會調用該方法。
首先,在ViewController.m中添加如下代碼:
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion*)region
{
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
-(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion*)region
{
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
self.beaconFoundLabel.text = @"No";
}
上邊代碼執行了兩個方法,當設備進入區域或者離開區域時會被調用。當區域被檢測,我們通知locationManager開始尋找區域內的beacons。
現在執行這個方法
-(void)locationManager:(CLLocationManager*)manager
didRangeBeacons:(NSArray*)beacons
inRegion:(CLBeaconRegion*)region
{
// Beacon found!
self.statusLabel.text = @"Beacon found!";
CLBeacon *foundBeacon = [beacons firstObject];
// You can retrieve the beacon data from its properties
//NSString *uuid = foundBeacon.proximityUUID.UUIDString;
//NSString *major = [NSString stringWithFormat:@"%@", foundBeacon.major];
//NSString *minor = [NSString stringWithFormat:@"%@", foundBeacon.minor];
}
當一個或者更多beacons被檢測時,該方法將會被失效。在上述代碼中,你可以看到我們如何獲得UUID,來自beacon的major和minor數據。另外,雖然我們上邊並未執行,但你可以遍歷beacons array,並通過檢測近距離的beacon屬性來決定哪一個是最近的。
運行demo
如果你有兩臺iOS真機,並且你已經加入了蘋果iOS開發者計劃,那你就可以對該技術進行測試。發佈beacon app和點擊“Broadcast”按鈕,然後等待“Broadcasting…”信息出現。發佈receiver app,並讓它遠離broadcasting beacon,然後走近它模仿實際進入beacon區域。
總結
如果你沒有多臺設備,你可以通過購買BLE beacons並把他們放在房子周圍來創建很酷的app。 Estimote makes such beacons and you get three for $99.
所以我希望你能明白iBeacons應用的強大之處,我也希望這個demo能點燃你對真實世界的想象。你可以下載在此下載demo app的Xcode項目。