@wisdomgarden/capacitor-plugin-beacon 0.0.2 → 0.0.3
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.
package/CHANGE-LOG.md
CHANGED
|
@@ -3,4 +3,11 @@
|
|
|
3
3
|
### Bug Fixes
|
|
4
4
|
- Fix (Android): Resolved broadcast failure `ADVERTISE_FAILED_DATA_TOO_LARGE`.
|
|
5
5
|
- Fix (Android/iOS): Resolved issue where stale/historical messages were received due to system caching.
|
|
6
|
-
- Optimization: Standardized logToJsWithTag output format and logical sequence `[SEQ-XX]` .
|
|
6
|
+
- Optimization: Standardized logToJsWithTag output format and logical sequence `[SEQ-XX]` .
|
|
7
|
+
|
|
8
|
+
## 0.0.3 (2025-12-23)
|
|
9
|
+
|
|
10
|
+
### Optimize code
|
|
11
|
+
- Logic Optimization: Aligned cross-platform encoding and improved variable-length payload handling.
|
|
12
|
+
- Code Fixes: Resolved naming conflicts and indexing safety issues.
|
|
13
|
+
- Log Refinement: Simplified logs with concise method tags.
|
|
@@ -47,10 +47,9 @@ public class BeaconUtils {
|
|
|
47
47
|
* @return 编码后的字符串
|
|
48
48
|
*/
|
|
49
49
|
public static String encode(int num) {
|
|
50
|
-
if (num
|
|
50
|
+
if (num <= 0) return String.valueOf(CHARS.charAt(0));
|
|
51
51
|
StringBuilder result = new StringBuilder();
|
|
52
|
-
|
|
53
|
-
int n = Math.abs(num);
|
|
52
|
+
int n = num;
|
|
54
53
|
|
|
55
54
|
while (n > 0) {
|
|
56
55
|
int remainder = n % RADIX;
|
|
@@ -58,7 +57,7 @@ public class BeaconUtils {
|
|
|
58
57
|
n /= RADIX;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
return
|
|
60
|
+
return result.toString();
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
/**
|
|
@@ -87,8 +86,7 @@ public class BeaconUtils {
|
|
|
87
86
|
* @return 如果是 nonce 字母返回 true,否则返回 false
|
|
88
87
|
*/
|
|
89
88
|
public static boolean isNonceLetter(char c) {
|
|
90
|
-
|
|
91
|
-
return code >= 84 && code <= 90;
|
|
89
|
+
return c >= 'T' && c <= 'Z';
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
/**
|
|
@@ -120,17 +118,16 @@ public class BeaconUtils {
|
|
|
120
118
|
payload.put("rollcallId", 0);
|
|
121
119
|
payload.put("nonce", "");
|
|
122
120
|
|
|
123
|
-
if (message == null) {
|
|
121
|
+
if (message == null || message.isEmpty()) {
|
|
124
122
|
return payload;
|
|
125
123
|
}
|
|
126
124
|
|
|
127
125
|
for (int i = 0; i < message.length(); i++) {
|
|
128
|
-
|
|
129
|
-
if (isNonceLetter(c)) {
|
|
126
|
+
if (isNonceLetter(message.charAt(i))) {
|
|
130
127
|
String rollcallIdStr = message.substring(0, i);
|
|
131
128
|
payload.put("rollcallId", decode(rollcallIdStr));
|
|
132
129
|
payload.put("nonce", message.substring(i));
|
|
133
|
-
|
|
130
|
+
return payload;
|
|
134
131
|
}
|
|
135
132
|
}
|
|
136
133
|
|
|
@@ -171,25 +168,25 @@ public class BeaconUtils {
|
|
|
171
168
|
*/
|
|
172
169
|
public static String extractMessageFromBytes(byte[] data) {
|
|
173
170
|
if (data == null) {
|
|
174
|
-
Log.w(TAG, "[
|
|
171
|
+
Log.w(TAG, "[extractBytes] data is null");
|
|
175
172
|
return null;
|
|
176
173
|
}
|
|
177
174
|
|
|
178
175
|
// Total length must be: length of WG_PREFIX_BYTES + length of message
|
|
179
176
|
int expectedLength = WG_PREFIX_BYTES.length + MESSAGE_MAX_LENGTH;
|
|
180
177
|
|
|
181
|
-
if (data.length
|
|
182
|
-
Log.w(TAG, "[
|
|
178
|
+
if (data.length < WG_PREFIX_BYTES.length || data.length > expectedLength) {
|
|
179
|
+
Log.w(TAG, "[extractBytes] Length out of bounds. Max: " + expectedLength + ", Got: " + data.length);
|
|
183
180
|
return null;
|
|
184
181
|
}
|
|
185
182
|
for (int i = 0; i < WG_PREFIX_BYTES.length; i++) {
|
|
186
183
|
if (data[i] != WG_PREFIX_BYTES[i]) {
|
|
187
|
-
Log.v(TAG, "[extractMessageFromBytes] Prefix mismatch at byte " + i);
|
|
188
184
|
return null;
|
|
189
185
|
}
|
|
190
186
|
}
|
|
191
|
-
|
|
192
|
-
|
|
187
|
+
int payloadLength = data.length - WG_PREFIX_BYTES.length;
|
|
188
|
+
String extracted = new String(data, WG_PREFIX_BYTES.length, payloadLength, StandardCharsets.US_ASCII);
|
|
189
|
+
Log.i(TAG, "[extractBytes] Successfully extracted message from bytes: " + extracted);
|
|
193
190
|
return extracted;
|
|
194
191
|
}
|
|
195
192
|
|
|
@@ -199,21 +196,20 @@ public class BeaconUtils {
|
|
|
199
196
|
* where the message is prefixed with "WG" and advertised as the device's name.
|
|
200
197
|
*/
|
|
201
198
|
public static String extractMessageFromDeviceName(String message) {
|
|
202
|
-
if (message == null) {
|
|
203
|
-
Log.w(TAG, "[
|
|
199
|
+
if (message == null || message.isEmpty()) {
|
|
200
|
+
Log.w(TAG, "[extractName] message is null");
|
|
204
201
|
return null;
|
|
205
202
|
}
|
|
206
203
|
if (!message.startsWith(WG_PREFIX)) {
|
|
207
|
-
Log.w(TAG, "[extractMessageFromDeviceName] message does not start with prefix.message is " + message);
|
|
208
204
|
return null;
|
|
209
205
|
}
|
|
210
|
-
int
|
|
211
|
-
if (message.length()
|
|
212
|
-
Log.w(TAG, "[
|
|
206
|
+
int expectedLength = WG_PREFIX.length() + MESSAGE_MAX_LENGTH;
|
|
207
|
+
if (message.length() > expectedLength) {
|
|
208
|
+
Log.w(TAG, "[extractName] Length out of bounds. Max: " + expectedLength + ", Got: " + message.length());
|
|
213
209
|
return null;
|
|
214
210
|
}
|
|
215
|
-
String extracted= message.substring(WG_PREFIX.length());
|
|
216
|
-
Log.i(TAG, "[
|
|
211
|
+
String extracted = message.substring(WG_PREFIX.length());
|
|
212
|
+
Log.i(TAG, "[extractName] Successfully. " + extracted);
|
|
217
213
|
return extracted;
|
|
218
214
|
}
|
|
219
215
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
|
|
3
3
|
public struct BeaconUtils {
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
5
|
* 16-bit Bluetooth Short UUID (0x5747)
|
|
6
6
|
* Logic & Rationale:
|
|
7
7
|
* 1. Represents the hex characters for 'WG' (W=0x57, G=0x47).
|
|
@@ -32,14 +32,13 @@ public struct BeaconUtils {
|
|
|
32
32
|
public static let message_max_length = 11
|
|
33
33
|
|
|
34
34
|
private static let chars =
|
|
35
|
-
|
|
35
|
+
"2O9AuFNPDx4gtJwS3ye7l1Mq0dEB5HsaKInikRmLhjpG6b8fzQrCcvo"
|
|
36
36
|
private static let radix = chars.count
|
|
37
37
|
|
|
38
38
|
public static func encode(_ num: Int) -> String {
|
|
39
|
-
if num
|
|
39
|
+
if num <= 0 { return String(chars[chars.startIndex]) }
|
|
40
40
|
var result = ""
|
|
41
|
-
|
|
42
|
-
var n = abs(num)
|
|
41
|
+
var n = num
|
|
43
42
|
|
|
44
43
|
while n > 0 {
|
|
45
44
|
let remainder = n % radix
|
|
@@ -48,7 +47,7 @@ public struct BeaconUtils {
|
|
|
48
47
|
n /= radix
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
return
|
|
50
|
+
return result
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
public static func decode(_ str: String) -> Int {
|
|
@@ -56,8 +55,8 @@ public struct BeaconUtils {
|
|
|
56
55
|
for char in str {
|
|
57
56
|
if let index = chars.firstIndex(of: char) {
|
|
58
57
|
num =
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
num * radix
|
|
59
|
+
+ chars.distance(from: chars.startIndex, to: index)
|
|
61
60
|
} else {
|
|
62
61
|
return 0
|
|
63
62
|
}
|
|
@@ -65,46 +64,29 @@ public struct BeaconUtils {
|
|
|
65
64
|
return num
|
|
66
65
|
}
|
|
67
66
|
|
|
67
|
+
// 检查字符是否为 nonce 字母,T-Z
|
|
68
|
+
func isNonceLetter(_ c: Character) -> Bool {
|
|
69
|
+
return c >= "T" && c <= "Z"
|
|
70
|
+
}
|
|
71
|
+
|
|
68
72
|
public static func parseMessage(_ message: String?) -> [String: Any] {
|
|
69
73
|
var payload: [String: Any] = [
|
|
70
74
|
"rollcallId": 0,
|
|
71
75
|
"nonce": "",
|
|
72
76
|
]
|
|
73
77
|
|
|
74
|
-
guard let message = message else {
|
|
78
|
+
guard let message = message, !message.isEmpty else {
|
|
75
79
|
return payload
|
|
76
80
|
}
|
|
77
81
|
|
|
78
|
-
if message.count < message_max_length {
|
|
79
|
-
return payload
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 检查字符是否为 nonce 字母,T-Z
|
|
83
|
-
func isNonceLetter(_ c: Character) -> Bool {
|
|
84
|
-
let code = c.asciiValue ?? 0
|
|
85
|
-
return code >= 84 && code <= 90
|
|
86
|
-
}
|
|
87
|
-
|
|
88
82
|
for (i, char) in message.enumerated() {
|
|
89
83
|
if isNonceLetter(char) {
|
|
90
|
-
let
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
message.startIndex,
|
|
94
|
-
offsetBy: i
|
|
95
|
-
)
|
|
96
|
-
]
|
|
97
|
-
)
|
|
84
|
+
let splitIndex = message.index(message.startIndex, offsetBy: i)
|
|
85
|
+
|
|
86
|
+
let rollcallIdStr = String(message[..<splitIndex])
|
|
98
87
|
payload["rollcallId"] = decode(rollcallIdStr)
|
|
99
88
|
|
|
100
|
-
let nonceStr = String(
|
|
101
|
-
message[
|
|
102
|
-
message.index(
|
|
103
|
-
message.startIndex,
|
|
104
|
-
offsetBy: i
|
|
105
|
-
)...
|
|
106
|
-
]
|
|
107
|
-
)
|
|
89
|
+
let nonceStr = String(message[splitIndex...])
|
|
108
90
|
payload["nonce"] = nonceStr
|
|
109
91
|
break
|
|
110
92
|
}
|
|
@@ -117,17 +99,16 @@ public struct BeaconUtils {
|
|
|
117
99
|
public static func buildMessage(rollcallId: Int, nonce: String) -> String {
|
|
118
100
|
let rollcallIdStr = encode(rollcallId)
|
|
119
101
|
|
|
120
|
-
guard !nonce.isEmpty
|
|
102
|
+
guard !nonce.isEmpty else {
|
|
121
103
|
return rollcallIdStr + "Z"
|
|
122
104
|
}
|
|
123
105
|
|
|
124
|
-
let remainingChars = String(nonce.dropFirst())
|
|
125
|
-
|
|
126
106
|
let message = rollcallIdStr + nonce
|
|
127
107
|
return message.count > message_max_length
|
|
128
|
-
|
|
108
|
+
? String(message.prefix(message_max_length)) : message
|
|
129
109
|
}
|
|
130
110
|
|
|
111
|
+
|
|
131
112
|
/**
|
|
132
113
|
* Prepends the protocol prefix "WG" to the message string.
|
|
133
114
|
* This is used for iOS advertising, where the identifier is placed in the
|
|
@@ -144,27 +125,28 @@ public struct BeaconUtils {
|
|
|
144
125
|
* length matches the protocol specification before returning the decoded string.
|
|
145
126
|
*/
|
|
146
127
|
public static func extractMessageFromBytes(_ data: Data) -> String? {
|
|
147
|
-
// 2 bytes
|
|
148
|
-
let
|
|
149
|
-
|
|
150
|
-
|
|
128
|
+
// Android Logic: CompanyID(2 bytes) + (Prefix)2 bytes + Msg(11 bytes) = 15
|
|
129
|
+
let minLength = 2 + WG_PREFIX_BYTES.count // 4 bytes
|
|
130
|
+
let maxLength = minLength + message_max_length // 15 bytes
|
|
131
|
+
|
|
132
|
+
guard data.count >= minLength && data.count <= maxLength else {
|
|
133
|
+
print("[extractBytes] Length out of bounds: \(data.count)")
|
|
151
134
|
return nil
|
|
152
135
|
}
|
|
153
136
|
|
|
154
137
|
let bytes = [UInt8](data)
|
|
155
138
|
// Check "WG" magic bytes at index 2 and 3 (after 0xFFFF Company ID)
|
|
156
139
|
guard bytes[2] == WG_PREFIX_BYTES[0], bytes[3] == WG_PREFIX_BYTES[1] else {
|
|
157
|
-
print("[extractMessageFromBytes] Extraction failed: Magic bytes prefix mismatch.")
|
|
158
140
|
return nil
|
|
159
141
|
}
|
|
160
142
|
|
|
161
143
|
let messageData = data.subdata(in: 4..<data.count)
|
|
162
144
|
if let extracted = String(data: messageData, encoding: .ascii) {
|
|
163
|
-
print("[
|
|
145
|
+
print("[extractBytes] Successfully: \(extracted)")
|
|
164
146
|
return extracted
|
|
165
147
|
}
|
|
166
148
|
|
|
167
|
-
print("[
|
|
149
|
+
print("[extractBytes] ASCII error")
|
|
168
150
|
return nil
|
|
169
151
|
}
|
|
170
152
|
|
|
@@ -174,17 +156,15 @@ public struct BeaconUtils {
|
|
|
174
156
|
* where the message is prefixed with "WG" and advertised as the device's name.
|
|
175
157
|
*/
|
|
176
158
|
public static func extractMessageFromDeviceName(_ message: String) -> String? {
|
|
177
|
-
guard
|
|
178
|
-
return nil
|
|
179
|
-
}
|
|
159
|
+
guard message.hasPrefix(WG_PREFIX) else { return nil }
|
|
180
160
|
|
|
181
|
-
let
|
|
182
|
-
if
|
|
183
|
-
let extracted = String(
|
|
184
|
-
print("[
|
|
161
|
+
let maxFullLength = WG_PREFIX.count + message_max_length
|
|
162
|
+
if message.count <= maxFullLength {
|
|
163
|
+
let extracted = String(message.dropFirst(WG_PREFIX.count))
|
|
164
|
+
print("[extractName] Successfully: \(extracted)")
|
|
185
165
|
return extracted
|
|
186
166
|
} else {
|
|
187
|
-
print("[
|
|
167
|
+
print("[extractName] Too long: \(message.count)")
|
|
188
168
|
return nil
|
|
189
169
|
}
|
|
190
170
|
}
|
package/package.json
CHANGED