@capgo/capacitor-ibeacon 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,234 @@
1
+ import Foundation
2
+ import CoreLocation
3
+ import CoreBluetooth
4
+
5
+ public class CapacitorIbeacon: NSObject, CLLocationManagerDelegate, CBPeripheralManagerDelegate {
6
+ private var locationManager: CLLocationManager!
7
+ private var peripheralManager: CBPeripheralManager!
8
+ private weak var plugin: CapacitorIbeaconPlugin?
9
+ private var monitoredRegions: [String: CLBeaconRegion] = [:]
10
+ private var rangedRegions: [String: CLBeaconRegion] = [:]
11
+
12
+ public override init() {
13
+ super.init()
14
+ locationManager = CLLocationManager()
15
+ locationManager.delegate = self
16
+ peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
17
+ }
18
+
19
+ public func setPlugin(_ plugin: CapacitorIbeaconPlugin) {
20
+ self.plugin = plugin
21
+ }
22
+
23
+ public func startMonitoringForRegion(identifier: String, uuid: String, major: Int?, minor: Int?, completion: @escaping (Result<Void, Error>) -> Void) {
24
+ guard let beaconUUID = UUID(uuidString: uuid) else {
25
+ completion(.failure(NSError(domain: "CapacitorIbeacon", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid UUID"])))
26
+ return
27
+ }
28
+
29
+ let beaconRegion: CLBeaconRegion
30
+ if let major = major {
31
+ if let minor = minor {
32
+ beaconRegion = CLBeaconRegion(uuid: beaconUUID, major: CLBeaconMajorValue(major), minor: CLBeaconMinorValue(minor), identifier: identifier)
33
+ } else {
34
+ beaconRegion = CLBeaconRegion(uuid: beaconUUID, major: CLBeaconMajorValue(major), identifier: identifier)
35
+ }
36
+ } else {
37
+ beaconRegion = CLBeaconRegion(uuid: beaconUUID, identifier: identifier)
38
+ }
39
+
40
+ beaconRegion.notifyEntryStateOnDisplay = true
41
+ beaconRegion.notifyOnEntry = true
42
+ beaconRegion.notifyOnExit = true
43
+
44
+ monitoredRegions[identifier] = beaconRegion
45
+ locationManager.startMonitoring(for: beaconRegion)
46
+ completion(.success(()))
47
+ }
48
+
49
+ public func stopMonitoringForRegion(identifier: String, uuid: String) {
50
+ if let region = monitoredRegions[identifier] {
51
+ locationManager.stopMonitoring(for: region)
52
+ monitoredRegions.removeValue(forKey: identifier)
53
+ }
54
+ }
55
+
56
+ public func startRangingBeaconsInRegion(identifier: String, uuid: String, major: Int?, minor: Int?, completion: @escaping (Result<Void, Error>) -> Void) {
57
+ guard let beaconUUID = UUID(uuidString: uuid) else {
58
+ completion(.failure(NSError(domain: "CapacitorIbeacon", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid UUID"])))
59
+ return
60
+ }
61
+
62
+ let beaconRegion: CLBeaconRegion
63
+ if let major = major {
64
+ if let minor = minor {
65
+ beaconRegion = CLBeaconRegion(uuid: beaconUUID, major: CLBeaconMajorValue(major), minor: CLBeaconMinorValue(minor), identifier: identifier)
66
+ } else {
67
+ beaconRegion = CLBeaconRegion(uuid: beaconUUID, major: CLBeaconMajorValue(major), identifier: identifier)
68
+ }
69
+ } else {
70
+ beaconRegion = CLBeaconRegion(uuid: beaconUUID, identifier: identifier)
71
+ }
72
+
73
+ rangedRegions[identifier] = beaconRegion
74
+ locationManager.startRangingBeacons(in: beaconRegion)
75
+ completion(.success(()))
76
+ }
77
+
78
+ public func stopRangingBeaconsInRegion(identifier: String, uuid: String) {
79
+ if let region = rangedRegions[identifier] {
80
+ locationManager.stopRangingBeacons(in: region)
81
+ rangedRegions.removeValue(forKey: identifier)
82
+ }
83
+ }
84
+
85
+ public func startAdvertising(uuid: String, major: Int, minor: Int, identifier: String, measuredPower: Int?, completion: @escaping (Result<Void, Error>) -> Void) {
86
+ guard let beaconUUID = UUID(uuidString: uuid) else {
87
+ completion(.failure(NSError(domain: "CapacitorIbeacon", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid UUID"])))
88
+ return
89
+ }
90
+
91
+ let beaconRegion = CLBeaconRegion(uuid: beaconUUID, major: CLBeaconMajorValue(major), minor: CLBeaconMinorValue(minor), identifier: identifier)
92
+
93
+ if let power = measuredPower {
94
+ peripheralManager.startAdvertising(beaconRegion.peripheralData(withMeasuredPower: NSNumber(value: power)) as? [String: Any])
95
+ } else {
96
+ peripheralManager.startAdvertising(beaconRegion.peripheralData(withMeasuredPower: nil) as? [String: Any])
97
+ }
98
+
99
+ completion(.success(()))
100
+ }
101
+
102
+ public func stopAdvertising() {
103
+ peripheralManager.stopAdvertising()
104
+ }
105
+
106
+ public func requestWhenInUseAuthorization() {
107
+ locationManager.requestWhenInUseAuthorization()
108
+ }
109
+
110
+ public func requestAlwaysAuthorization() {
111
+ locationManager.requestAlwaysAuthorization()
112
+ }
113
+
114
+ public func getAuthorizationStatus() -> String {
115
+ let status = CLLocationManager.authorizationStatus()
116
+ switch status {
117
+ case .notDetermined:
118
+ return "not_determined"
119
+ case .restricted:
120
+ return "restricted"
121
+ case .denied:
122
+ return "denied"
123
+ case .authorizedAlways:
124
+ return "authorized_always"
125
+ case .authorizedWhenInUse:
126
+ return "authorized_when_in_use"
127
+ @unknown default:
128
+ return "unknown"
129
+ }
130
+ }
131
+
132
+ public func isBluetoothEnabled() -> Bool {
133
+ return peripheralManager.state == .poweredOn
134
+ }
135
+
136
+ public func isRangingAvailable() -> Bool {
137
+ return CLLocationManager.isRangingAvailable()
138
+ }
139
+
140
+ // MARK: - CLLocationManagerDelegate
141
+
142
+ public func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
143
+ var beaconsArray: [[String: Any]] = []
144
+
145
+ for beacon in beacons {
146
+ var proximityString = "unknown"
147
+ switch beacon.proximity {
148
+ case .immediate:
149
+ proximityString = "immediate"
150
+ case .near:
151
+ proximityString = "near"
152
+ case .far:
153
+ proximityString = "far"
154
+ case .unknown:
155
+ proximityString = "unknown"
156
+ @unknown default:
157
+ proximityString = "unknown"
158
+ }
159
+
160
+ beaconsArray.append([
161
+ "uuid": beacon.uuid.uuidString,
162
+ "major": beacon.major.intValue,
163
+ "minor": beacon.minor.intValue,
164
+ "rssi": beacon.rssi,
165
+ "proximity": proximityString,
166
+ "accuracy": beacon.accuracy
167
+ ])
168
+ }
169
+
170
+ plugin?.notifyListeners("didRangeBeacons", data: [
171
+ "region": [
172
+ "identifier": region.identifier,
173
+ "uuid": region.uuid.uuidString
174
+ ],
175
+ "beacons": beaconsArray
176
+ ])
177
+ }
178
+
179
+ public func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
180
+ if let beaconRegion = region as? CLBeaconRegion {
181
+ plugin?.notifyListeners("didEnterRegion", data: [
182
+ "region": [
183
+ "identifier": beaconRegion.identifier,
184
+ "uuid": beaconRegion.uuid.uuidString
185
+ ]
186
+ ])
187
+
188
+ plugin?.notifyListeners("didDetermineStateForRegion", data: [
189
+ "region": [
190
+ "identifier": beaconRegion.identifier,
191
+ "uuid": beaconRegion.uuid.uuidString
192
+ ],
193
+ "state": "enter"
194
+ ])
195
+ }
196
+ }
197
+
198
+ public func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
199
+ if let beaconRegion = region as? CLBeaconRegion {
200
+ plugin?.notifyListeners("didExitRegion", data: [
201
+ "region": [
202
+ "identifier": beaconRegion.identifier,
203
+ "uuid": beaconRegion.uuid.uuidString
204
+ ]
205
+ ])
206
+
207
+ plugin?.notifyListeners("didDetermineStateForRegion", data: [
208
+ "region": [
209
+ "identifier": beaconRegion.identifier,
210
+ "uuid": beaconRegion.uuid.uuidString
211
+ ],
212
+ "state": "exit"
213
+ ])
214
+ }
215
+ }
216
+
217
+ public func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
218
+ if let beaconRegion = region as? CLBeaconRegion {
219
+ plugin?.notifyListeners("monitoringDidFailForRegion", data: [
220
+ "region": [
221
+ "identifier": beaconRegion.identifier,
222
+ "uuid": beaconRegion.uuid.uuidString
223
+ ],
224
+ "error": error.localizedDescription
225
+ ])
226
+ }
227
+ }
228
+
229
+ // MARK: - CBPeripheralManagerDelegate
230
+
231
+ public func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
232
+ // Handle Bluetooth state changes if needed
233
+ }
234
+ }
@@ -0,0 +1,159 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import CoreLocation
4
+
5
+ @objc(CapacitorIbeaconPlugin)
6
+ public class CapacitorIbeaconPlugin: CAPPlugin, CAPBridgedPlugin {
7
+ private let PLUGIN_VERSION: String = "0.0.1"
8
+ public let identifier = "CapacitorIbeaconPlugin"
9
+ public let jsName = "CapacitorIbeacon"
10
+ public let pluginMethods: [CAPPluginMethod] = [
11
+ CAPPluginMethod(name: "startMonitoringForRegion", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "stopMonitoringForRegion", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "startRangingBeaconsInRegion", returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: "stopRangingBeaconsInRegion", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "startAdvertising", returnType: CAPPluginReturnPromise),
16
+ CAPPluginMethod(name: "stopAdvertising", returnType: CAPPluginReturnPromise),
17
+ CAPPluginMethod(name: "requestWhenInUseAuthorization", returnType: CAPPluginReturnPromise),
18
+ CAPPluginMethod(name: "requestAlwaysAuthorization", returnType: CAPPluginReturnPromise),
19
+ CAPPluginMethod(name: "getAuthorizationStatus", returnType: CAPPluginReturnPromise),
20
+ CAPPluginMethod(name: "isBluetoothEnabled", returnType: CAPPluginReturnPromise),
21
+ CAPPluginMethod(name: "isRangingAvailable", returnType: CAPPluginReturnPromise),
22
+ CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
23
+ ]
24
+
25
+ private let implementation = CapacitorIbeacon()
26
+
27
+ public override func load() {
28
+ implementation.setPlugin(self)
29
+ }
30
+
31
+ @objc func startMonitoringForRegion(_ call: CAPPluginCall) {
32
+ guard let identifier = call.getString("identifier"),
33
+ let uuid = call.getString("uuid") else {
34
+ call.reject("Missing required parameters")
35
+ return
36
+ }
37
+
38
+ implementation.startMonitoringForRegion(
39
+ identifier: identifier,
40
+ uuid: uuid,
41
+ major: call.getInt("major"),
42
+ minor: call.getInt("minor")
43
+ ) { result in
44
+ switch result {
45
+ case .success:
46
+ call.resolve()
47
+ case .failure(let error):
48
+ call.reject("Failed to start monitoring: \(error.localizedDescription)")
49
+ }
50
+ }
51
+ }
52
+
53
+ @objc func stopMonitoringForRegion(_ call: CAPPluginCall) {
54
+ guard let identifier = call.getString("identifier"),
55
+ let uuid = call.getString("uuid") else {
56
+ call.reject("Missing required parameters")
57
+ return
58
+ }
59
+
60
+ implementation.stopMonitoringForRegion(identifier: identifier, uuid: uuid)
61
+ call.resolve()
62
+ }
63
+
64
+ @objc func startRangingBeaconsInRegion(_ call: CAPPluginCall) {
65
+ guard let identifier = call.getString("identifier"),
66
+ let uuid = call.getString("uuid") else {
67
+ call.reject("Missing required parameters")
68
+ return
69
+ }
70
+
71
+ implementation.startRangingBeaconsInRegion(
72
+ identifier: identifier,
73
+ uuid: uuid,
74
+ major: call.getInt("major"),
75
+ minor: call.getInt("minor")
76
+ ) { result in
77
+ switch result {
78
+ case .success:
79
+ call.resolve()
80
+ case .failure(let error):
81
+ call.reject("Failed to start ranging: \(error.localizedDescription)")
82
+ }
83
+ }
84
+ }
85
+
86
+ @objc func stopRangingBeaconsInRegion(_ call: CAPPluginCall) {
87
+ guard let identifier = call.getString("identifier"),
88
+ let uuid = call.getString("uuid") else {
89
+ call.reject("Missing required parameters")
90
+ return
91
+ }
92
+
93
+ implementation.stopRangingBeaconsInRegion(identifier: identifier, uuid: uuid)
94
+ call.resolve()
95
+ }
96
+
97
+ @objc func startAdvertising(_ call: CAPPluginCall) {
98
+ guard let uuid = call.getString("uuid"),
99
+ let major = call.getInt("major"),
100
+ let minor = call.getInt("minor"),
101
+ let identifier = call.getString("identifier") else {
102
+ call.reject("Missing required parameters")
103
+ return
104
+ }
105
+
106
+ let measuredPower = call.getInt("measuredPower")
107
+
108
+ implementation.startAdvertising(
109
+ uuid: uuid,
110
+ major: major,
111
+ minor: minor,
112
+ identifier: identifier,
113
+ measuredPower: measuredPower
114
+ ) { result in
115
+ switch result {
116
+ case .success:
117
+ call.resolve()
118
+ case .failure(let error):
119
+ call.reject("Failed to start advertising: \(error.localizedDescription)")
120
+ }
121
+ }
122
+ }
123
+
124
+ @objc func stopAdvertising(_ call: CAPPluginCall) {
125
+ implementation.stopAdvertising()
126
+ call.resolve()
127
+ }
128
+
129
+ @objc func requestWhenInUseAuthorization(_ call: CAPPluginCall) {
130
+ implementation.requestWhenInUseAuthorization()
131
+ let status = implementation.getAuthorizationStatus()
132
+ call.resolve(["status": status])
133
+ }
134
+
135
+ @objc func requestAlwaysAuthorization(_ call: CAPPluginCall) {
136
+ implementation.requestAlwaysAuthorization()
137
+ let status = implementation.getAuthorizationStatus()
138
+ call.resolve(["status": status])
139
+ }
140
+
141
+ @objc func getAuthorizationStatus(_ call: CAPPluginCall) {
142
+ let status = implementation.getAuthorizationStatus()
143
+ call.resolve(["status": status])
144
+ }
145
+
146
+ @objc func isBluetoothEnabled(_ call: CAPPluginCall) {
147
+ let enabled = implementation.isBluetoothEnabled()
148
+ call.resolve(["enabled": enabled])
149
+ }
150
+
151
+ @objc func isRangingAvailable(_ call: CAPPluginCall) {
152
+ let available = implementation.isRangingAvailable()
153
+ call.resolve(["available": available])
154
+ }
155
+
156
+ @objc func getPluginVersion(_ call: CAPPluginCall) {
157
+ call.resolve(["version": self.PLUGIN_VERSION])
158
+ }
159
+ }
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@capgo/capacitor-ibeacon",
3
+ "version": "7.0.0",
4
+ "description": "iBeacon plugin for Capacitor - proximity detection and beacon region monitoring",
5
+ "main": "dist/plugin.cjs.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
8
+ "unpkg": "dist/plugin.js",
9
+ "files": [
10
+ "android/src/main/",
11
+ "android/build.gradle",
12
+ "dist/",
13
+ "ios/Sources",
14
+ "ios/Tests",
15
+ "Package.swift",
16
+ "CapgoCapacitorIbeacon.podspec"
17
+ ],
18
+ "author": "Martin Donadieu <martin@capgo.app>",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Cap-go/capacitor-ibeacon.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Cap-go/capacitor-ibeacon/issues"
26
+ },
27
+ "keywords": [
28
+ "capacitor",
29
+ "ibeacon",
30
+ "beacon",
31
+ "bluetooth",
32
+ "ble",
33
+ "proximity",
34
+ "location",
35
+ "ranging",
36
+ "monitoring",
37
+ "plugin",
38
+ "native"
39
+ ],
40
+ "scripts": {
41
+ "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
42
+ "verify:ios": "xcodebuild -scheme CapgoCapacitorIbeacon -destination generic/platform=iOS",
43
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
44
+ "verify:web": "npm run build",
45
+ "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
46
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --autocorrect --format",
47
+ "eslint": "eslint .",
48
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
49
+ "swiftlint": "node-swiftlint",
50
+ "docgen": "docgen --api CapacitorIbeaconPlugin --output-readme README.md --output-json dist/docs.json",
51
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
52
+ "clean": "rimraf ./dist",
53
+ "watch": "tsc --watch",
54
+ "prepublishOnly": "npm run build"
55
+ },
56
+ "devDependencies": {
57
+ "@capacitor/android": "^7.0.0",
58
+ "@capacitor/cli": "^7.0.0",
59
+ "@capacitor/core": "^7.0.0",
60
+ "@capacitor/docgen": "^0.3.0",
61
+ "@capacitor/ios": "^7.0.0",
62
+ "@ionic/eslint-config": "^0.4.0",
63
+ "@ionic/prettier-config": "^4.0.0",
64
+ "@ionic/swiftlint-config": "^2.0.0",
65
+ "@types/node": "^22.13.1",
66
+ "eslint": "^8.57.0",
67
+ "eslint-plugin-import": "^2.31.0",
68
+ "husky": "^9.1.7",
69
+ "prettier": "^3.4.2",
70
+ "prettier-plugin-java": "^2.6.7",
71
+ "rimraf": "^6.0.1",
72
+ "rollup": "^4.34.6",
73
+ "swiftlint": "^2.0.0",
74
+ "typescript": "^5.7.3"
75
+ },
76
+ "peerDependencies": {
77
+ "@capacitor/core": ">=7.0.0"
78
+ },
79
+ "eslintConfig": {
80
+ "extends": "@ionic/eslint-config/recommended"
81
+ },
82
+ "prettier": "@ionic/prettier-config",
83
+ "swiftlint": "@ionic/swiftlint-config",
84
+ "capacitor": {
85
+ "ios": {
86
+ "src": "ios"
87
+ },
88
+ "android": {
89
+ "src": "android"
90
+ }
91
+ }
92
+ }