โปรเจคนี้ผมพยายามทำให้แอพสามารถสแกนหาอุปกรณ์ beacon ได้ทั้งตอนที่เปิดแอพอยู่, แอพทำงานใน background mode และขณะที่ไม่ได้เปิดแอพ
ถ้าแอพทำงานใน background mode และขณะที่ไม่ได้เปิดแอพ จะมี Notification เตือนให้รู้เมื่อพบอุปกรณ์ Beacon
ขั้นแรกหลังจากสร้างโปรเจคใหม่ ให้ไปเปิดให้สามารถสแกน Location ใน Background mode ได้ โดยทำตามขั้นตอนนี้
ต่อมาให้เพิ่มข้อมูลการขอสิทธิในการ monitor location ในไฟล์ Info.plist
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App ต้องใช้งาน Location</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>App ต้องใช้งาน Location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>App ต้องใช้งาน Location</string>
import CoreLocation
class VCMain: ... , CLLocationManagerDelegate
lazy var locationManager: CLLocationManager = {
let manager = CLLocationManager()
manager.delegate = self
manager.allowsBackgroundLocationUpdates = true
return manager
}()
lazy var ibeaconRegion:CLBeaconRegion = {
let proximityUUID = UUID(uuidString: beaconUuid)
let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconRegionId)
region.notifyEntryStateOnDisplay = true
region.notifyOnEntry = true
region.notifyOnExit = true
return region
}()
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .restricted, .denied:
// Disable your app's location features
disableLocationServices()
break
case .authorizedAlways:
// Enable any of your app's location services.
self.enableLocationServices()
break
case .notDetermined, .authorizedWhenInUse:
break
}
}
สำหรับกรณีที่สั่งให้เริ่ม monitor แต่มือถืออยู่ใน Region อยู่แล้ว ถ้าไม่ใส่จะไม่ได้รับ didEnterRegion
func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
manager.requestState(for: region)
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
if state == .inside {
manager.startRangingBeacons(in: region as! CLBeaconRegion)
} else {
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region is CLBeaconRegion {
// Start ranging only if the feature is available.
if CLLocationManager.isRangingAvailable() {
manager.startRangingBeacons(in: region as! CLBeaconRegion)
}
}
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
// perform actions when exit region
}
ใน event นี้สามารถขอค่า Major , Minor ออกมาได้
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
if self.ibeaconList.count > 0 && beacons.count <= 0 {
manager.stopRangingBeacons(in: region)
self.ibeaconList = []
self.tableview.reloadData()
return
}
if self.ibeaconList.count == 0 && beacons.count > 0 {
self.performNotification(title: "Found new beacon devices", body: "Tap to view more details")
}
self.ibeaconList = []
for aBeacon in beacons {
let major = Int( CLBeaconMajorValue(truncating: aBeacon.major) )
let minor = Int( CLBeaconMinorValue(truncating: aBeacon.minor) )
var range = ""
switch aBeacon.proximity {
case .immediate:
range = "Range : Immediate"
break
case .near:
range = "Range : Near"
break
case .far:
range = "Range : Far"
break
case .unknown:
range = "Range : Unknown"
break
}
self.ibeaconList.append(IBeaconItem(major: major, minor: minor, range: range))
}
self.tableview.reloadData()
}