@wisdomgarden/capacitor-plugin-beacon 0.0.1
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/README.md +117 -0
- package/WisdomgardenCapacitorPluginBeacon.podspec +17 -0
- package/android/build.gradle +52 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/android/gradle.properties +24 -0
- package/android/gradlew +188 -0
- package/android/gradlew.bat +100 -0
- package/android/proguard-rules.pro +21 -0
- package/android/settings.gradle +2 -0
- package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +26 -0
- package/android/src/main/AndroidManifest.xml +20 -0
- package/android/src/main/java/com/wisdomgarden/mobile/beacon/Beacon.java +294 -0
- package/android/src/main/java/com/wisdomgarden/mobile/beacon/BeaconUtils.java +118 -0
- package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
- package/android/src/main/res/values/colors.xml +3 -0
- package/android/src/main/res/values/strings.xml +3 -0
- package/android/src/main/res/values/styles.xml +3 -0
- package/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +18 -0
- package/dist/esm/definitions.d.ts +49 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +25 -0
- package/dist/esm/web.js +61 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.js +70 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/BeaconUtils.swift +103 -0
- package/ios/Plugin/Info.plist +30 -0
- package/ios/Plugin/Plugin.h +10 -0
- package/ios/Plugin/Plugin.m +14 -0
- package/ios/Plugin/Plugin.swift +342 -0
- package/ios/Plugin.xcodeproj/project.pbxproj +556 -0
- package/ios/Plugin.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/ios/Plugin.xcworkspace/contents.xcworkspacedata +10 -0
- package/ios/Plugin.xcworkspace/xcuserdata/peixinliu.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/PluginTests/Info.plist +22 -0
- package/ios/PluginTests/PluginTests.swift +35 -0
- package/ios/Podfile +16 -0
- package/ios/Podfile.lock +22 -0
- package/ios/Pods/Local Podspecs/Capacitor.podspec.json +30 -0
- package/ios/Pods/Local Podspecs/CapacitorCordova.podspec.json +22 -0
- package/ios/Pods/Manifest.lock +22 -0
- package/ios/Pods/Pods.xcodeproj/project.pbxproj +1381 -0
- package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/Capacitor.xcscheme +58 -0
- package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/CapacitorCordova.xcscheme +58 -0
- package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/Pods-Plugin.xcscheme +58 -0
- package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/Pods-PluginTests.xcscheme +58 -0
- package/ios/Pods/Pods.xcodeproj/xcuserdata/peixinliu.xcuserdatad/xcschemes/xcschememanagement.plist +39 -0
- package/ios/Pods/Target Support Files/Capacitor/Capacitor-Info.plist +26 -0
- package/ios/Pods/Target Support Files/Capacitor/Capacitor-dummy.m +5 -0
- package/ios/Pods/Target Support Files/Capacitor/Capacitor-prefix.pch +12 -0
- package/ios/Pods/Target Support Files/Capacitor/Capacitor-umbrella.h +23 -0
- package/ios/Pods/Target Support Files/Capacitor/Capacitor.debug.xcconfig +16 -0
- package/ios/Pods/Target Support Files/Capacitor/Capacitor.modulemap +6 -0
- package/ios/Pods/Target Support Files/Capacitor/Capacitor.release.xcconfig +16 -0
- package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-Info.plist +26 -0
- package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-dummy.m +5 -0
- package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-prefix.pch +12 -0
- package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-umbrella.h +33 -0
- package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.debug.xcconfig +13 -0
- package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.modulemap +6 -0
- package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.release.xcconfig +13 -0
- package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-Info.plist +26 -0
- package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-acknowledgements.markdown +3 -0
- package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-acknowledgements.plist +29 -0
- package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-dummy.m +5 -0
- package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-umbrella.h +16 -0
- package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig +14 -0
- package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.modulemap +6 -0
- package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig +14 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-Info.plist +26 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-acknowledgements.markdown +3 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-acknowledgements.plist +29 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-dummy.m +5 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh +188 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-umbrella.h +16 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig +15 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.modulemap +6 -0
- package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig +15 -0
- package/package.json +64 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
package com.wisdomgarden.mobile.beacon;
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint;
|
|
4
|
+
import android.bluetooth.BluetoothAdapter;
|
|
5
|
+
import android.bluetooth.BluetoothManager;
|
|
6
|
+
import android.bluetooth.le.AdvertiseCallback;
|
|
7
|
+
import android.bluetooth.le.AdvertiseData;
|
|
8
|
+
import android.bluetooth.le.AdvertiseSettings;
|
|
9
|
+
import android.bluetooth.le.BluetoothLeAdvertiser;
|
|
10
|
+
import android.bluetooth.le.BluetoothLeScanner;
|
|
11
|
+
import android.bluetooth.le.ScanCallback;
|
|
12
|
+
import android.bluetooth.le.ScanFilter;
|
|
13
|
+
import android.bluetooth.le.ScanResult;
|
|
14
|
+
import android.bluetooth.le.ScanSettings;
|
|
15
|
+
import android.content.Context;
|
|
16
|
+
import android.os.ParcelUuid;
|
|
17
|
+
|
|
18
|
+
import com.getcapacitor.JSObject;
|
|
19
|
+
import com.getcapacitor.NativePlugin;
|
|
20
|
+
import com.getcapacitor.Plugin;
|
|
21
|
+
import com.getcapacitor.PluginCall;
|
|
22
|
+
import com.getcapacitor.PluginMethod;
|
|
23
|
+
|
|
24
|
+
import java.util.ArrayList;
|
|
25
|
+
import java.util.List;
|
|
26
|
+
import java.util.Map;
|
|
27
|
+
|
|
28
|
+
@NativePlugin()
|
|
29
|
+
public class Beacon extends Plugin {
|
|
30
|
+
private static final String TAG = "Beacon";
|
|
31
|
+
private static final String WG_UUID = "1ed18c59-a7cc-4752-96b0-51d77a456584";
|
|
32
|
+
|
|
33
|
+
private BluetoothAdapter bluetoothAdapter;
|
|
34
|
+
private BluetoothLeAdvertiser advertiser;
|
|
35
|
+
private BluetoothLeScanner scanner;
|
|
36
|
+
private boolean isBroadcasting = false;
|
|
37
|
+
private boolean isMonitoring = false;
|
|
38
|
+
private int rollcallId = 0;
|
|
39
|
+
private String nonce = "";
|
|
40
|
+
private String message = "";
|
|
41
|
+
|
|
42
|
+
@PluginMethod
|
|
43
|
+
public void initialize(PluginCall call) {
|
|
44
|
+
call.resolve();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private boolean checkBluetoothEnabled(PluginCall call) {
|
|
48
|
+
if (bluetoothAdapter == null) {
|
|
49
|
+
BluetoothManager bluetoothManager = (BluetoothManager) getContext().getSystemService(Context.BLUETOOTH_SERVICE);
|
|
50
|
+
bluetoothAdapter = bluetoothManager.getAdapter();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (bluetoothAdapter == null) {
|
|
54
|
+
call.reject("Bluetooth is not supported on this device");
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!bluetoothAdapter.isEnabled()) {
|
|
59
|
+
call.reject("Bluetooth is not enabled");
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@PluginMethod
|
|
67
|
+
public void startBroadcasting(PluginCall call) {
|
|
68
|
+
bridge.logToJs("[Debug] startBroadcasting 11");
|
|
69
|
+
|
|
70
|
+
if (call.getString("message") != null && call.getString("message").length() == BeaconUtils.getMessageMaxLength()) {
|
|
71
|
+
message = call.getString("message");
|
|
72
|
+
} else {
|
|
73
|
+
if (call.getInt("rollcallId") == null) {
|
|
74
|
+
call.reject("rollcallId is required");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (call.getString("nonce") == null) {
|
|
78
|
+
call.reject("nonce is required");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
rollcallId = call.getInt("rollcallId");
|
|
83
|
+
nonce = call.getString("nonce");
|
|
84
|
+
|
|
85
|
+
message = BeaconUtils.buildMessage(rollcallId, nonce);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
bridge.logToJs("[Debug] startBroadcasting 11.1");
|
|
89
|
+
|
|
90
|
+
if (isBroadcasting) {
|
|
91
|
+
call.resolve();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
bridge.logToJs("[Debug] startBroadcasting 11.2");
|
|
95
|
+
|
|
96
|
+
if (!checkBluetoothEnabled(call)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
startAdvertising();
|
|
101
|
+
bridge.logToJs("[Debug] startBroadcasting 11.3");
|
|
102
|
+
|
|
103
|
+
call.resolve();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@PluginMethod
|
|
107
|
+
@SuppressLint("MissingPermission")
|
|
108
|
+
public void stopBroadcasting(PluginCall call) {
|
|
109
|
+
if (advertiser != null) {
|
|
110
|
+
advertiser.stopAdvertising(advertiseCallback);
|
|
111
|
+
advertiser = null;
|
|
112
|
+
}
|
|
113
|
+
isBroadcasting = false;
|
|
114
|
+
if (call != null) {
|
|
115
|
+
call.resolve();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@PluginMethod
|
|
120
|
+
public void startMonitoring(PluginCall call) {
|
|
121
|
+
bridge.logToJs("[Debug] startMonitoring 21");
|
|
122
|
+
if (isMonitoring) {
|
|
123
|
+
call.resolve();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
bridge.logToJs("[Debug] startMonitoring 21.1");
|
|
127
|
+
|
|
128
|
+
if (!checkBluetoothEnabled(call)) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
scanForPeripherals();
|
|
133
|
+
bridge.logToJs("[Debug] startMonitoring 21.3");
|
|
134
|
+
|
|
135
|
+
call.resolve();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@PluginMethod
|
|
139
|
+
@SuppressLint("MissingPermission")
|
|
140
|
+
public void stopMonitoring(PluginCall call) {
|
|
141
|
+
if (scanner != null) {
|
|
142
|
+
scanner.stopScan(scanCallback);
|
|
143
|
+
scanner = null;
|
|
144
|
+
}
|
|
145
|
+
isMonitoring = false;
|
|
146
|
+
call.resolve();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@PluginMethod
|
|
150
|
+
@SuppressLint("MissingPermission")
|
|
151
|
+
public void cleanup(PluginCall call) {
|
|
152
|
+
if (advertiser != null) {
|
|
153
|
+
advertiser.stopAdvertising(advertiseCallback);
|
|
154
|
+
advertiser = null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (scanner != null) {
|
|
158
|
+
scanner.stopScan(scanCallback);
|
|
159
|
+
scanner = null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
bluetoothAdapter = null;
|
|
163
|
+
|
|
164
|
+
isBroadcasting = false;
|
|
165
|
+
isMonitoring = false;
|
|
166
|
+
|
|
167
|
+
message = "";
|
|
168
|
+
nonce = "";
|
|
169
|
+
rollcallId = 0;
|
|
170
|
+
|
|
171
|
+
removeAllListeners(call);
|
|
172
|
+
|
|
173
|
+
call.resolve();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@PluginMethod
|
|
177
|
+
public void parseMessage(PluginCall call) {
|
|
178
|
+
String message = call.getString("message");
|
|
179
|
+
Map<String, Object> result = BeaconUtils.parseMessage(message);
|
|
180
|
+
JSObject jsResult = new JSObject();
|
|
181
|
+
jsResult.put("rollcallId", result.get("rollcallId"));
|
|
182
|
+
jsResult.put("nonce", result.get("nonce"));
|
|
183
|
+
call.resolve(jsResult);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@SuppressLint("MissingPermission")
|
|
187
|
+
private void startAdvertising() {
|
|
188
|
+
bridge.logToJs("[Debug] startAdvertising 12");
|
|
189
|
+
if (advertiser == null) {
|
|
190
|
+
advertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (isBroadcasting) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
bridge.logToJs("[Debug] startAdvertising broadcasting 13");
|
|
197
|
+
isBroadcasting = true;
|
|
198
|
+
|
|
199
|
+
AdvertiseSettings settings = new AdvertiseSettings.Builder()
|
|
200
|
+
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
|
|
201
|
+
.setConnectable(false)
|
|
202
|
+
.setTimeout(0)
|
|
203
|
+
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
|
|
204
|
+
.build();
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
bluetoothAdapter.setName(message);
|
|
208
|
+
bridge.logToJs("[Debug] startAdvertising broadcasting 13.1 " + message + " " + message.length());
|
|
209
|
+
|
|
210
|
+
AdvertiseData advertiseData = new AdvertiseData.Builder()
|
|
211
|
+
.setIncludeDeviceName(true)
|
|
212
|
+
.setIncludeTxPowerLevel(false)
|
|
213
|
+
.addServiceUuid(new ParcelUuid(java.util.UUID.fromString(WG_UUID)))
|
|
214
|
+
.build();
|
|
215
|
+
|
|
216
|
+
bridge.logToJs("[Debug] startAdvertising broadcasting 14");
|
|
217
|
+
advertiser.startAdvertising(settings, advertiseData, advertiseCallback);
|
|
218
|
+
bridge.logToJs("[Debug] startAdvertising broadcasting 15");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@SuppressLint("MissingPermission")
|
|
222
|
+
private void scanForPeripherals() {
|
|
223
|
+
bridge.logToJs("[Debug] scanForPeripherals 22");
|
|
224
|
+
if (scanner == null) {
|
|
225
|
+
scanner = bluetoothAdapter.getBluetoothLeScanner();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (isMonitoring) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
bridge.logToJs("[Debug] scanForPeripherals monitoring 23");
|
|
232
|
+
isMonitoring = true;
|
|
233
|
+
|
|
234
|
+
ScanSettings settings = new ScanSettings.Builder()
|
|
235
|
+
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
|
|
236
|
+
.setReportDelay(0)
|
|
237
|
+
.build();
|
|
238
|
+
|
|
239
|
+
List<ScanFilter> filters = new ArrayList<>();
|
|
240
|
+
ScanFilter filter = new ScanFilter.Builder()
|
|
241
|
+
.setServiceUuid(new ParcelUuid(java.util.UUID.fromString(WG_UUID)))
|
|
242
|
+
.build();
|
|
243
|
+
filters.add(filter);
|
|
244
|
+
|
|
245
|
+
bridge.logToJs("[Debug] scanForPeripherals monitoring 24");
|
|
246
|
+
scanner.startScan(filters, settings, scanCallback);
|
|
247
|
+
bridge.logToJs("[Debug] scanForPeripherals monitoring 25");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private final AdvertiseCallback advertiseCallback = new AdvertiseCallback() {
|
|
251
|
+
@Override
|
|
252
|
+
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
|
|
253
|
+
super.onStartSuccess(settingsInEffect);
|
|
254
|
+
bridge.logToJs("[Beacon] Peripheral manager is powered on");
|
|
255
|
+
JSObject data = new JSObject();
|
|
256
|
+
data.put("type", "peripheral");
|
|
257
|
+
data.put("state", "poweredOn");
|
|
258
|
+
notifyListeners("stateUpdated", data);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
@Override
|
|
262
|
+
public void onStartFailure(int errorCode) {
|
|
263
|
+
super.onStartFailure(errorCode);
|
|
264
|
+
bridge.logToJs("[Beacon] Peripheral manager failed to start advertising: " + errorCode);
|
|
265
|
+
JSObject data = new JSObject();
|
|
266
|
+
data.put("type", "peripheral");
|
|
267
|
+
data.put("state", errorCode);
|
|
268
|
+
notifyListeners("stateUpdated", data);
|
|
269
|
+
|
|
270
|
+
stopBroadcasting(null);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
private final ScanCallback scanCallback = new ScanCallback() {
|
|
275
|
+
@Override
|
|
276
|
+
public void onScanResult(int callbackType, ScanResult result) {
|
|
277
|
+
super.onScanResult(callbackType, result);
|
|
278
|
+
bridge.logToJs("[Debug] onScanResult 31");
|
|
279
|
+
if (result.getScanRecord() != null) {
|
|
280
|
+
bridge.logToJs("[Debug] onScanResult 32");
|
|
281
|
+
String deviceName = result.getScanRecord().getDeviceName();
|
|
282
|
+
if (deviceName != null && deviceName.length() == BeaconUtils.getMessageMaxLength()) {
|
|
283
|
+
bridge.logToJs("[Debug] onScanResult 33" + deviceName);
|
|
284
|
+
JSObject jsResult = new JSObject();
|
|
285
|
+
jsResult.put("message", deviceName);
|
|
286
|
+
jsResult.put("rssi", result.getRssi());
|
|
287
|
+
jsResult.put("peripheralId", result.getDevice().getAddress());
|
|
288
|
+
jsResult.put("timestamp", System.currentTimeMillis());
|
|
289
|
+
notifyListeners("beaconReceived", jsResult);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
package com.wisdomgarden.mobile.beacon;
|
|
2
|
+
|
|
3
|
+
import java.util.HashMap;
|
|
4
|
+
import java.util.Map;
|
|
5
|
+
import java.util.Random;
|
|
6
|
+
|
|
7
|
+
public class BeaconUtils {
|
|
8
|
+
private static final String CHARS = "2O9AuFNPDx4gtJwS3ye7l1Mq0dEB5HsaKInikRmLhjpG6b8fzQrCcvo";
|
|
9
|
+
private static final int RADIX = CHARS.length();
|
|
10
|
+
private static final int MESSAGE_MAX_LENGTH = 11;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 将数字编码为字符串
|
|
14
|
+
*
|
|
15
|
+
* @param num 要编码的数字
|
|
16
|
+
* @return 编码后的字符串
|
|
17
|
+
*/
|
|
18
|
+
public static String encode(int num) {
|
|
19
|
+
if (num == 0) return String.valueOf(CHARS.charAt(0));
|
|
20
|
+
StringBuilder result = new StringBuilder();
|
|
21
|
+
boolean isNegative = num < 0;
|
|
22
|
+
int n = Math.abs(num);
|
|
23
|
+
|
|
24
|
+
while (n > 0) {
|
|
25
|
+
int remainder = n % RADIX;
|
|
26
|
+
result.insert(0, CHARS.charAt(remainder));
|
|
27
|
+
n /= RADIX;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return isNegative ? "-" + result.toString() : result.toString();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 将字符串解码为数字
|
|
35
|
+
*
|
|
36
|
+
* @param str 要解码的字符串
|
|
37
|
+
* @return 解码后的数字
|
|
38
|
+
*/
|
|
39
|
+
public static int decode(String str) {
|
|
40
|
+
int num = 0;
|
|
41
|
+
for (char c : str.toCharArray()) {
|
|
42
|
+
int index = CHARS.indexOf(c);
|
|
43
|
+
if (index != -1) {
|
|
44
|
+
num = num * RADIX + index;
|
|
45
|
+
} else {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return num;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 检查字符是否为 nonce 字母,T-Z
|
|
54
|
+
*
|
|
55
|
+
* @param c 要检查的字符
|
|
56
|
+
* @return 如果是 nonce 字母返回 true,否则返回 false
|
|
57
|
+
*/
|
|
58
|
+
public static boolean isNonceLetter(char c) {
|
|
59
|
+
int code = (int) c;
|
|
60
|
+
return code >= 84 && code <= 90;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 构建消息
|
|
65
|
+
*
|
|
66
|
+
* @param rollcallId 点名ID
|
|
67
|
+
* @param nonce 随机字符串
|
|
68
|
+
* @return 构建的消息
|
|
69
|
+
*/
|
|
70
|
+
public static String buildMessage(int rollcallId, String nonce) {
|
|
71
|
+
String rollcallIdStr = encode(rollcallId);
|
|
72
|
+
|
|
73
|
+
if (nonce == null || nonce.isEmpty()) {
|
|
74
|
+
return rollcallIdStr + "Z";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
String message = rollcallIdStr + nonce;
|
|
78
|
+
return message.length() > MESSAGE_MAX_LENGTH ? message.substring(0, MESSAGE_MAX_LENGTH) : message;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 解析消息
|
|
83
|
+
*
|
|
84
|
+
* @param message 要解析的消息
|
|
85
|
+
* @return 包含 rollcallId 和 nonce 的 Map
|
|
86
|
+
*/
|
|
87
|
+
public static Map<String, Object> parseMessage(String message) {
|
|
88
|
+
Map<String, Object> payload = new HashMap<>();
|
|
89
|
+
payload.put("rollcallId", 0);
|
|
90
|
+
payload.put("nonce", "");
|
|
91
|
+
|
|
92
|
+
if (message == null) {
|
|
93
|
+
return payload;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
for (int i = 0; i < message.length(); i++) {
|
|
98
|
+
char c = message.charAt(i);
|
|
99
|
+
if (isNonceLetter(c)) {
|
|
100
|
+
String rollcallIdStr = message.substring(0, i);
|
|
101
|
+
payload.put("rollcallId", decode(rollcallIdStr));
|
|
102
|
+
payload.put("nonce", message.substring(i));
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return payload;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 获取消息最大长度
|
|
112
|
+
*
|
|
113
|
+
* @return 消息最大长度
|
|
114
|
+
*/
|
|
115
|
+
public static int getMessageMaxLength() {
|
|
116
|
+
return MESSAGE_MAX_LENGTH;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
4
|
+
xmlns:tools="http://schemas.android.com/tools"
|
|
5
|
+
android:layout_width="match_parent"
|
|
6
|
+
android:layout_height="match_parent"
|
|
7
|
+
tools:context="com.getcapacitor.BridgeActivity"
|
|
8
|
+
>
|
|
9
|
+
|
|
10
|
+
<WebView
|
|
11
|
+
android:id="@+id/webview"
|
|
12
|
+
android:layout_width="fill_parent"
|
|
13
|
+
android:layout_height="fill_parent" />
|
|
14
|
+
|
|
15
|
+
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package com.getcapacitor;
|
|
2
|
+
|
|
3
|
+
import static org.junit.Assert.*;
|
|
4
|
+
|
|
5
|
+
import org.junit.Test;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Example local unit test, which will execute on the development machine (host).
|
|
9
|
+
*
|
|
10
|
+
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
11
|
+
*/
|
|
12
|
+
public class ExampleUnitTest {
|
|
13
|
+
|
|
14
|
+
@Test
|
|
15
|
+
public void addition_isCorrect() throws Exception {
|
|
16
|
+
assertEquals(4, 2 + 2);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { PluginListenerHandle } from "@capacitor/core";
|
|
2
|
+
declare module '@capacitor/core' {
|
|
3
|
+
interface PluginRegistry {
|
|
4
|
+
Beacon: BeaconPlugin;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export interface BeaconPlugin {
|
|
8
|
+
initialize(options: {
|
|
9
|
+
allowDuplicatesKey?: boolean;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
startBroadcasting(options: {
|
|
12
|
+
message?: string;
|
|
13
|
+
rollcallId?: number;
|
|
14
|
+
nonce?: string;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
stopBroadcasting(): Promise<void>;
|
|
17
|
+
startMonitoring(): Promise<void>;
|
|
18
|
+
stopMonitoring(): Promise<void>;
|
|
19
|
+
cleanup(): Promise<void>;
|
|
20
|
+
parseMessage(options: {
|
|
21
|
+
message?: string;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
rollcallId: number;
|
|
24
|
+
nonce: string;
|
|
25
|
+
}>;
|
|
26
|
+
addListener(eventName: 'beaconReceived', listenerFunc: (data: BeaconReceivedEvent) => void): PluginListenerHandle;
|
|
27
|
+
addListener(eventName: 'stateUpdated', listenerFunc: (data: StateUpdatedEvent) => void): PluginListenerHandle;
|
|
28
|
+
addListener(eventName: 'stateError', listenerFunc: (data: StateErrorEvent) => void): PluginListenerHandle;
|
|
29
|
+
addListener(eventName: 'bluetoothStateChanged', listenerFunc: (data: BluetoothStateEvent) => void): PluginListenerHandle;
|
|
30
|
+
removeAllListeners(): void;
|
|
31
|
+
}
|
|
32
|
+
export interface BeaconReceivedEvent {
|
|
33
|
+
message: string;
|
|
34
|
+
rssi: number;
|
|
35
|
+
peripheralId: string;
|
|
36
|
+
timestamp: number;
|
|
37
|
+
}
|
|
38
|
+
export interface StateUpdatedEvent {
|
|
39
|
+
type: 'peripheral';
|
|
40
|
+
state: 'poweredOn' | 'poweredOff' | 'unauthorized' | 'unsupported' | number;
|
|
41
|
+
}
|
|
42
|
+
export interface StateErrorEvent {
|
|
43
|
+
type: 'peripheral' | 'central';
|
|
44
|
+
state: string;
|
|
45
|
+
}
|
|
46
|
+
export interface BluetoothStateEvent {
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import { BeaconPlugin } from './definitions';
|
|
3
|
+
export declare class BeaconWeb extends WebPlugin implements BeaconPlugin {
|
|
4
|
+
constructor();
|
|
5
|
+
initialize(_options: {
|
|
6
|
+
allowDuplicatesKey?: boolean;
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
startBroadcasting(_options: {
|
|
9
|
+
message?: string;
|
|
10
|
+
rollcallId?: number;
|
|
11
|
+
nonce?: string;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
stopBroadcasting(): Promise<void>;
|
|
14
|
+
startMonitoring(): Promise<void>;
|
|
15
|
+
stopMonitoring(): Promise<void>;
|
|
16
|
+
cleanup(): Promise<void>;
|
|
17
|
+
parseMessage(_options: {
|
|
18
|
+
message?: string;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
rollcallId: number;
|
|
21
|
+
nonce: string;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
declare const Beacon: BeaconWeb;
|
|
25
|
+
export { Beacon };
|
package/dist/esm/web.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { WebPlugin } from '@capacitor/core';
|
|
11
|
+
export class BeaconWeb extends WebPlugin {
|
|
12
|
+
constructor() {
|
|
13
|
+
super({
|
|
14
|
+
name: 'Beacon',
|
|
15
|
+
platforms: ['web'],
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
initialize(_options) {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
//
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
startBroadcasting(_options) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
//
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
stopBroadcasting() {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
//
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
startMonitoring() {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
//
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
stopMonitoring() {
|
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
//
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
cleanup() {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
//
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
parseMessage(_options) {
|
|
49
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
return {
|
|
51
|
+
rollcallId: 0,
|
|
52
|
+
nonce: '',
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const Beacon = new BeaconWeb();
|
|
58
|
+
export { Beacon };
|
|
59
|
+
import { registerWebPlugin } from '@capacitor/core';
|
|
60
|
+
registerWebPlugin(Beacon);
|
|
61
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,SAAU,SAAQ,SAAS;IACtC;QACE,KAAK,CAAC;YACJ,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC,KAAK,CAAC;SACnB,CAAC,CAAC;IACL,CAAC;IAEK,UAAU,CAAC,QAA0C;;YACzD,EAAE;QACJ,CAAC;KAAA;IAEK,iBAAiB,CAAC,QAIvB;;YACC,EAAE;QACJ,CAAC;KAAA;IAEK,gBAAgB;;YACpB,EAAE;QACJ,CAAC;KAAA;IAEK,eAAe;;YACnB,EAAE;QACJ,CAAC;KAAA;IAEK,cAAc;;YAClB,EAAE;QACJ,CAAC;KAAA;IAEK,OAAO;;YACX,EAAE;QACJ,CAAC;KAAA;IAEK,YAAY,CAAC,QAA8B;;YAI/C,OAAO;gBACL,UAAU,EAAE,CAAC;gBACb,KAAK,EAAE,EAAE;aACV,CAAC;QACJ,CAAC;KAAA;CACF;AAED,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;AAE/B,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,iBAAiB,CAAC,MAAM,CAAC,CAAC"}
|