@capgo/capacitor-wifi 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,591 @@
1
+ package ee.forgr.plugin.capacitor_wifi;
2
+
3
+ import android.Manifest;
4
+ import android.content.BroadcastReceiver;
5
+ import android.content.Context;
6
+ import android.content.Intent;
7
+ import android.content.IntentFilter;
8
+ import android.net.ConnectivityManager;
9
+ import android.net.Network;
10
+ import android.net.NetworkCapabilities;
11
+ import android.net.NetworkRequest;
12
+ import android.net.NetworkSpecifier;
13
+ import android.net.wifi.ScanResult;
14
+ import android.net.wifi.WifiConfiguration;
15
+ import android.net.wifi.WifiInfo;
16
+ import android.net.wifi.WifiManager;
17
+ import android.net.wifi.WifiNetworkSpecifier;
18
+ import android.net.wifi.WifiNetworkSuggestion;
19
+ import android.os.Build;
20
+ import android.provider.Settings;
21
+ import androidx.annotation.NonNull;
22
+ import androidx.annotation.RequiresApi;
23
+ import com.getcapacitor.JSArray;
24
+ import com.getcapacitor.JSObject;
25
+ import com.getcapacitor.PermissionState;
26
+ import com.getcapacitor.Plugin;
27
+ import com.getcapacitor.PluginCall;
28
+ import com.getcapacitor.PluginMethod;
29
+ import com.getcapacitor.annotation.CapacitorPlugin;
30
+ import com.getcapacitor.annotation.Permission;
31
+ import com.getcapacitor.annotation.PermissionCallback;
32
+ import java.net.Inet4Address;
33
+ import java.net.InetAddress;
34
+ import java.net.NetworkInterface;
35
+ import java.util.ArrayList;
36
+ import java.util.Collections;
37
+ import java.util.List;
38
+
39
+ @CapacitorPlugin(
40
+ name = "CapacitorWifi",
41
+ permissions = {
42
+ @Permission(alias = "location", strings = { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION })
43
+ }
44
+ )
45
+ public class CapacitorWifiPlugin extends Plugin {
46
+
47
+ private final String pluginVersion = "1.0.0";
48
+
49
+ private WifiManager wifiManager;
50
+ private ConnectivityManager connectivityManager;
51
+ private BroadcastReceiver scanResultsReceiver;
52
+ private ConnectivityManager.NetworkCallback networkCallback;
53
+
54
+ @Override
55
+ public void load() {
56
+ wifiManager = (WifiManager) getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
57
+ connectivityManager = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
58
+ }
59
+
60
+ @PluginMethod
61
+ public void addNetwork(PluginCall call) {
62
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
63
+ addNetworkModern(call);
64
+ } else {
65
+ addNetworkLegacy(call);
66
+ }
67
+ }
68
+
69
+ @RequiresApi(api = Build.VERSION_CODES.Q)
70
+ private void addNetworkModern(PluginCall call) {
71
+ String ssid = call.getString("ssid");
72
+ if (ssid == null || ssid.isEmpty()) {
73
+ call.reject("SSID is required");
74
+ return;
75
+ }
76
+
77
+ String password = call.getString("password");
78
+ Boolean isHiddenSsid = call.getBoolean("isHiddenSsid", false);
79
+ Integer securityType = call.getInt("securityType", 2); // Default to WPA2_PSK
80
+
81
+ try {
82
+ // Open system settings to add network
83
+ Intent intent = new Intent(Settings.ACTION_WIFI_ADD_NETWORKS);
84
+ WifiNetworkSuggestion.Builder suggestionBuilder = new WifiNetworkSuggestion.Builder().setSsid(ssid);
85
+
86
+ if (isHiddenSsid != null && isHiddenSsid) {
87
+ suggestionBuilder.setIsHiddenSsid(true);
88
+ }
89
+
90
+ if (password != null && !password.isEmpty()) {
91
+ // Determine security type based on parameter
92
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
93
+ switch (securityType) {
94
+ case 1: // WEP
95
+ suggestionBuilder.setWpa2Passphrase(password); // WEP not supported, fallback to WPA2
96
+ break;
97
+ case 2: // WPA2_PSK
98
+ suggestionBuilder.setWpa2Passphrase(password);
99
+ break;
100
+ case 3: // EAP
101
+ // Enterprise networks require more configuration
102
+ suggestionBuilder.setWpa2Passphrase(password);
103
+ break;
104
+ case 4: // SAE (WPA3)
105
+ suggestionBuilder.setWpa3Passphrase(password);
106
+ break;
107
+ default:
108
+ suggestionBuilder.setWpa2Passphrase(password);
109
+ break;
110
+ }
111
+ } else {
112
+ suggestionBuilder.setWpa2Passphrase(password);
113
+ }
114
+ }
115
+
116
+ ArrayList<WifiNetworkSuggestion> suggestionsList = new ArrayList<>();
117
+ suggestionsList.add(suggestionBuilder.build());
118
+
119
+ intent.putParcelableArrayListExtra(Settings.EXTRA_WIFI_NETWORK_LIST, suggestionsList);
120
+ getActivity().startActivity(intent);
121
+ call.resolve();
122
+ } catch (Exception e) {
123
+ call.reject("Failed to add network: " + e.getMessage(), e);
124
+ }
125
+ }
126
+
127
+ private void addNetworkLegacy(PluginCall call) {
128
+ if (getPermissionState("location") != PermissionState.GRANTED) {
129
+ requestPermissionForAlias("location", call, "addNetworkCallback");
130
+ return;
131
+ }
132
+
133
+ String ssid = call.getString("ssid");
134
+ if (ssid == null || ssid.isEmpty()) {
135
+ call.reject("SSID is required");
136
+ return;
137
+ }
138
+
139
+ String password = call.getString("password");
140
+ Boolean isHiddenSsid = call.getBoolean("isHiddenSsid", false);
141
+ Integer securityType = call.getInt("securityType", 2);
142
+
143
+ try {
144
+ WifiConfiguration wifiConfig = new WifiConfiguration();
145
+ wifiConfig.SSID = "\"" + ssid + "\"";
146
+
147
+ if (isHiddenSsid != null && isHiddenSsid) {
148
+ wifiConfig.hiddenSSID = true;
149
+ }
150
+
151
+ if (password != null && !password.isEmpty()) {
152
+ if (securityType == 1) {
153
+ // WEP
154
+ wifiConfig.wepKeys[0] = "\"" + password + "\"";
155
+ wifiConfig.wepTxKeyIndex = 0;
156
+ wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
157
+ wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
158
+ } else {
159
+ // WPA/WPA2
160
+ wifiConfig.preSharedKey = "\"" + password + "\"";
161
+ }
162
+ } else {
163
+ // Open network
164
+ wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
165
+ }
166
+
167
+ int netId = wifiManager.addNetwork(wifiConfig);
168
+ if (netId == -1) {
169
+ call.reject("Failed to add network");
170
+ return;
171
+ }
172
+
173
+ boolean enableResult = wifiManager.enableNetwork(netId, true);
174
+ if (!enableResult) {
175
+ call.reject("Failed to enable network");
176
+ return;
177
+ }
178
+
179
+ call.resolve();
180
+ } catch (Exception e) {
181
+ call.reject("Failed to add network: " + e.getMessage(), e);
182
+ }
183
+ }
184
+
185
+ @PluginMethod
186
+ public void connect(PluginCall call) {
187
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
188
+ connectModern(call);
189
+ } else {
190
+ connectLegacy(call);
191
+ }
192
+ }
193
+
194
+ @RequiresApi(api = Build.VERSION_CODES.Q)
195
+ private void connectModern(PluginCall call) {
196
+ String ssid = call.getString("ssid");
197
+ if (ssid == null || ssid.isEmpty()) {
198
+ call.reject("SSID is required");
199
+ return;
200
+ }
201
+
202
+ String password = call.getString("password");
203
+ Boolean isHiddenSsid = call.getBoolean("isHiddenSsid", false);
204
+
205
+ try {
206
+ WifiNetworkSpecifier.Builder specifierBuilder = new WifiNetworkSpecifier.Builder().setSsid(ssid);
207
+
208
+ if (isHiddenSsid != null && isHiddenSsid) {
209
+ specifierBuilder.setIsHiddenSsid(true);
210
+ }
211
+
212
+ if (password != null && !password.isEmpty()) {
213
+ specifierBuilder.setWpa2Passphrase(password);
214
+ }
215
+
216
+ NetworkSpecifier specifier = specifierBuilder.build();
217
+
218
+ NetworkRequest request = new NetworkRequest.Builder()
219
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
220
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
221
+ .setNetworkSpecifier(specifier)
222
+ .build();
223
+
224
+ networkCallback = new ConnectivityManager.NetworkCallback() {
225
+ @Override
226
+ public void onAvailable(@NonNull Network network) {
227
+ super.onAvailable(network);
228
+ call.resolve();
229
+ }
230
+
231
+ @Override
232
+ public void onUnavailable() {
233
+ super.onUnavailable();
234
+ call.reject("Failed to connect to network");
235
+ }
236
+ };
237
+
238
+ connectivityManager.requestNetwork(request, networkCallback);
239
+ } catch (Exception e) {
240
+ call.reject("Failed to connect: " + e.getMessage(), e);
241
+ }
242
+ }
243
+
244
+ private void connectLegacy(PluginCall call) {
245
+ if (getPermissionState("location") != PermissionState.GRANTED) {
246
+ requestPermissionForAlias("location", call, "connectCallback");
247
+ return;
248
+ }
249
+
250
+ String ssid = call.getString("ssid");
251
+ if (ssid == null || ssid.isEmpty()) {
252
+ call.reject("SSID is required");
253
+ return;
254
+ }
255
+
256
+ String password = call.getString("password");
257
+ Boolean isHiddenSsid = call.getBoolean("isHiddenSsid", false);
258
+
259
+ try {
260
+ WifiConfiguration wifiConfig = new WifiConfiguration();
261
+ wifiConfig.SSID = "\"" + ssid + "\"";
262
+
263
+ if (isHiddenSsid != null && isHiddenSsid) {
264
+ wifiConfig.hiddenSSID = true;
265
+ }
266
+
267
+ if (password != null && !password.isEmpty()) {
268
+ wifiConfig.preSharedKey = "\"" + password + "\"";
269
+ } else {
270
+ wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
271
+ }
272
+
273
+ int netId = wifiManager.addNetwork(wifiConfig);
274
+ if (netId == -1) {
275
+ call.reject("Failed to add network configuration");
276
+ return;
277
+ }
278
+
279
+ boolean disconnectResult = wifiManager.disconnect();
280
+ if (!disconnectResult) {
281
+ call.reject("Failed to disconnect from current network");
282
+ return;
283
+ }
284
+
285
+ boolean enableResult = wifiManager.enableNetwork(netId, true);
286
+ if (!enableResult) {
287
+ call.reject("Failed to enable network");
288
+ return;
289
+ }
290
+
291
+ boolean reconnectResult = wifiManager.reconnect();
292
+ if (!reconnectResult) {
293
+ call.reject("Failed to reconnect");
294
+ return;
295
+ }
296
+
297
+ call.resolve();
298
+ } catch (Exception e) {
299
+ call.reject("Failed to connect: " + e.getMessage(), e);
300
+ }
301
+ }
302
+
303
+ @PluginMethod
304
+ public void disconnect(PluginCall call) {
305
+ try {
306
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
307
+ if (networkCallback != null) {
308
+ connectivityManager.unregisterNetworkCallback(networkCallback);
309
+ networkCallback = null;
310
+ }
311
+ } else {
312
+ wifiManager.disconnect();
313
+ }
314
+ call.resolve();
315
+ } catch (Exception e) {
316
+ call.reject("Failed to disconnect: " + e.getMessage(), e);
317
+ }
318
+ }
319
+
320
+ @PluginMethod
321
+ public void getAvailableNetworks(PluginCall call) {
322
+ if (getPermissionState("location") != PermissionState.GRANTED) {
323
+ requestPermissionForAlias("location", call, "getAvailableNetworksCallback");
324
+ return;
325
+ }
326
+
327
+ try {
328
+ List<ScanResult> scanResults = wifiManager.getScanResults();
329
+ JSArray networks = new JSArray();
330
+
331
+ for (ScanResult result : scanResults) {
332
+ JSObject network = new JSObject();
333
+ network.put("ssid", result.SSID);
334
+ network.put("rssi", result.level);
335
+
336
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
337
+ JSArray securityTypes = new JSArray();
338
+ int[] types = result.getSecurityTypes();
339
+ for (int type : types) {
340
+ securityTypes.put(type);
341
+ }
342
+ network.put("securityTypes", securityTypes);
343
+ }
344
+
345
+ networks.put(network);
346
+ }
347
+
348
+ JSObject ret = new JSObject();
349
+ ret.put("networks", networks);
350
+ call.resolve(ret);
351
+ } catch (Exception e) {
352
+ call.reject("Failed to get available networks: " + e.getMessage(), e);
353
+ }
354
+ }
355
+
356
+ @PluginMethod
357
+ public void getIpAddress(PluginCall call) {
358
+ try {
359
+ String ipAddress = null;
360
+
361
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
362
+ Network network = connectivityManager.getActiveNetwork();
363
+ if (network != null) {
364
+ NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
365
+ if (capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
366
+ ipAddress = getWifiIpAddress();
367
+ }
368
+ }
369
+ } else {
370
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
371
+ if (wifiInfo != null) {
372
+ int ip = wifiInfo.getIpAddress();
373
+ ipAddress = String.format("%d.%d.%d.%d", (ip & 0xff), ((ip >> 8) & 0xff), ((ip >> 16) & 0xff), ((ip >> 24) & 0xff));
374
+ }
375
+ }
376
+
377
+ if (ipAddress != null && !ipAddress.isEmpty()) {
378
+ JSObject ret = new JSObject();
379
+ ret.put("ipAddress", ipAddress);
380
+ call.resolve(ret);
381
+ } else {
382
+ call.reject("No IP address found");
383
+ }
384
+ } catch (Exception e) {
385
+ call.reject("Failed to get IP address: " + e.getMessage(), e);
386
+ }
387
+ }
388
+
389
+ private String getWifiIpAddress() {
390
+ try {
391
+ List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
392
+ for (NetworkInterface intf : interfaces) {
393
+ if (intf.getName().contains("wlan")) {
394
+ List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
395
+ for (InetAddress addr : addrs) {
396
+ if (!addr.isLoopbackAddress() && addr instanceof Inet4Address) {
397
+ return addr.getHostAddress();
398
+ }
399
+ }
400
+ }
401
+ }
402
+ } catch (Exception e) {
403
+ e.printStackTrace();
404
+ }
405
+ return null;
406
+ }
407
+
408
+ @PluginMethod
409
+ public void getRssi(PluginCall call) {
410
+ if (getPermissionState("location") != PermissionState.GRANTED) {
411
+ requestPermissionForAlias("location", call, "getRssiCallback");
412
+ return;
413
+ }
414
+
415
+ try {
416
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
417
+ if (wifiInfo != null) {
418
+ int rssi = wifiInfo.getRssi();
419
+ JSObject ret = new JSObject();
420
+ ret.put("rssi", rssi);
421
+ call.resolve(ret);
422
+ } else {
423
+ call.reject("Failed to get WiFi info");
424
+ }
425
+ } catch (Exception e) {
426
+ call.reject("Failed to get RSSI: " + e.getMessage(), e);
427
+ }
428
+ }
429
+
430
+ @PluginMethod
431
+ public void getSsid(PluginCall call) {
432
+ if (getPermissionState("location") != PermissionState.GRANTED) {
433
+ requestPermissionForAlias("location", call, "getSsidCallback");
434
+ return;
435
+ }
436
+
437
+ try {
438
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
439
+ if (wifiInfo != null) {
440
+ String ssid = wifiInfo.getSSID();
441
+ if (ssid != null) {
442
+ // Remove quotes if present
443
+ ssid = ssid.replace("\"", "");
444
+ JSObject ret = new JSObject();
445
+ ret.put("ssid", ssid);
446
+ call.resolve(ret);
447
+ } else {
448
+ call.reject("No SSID found");
449
+ }
450
+ } else {
451
+ call.reject("Failed to get WiFi info");
452
+ }
453
+ } catch (Exception e) {
454
+ call.reject("Failed to get SSID: " + e.getMessage(), e);
455
+ }
456
+ }
457
+
458
+ @PluginMethod
459
+ public void isEnabled(PluginCall call) {
460
+ try {
461
+ boolean enabled = wifiManager.isWifiEnabled();
462
+ JSObject ret = new JSObject();
463
+ ret.put("enabled", enabled);
464
+ call.resolve(ret);
465
+ } catch (Exception e) {
466
+ call.reject("Failed to check WiFi status: " + e.getMessage(), e);
467
+ }
468
+ }
469
+
470
+ @PluginMethod
471
+ public void startScan(PluginCall call) {
472
+ if (getPermissionState("location") != PermissionState.GRANTED) {
473
+ requestPermissionForAlias("location", call, "startScanCallback");
474
+ return;
475
+ }
476
+
477
+ try {
478
+ // Register broadcast receiver for scan results
479
+ if (scanResultsReceiver == null) {
480
+ scanResultsReceiver = new BroadcastReceiver() {
481
+ @Override
482
+ public void onReceive(Context context, Intent intent) {
483
+ boolean success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
484
+ if (success) {
485
+ notifyListeners("networksScanned", new JSObject());
486
+ }
487
+ }
488
+ };
489
+
490
+ IntentFilter intentFilter = new IntentFilter();
491
+ intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
492
+ getContext().registerReceiver(scanResultsReceiver, intentFilter);
493
+ }
494
+
495
+ boolean scanStarted = wifiManager.startScan();
496
+ if (scanStarted) {
497
+ call.resolve();
498
+ } else {
499
+ call.reject("Failed to start scan");
500
+ }
501
+ } catch (Exception e) {
502
+ call.reject("Failed to start scan: " + e.getMessage(), e);
503
+ }
504
+ }
505
+
506
+ @PluginMethod
507
+ public void getPluginVersion(final PluginCall call) {
508
+ try {
509
+ final JSObject ret = new JSObject();
510
+ ret.put("version", this.pluginVersion);
511
+ call.resolve(ret);
512
+ } catch (final Exception e) {
513
+ call.reject("Could not get plugin version", e);
514
+ }
515
+ }
516
+
517
+ @PermissionCallback
518
+ private void addNetworkCallback(PluginCall call) {
519
+ if (getPermissionState("location") == PermissionState.GRANTED) {
520
+ addNetworkLegacy(call);
521
+ } else {
522
+ call.reject("Location permission is required");
523
+ }
524
+ }
525
+
526
+ @PermissionCallback
527
+ private void connectCallback(PluginCall call) {
528
+ if (getPermissionState("location") == PermissionState.GRANTED) {
529
+ connectLegacy(call);
530
+ } else {
531
+ call.reject("Location permission is required");
532
+ }
533
+ }
534
+
535
+ @PermissionCallback
536
+ private void getAvailableNetworksCallback(PluginCall call) {
537
+ if (getPermissionState("location") == PermissionState.GRANTED) {
538
+ getAvailableNetworks(call);
539
+ } else {
540
+ call.reject("Location permission is required");
541
+ }
542
+ }
543
+
544
+ @PermissionCallback
545
+ private void getRssiCallback(PluginCall call) {
546
+ if (getPermissionState("location") == PermissionState.GRANTED) {
547
+ getRssi(call);
548
+ } else {
549
+ call.reject("Location permission is required");
550
+ }
551
+ }
552
+
553
+ @PermissionCallback
554
+ private void getSsidCallback(PluginCall call) {
555
+ if (getPermissionState("location") == PermissionState.GRANTED) {
556
+ getSsid(call);
557
+ } else {
558
+ call.reject("Location permission is required");
559
+ }
560
+ }
561
+
562
+ @PermissionCallback
563
+ private void startScanCallback(PluginCall call) {
564
+ if (getPermissionState("location") == PermissionState.GRANTED) {
565
+ startScan(call);
566
+ } else {
567
+ call.reject("Location permission is required");
568
+ }
569
+ }
570
+
571
+ @Override
572
+ protected void handleOnDestroy() {
573
+ if (scanResultsReceiver != null) {
574
+ try {
575
+ getContext().unregisterReceiver(scanResultsReceiver);
576
+ } catch (Exception e) {
577
+ // Receiver not registered
578
+ }
579
+ scanResultsReceiver = null;
580
+ }
581
+
582
+ if (networkCallback != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
583
+ try {
584
+ connectivityManager.unregisterNetworkCallback(networkCallback);
585
+ } catch (Exception e) {
586
+ // Callback not registered
587
+ }
588
+ networkCallback = null;
589
+ }
590
+ }
591
+ }