總結
1.iOS 7.0及以后的版本開始支持iBeacon。
2.硬件方面, iPhone4S 及以后, ipad 3代及以后, ipad Mini及以后, ipod 5及以后。
3.iOS7.1與7.0的提升在于, ios 7.1在應用被kill掉后, 以及設備重啟后, 仍然能繼續監控iBeacon的邊緣觸發及點亮觸發行為,而ios7.0在程序被kill掉后以及設備重啟后不再進行監控
4.通過iBeacon喚醒的應用,只會在后臺運行10秒鐘,當然也可以通過beginBackgoundTask來執行一些需要長時間執行的任務, 不管應用之前是處于后臺, 還是被kill掉, 10秒內,應用的狀態就是在后臺運行。 10秒后, 理論上講程序仍然是處于后臺運行, 但這個時候也可能會因為系統資源的原因而直接把程序再次kill掉。
5.ios7.1版本及以后,要進行后臺及kill掉仍然可以監控,需要用戶把藍牙打開,后臺應用應用程序刷新功能打開,以及定位服務中該應用的定位功能打開(不打開這個功能將不能進行iBeacon 的didRange方法的回調)
6.didEnter和didExit的調用是以uuid為單位來觸發的, 因為iBeacon可以有相同的uuid, 不同的major和不同的minor。 如果A,B是兩個相同uuid, major和minor不同的兩個iBeacon設備,用戶從A區域走到B區域,不會引發didEnter和didExit事件。
7.而且測試發現iBeacon的didEnter和didExit的調用并不準確。因為在同一秒內出現了先調didExit然后又調用了didEnter方法, 所以這兩個方法存在不可靠性。
8.好的方法應該是依賴于didRange來進行beacon的統計與代碼調用, 因為系統只要喚醒后就會調用didRange。 在didRange中可以取當前系統的狀態,以過濾掉應用在前臺的情況。
9.點亮屏幕喚起應用的行為需要在點亮的那個時刻,用戶周圍能檢測到ibeacon設備, 否則不會觸發喚醒應用的操作。
10.進入區域來喚醒應用,則說明周圍一定有iBeacon設備, 退出區域來喚醒應用,喚醒時周圍可以沒有iBeacon設備。進入區域和退出區域事件均能喚醒應用。
11.ibeacon的邊緣觸發可以是ios設備在移動,也可以是ibeacon設備在移動。
12.直接在ios程序中使用藍牙功能進行ibeacon設備的掃描, 如果此時藍牙處于關閉狀態, 則會彈出提示, 提示用戶:"打開藍牙來允許“XXX應用“連接到配件"提示, 相信不少用戶看到這個提示都會比較擔心這是一個什么樣的應用。 所以最好的辦法是, 在程序中使用ibeacon, 如果ibeacon能使用, 則藍牙功能必然處于打開狀態,如果ibeacon不能使用, 先判斷后臺刷新是否打開, 以及用戶是否授權, 如果沒有問題, 則有可能是因為藍牙沒有打開。 但是不能確定一定就是藍牙沒打開。
13.測試ibeacon離開的區域只需約15米即可, 最好是有障礙物, 不能直接讓手機與ibeacon相互可見即可。
14.如果不需要把當前ios設備模擬成iBeacon設備,是不需要打開Target的background mode并進行設置的。(網上好些文章什么都沒有解釋,直接告訴要打開這個,然后再設置bluetooth啥的,以及location update等。打開這個會導致程序在按下Home鍵后,進入后臺會繼續運行好長一段時間,測試發現最長可以運行25分鐘左右。這樣的應用,蘋果如果審得較嚴的情況下,比較難以通過審核。)
UIAppDelegate
import UIKit
import CoreLocation
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate ,CLLocationManagerDelegate{
let manager = CLLocationManager()
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.backgroundColor = UIColor.whiteColor()
let na = UINavigationController(rootViewController: ViewController())
window?.rootViewController = na
manager.delegate = self
return true
}
//進入監控
func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region.isKindOfClass(CLBeaconRegion) {
let no = UILocalNotification()
no.alertBody = "歡迎光臨"
no.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().scheduleLocalNotification(no)
}
}
//離開監控
func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
if region.isKindOfClass(CLBeaconRegion) {
let no = UILocalNotification()
no.alertBody = "歡迎再來"
no.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().scheduleLocalNotification(no)
}
}
}
ViewController
import UIKit
import CoreLocation
class ViewController: UIViewController {
var beaconRegion :CLBeaconRegion?
let manager = CLLocationManager()
// let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(label)
/**設置代理
*/
manager.delegate = self
//Always會提示用戶授權訪問位置服務 —— 當然如果他們已經授權,系統的提示就不會出現。Always(始終) 和 When in Use(使用應用程序期間) 是 iOS 8 中位置服務權限的新形式。如果用戶給應用程序授權了 Always(始終) ,那無論是前臺還是后臺運行,應用程序都調用任何可用的位置服務。
manager.requestAlwaysAuthorization()
title = "么么噠"
}
//MARK:懶加載
private lazy var label: UILabel = {
let label = UILabel(frame: CGRect(x: 60, y: 150, width: 200, height: 100))
label.backgroundColor = UIColor.cyanColor()
label.numberOfLines = 0
return label
}()
}
extension ViewController: CLLocationManagerDelegate{
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == CLAuthorizationStatus.AuthorizedAlways {
startMonitoring()
}
}
//開始監控
func startMonitoring(){
beaconRegion = CLBeaconRegion(proximityUUID: NSUUID(UUIDString: "")!, major: 1, minor: 1, identifier: "code")
manager.startMonitoringForRegion(beaconRegion!)
manager.startRangingBeaconsInRegion(beaconRegion!)
NSUserDefaults.standardUserDefaults().setObject(1, forKey: "beaconAwakening")
}
//位置管理器失敗
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
}
// 監控失敗
func locationManager(manager: CLLocationManager, monitoringDidFailForRegion region: CLRegion?, withError error: NSError) {
}
//監控范圍內的beacon
通過iBeacon喚醒的應用,只會在后臺運行10秒鐘,當然也可以通過beginBackgoundTask來執行一些需要長時間執行的任務,不管應用之前是處于后臺, 還是被kill掉, 10秒內,應用的狀態就是在后臺運行。
10秒后, 理論上講程序仍然是處于后臺運行, 但這個時候也可能會因為系統資源的原因而直接把程序再次kill掉。
func locationManager(manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], inRegion region: CLBeaconRegion) {
// // 在這里可以獲取當前系統的狀態,以過濾掉應用在前臺的情況,ibeacon喚醒手機,手機也是處于后臺狀態
//為了保持后臺長時間運行,開始后臺任務,but,可能會被蘋果拒絕
myTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
//后臺任務到期執行
})
// 關閉后臺任務
UIApplication.sharedApplication().endBackgroundTask(myTask!)
myTask = UIBackgroundTaskInvalid
for beacon in beacons {
WLLog("\(beacon)")
}
for beacon in beacons {
label.text = "proximity:\(nameForProximity(beacon.proximity))RSSI:\(beacon.rssi) 距離:\(beacon.accuracy)"
}
}
func nameForProximity(proximity: CLProximity) ->String{
switch proximity {
case CLProximity.Unknown:
return "Unknown"
case CLProximity.Far:
return "Far"
case CLProximity.Near:
return "Near"
case CLProximity.Immediate:
return "Immediate"
}
}
}
Info.plist
打開 Info.plist
并點擊Information Property List
這一行上的 + 來添加一項
Key: NSLocationAlwaysUsageDescription
Type: String
Value:"SLC需要獲取你的位置信息用于開門"