@cappitolian/network-discovery 0.0.9 → 0.0.10
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/Package.swift +1 -1
- package/README.md +4 -4
- package/android/src/main/java/com/cappitolian/plugins/networkdiscovery/NetworkDiscovery.java +224 -249
- package/android/src/main/java/com/cappitolian/plugins/networkdiscovery/NetworkDiscoveryPlugin.java +15 -2
- package/ios/Sources/NetworkDiscoveryPlugin/NetworkDiscovery.swift +34 -62
- package/ios/Sources/NetworkDiscoveryPlugin/NetworkDiscoveryPlugin.swift +5 -34
- package/package.json +5 -5
package/Package.swift
CHANGED
|
@@ -10,7 +10,7 @@ let package = Package(
|
|
|
10
10
|
targets: ["NetworkDiscoveryPlugin"])
|
|
11
11
|
],
|
|
12
12
|
dependencies: [
|
|
13
|
-
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
|
|
14
14
|
],
|
|
15
15
|
targets: [
|
|
16
16
|
.target(
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ import { NetworkDiscovery } from '@cappitolian/network-discovery';
|
|
|
35
35
|
// Start advertising your server
|
|
36
36
|
await NetworkDiscovery.startAdvertising({
|
|
37
37
|
serviceName: 'MyAppServer',
|
|
38
|
-
serviceType: '_http._tcp', // or '_myapp._tcp' for custom service
|
|
38
|
+
serviceType: '_http._tcp', // or '_myapp._tcp' for custom service
|
|
39
39
|
port: 8080,
|
|
40
40
|
txtRecord: {
|
|
41
41
|
ip: '192.168.1.100', // Your server IP
|
|
@@ -69,7 +69,7 @@ NetworkDiscovery.addListener('serviceLost', (service) => {
|
|
|
69
69
|
|
|
70
70
|
// Start discovery
|
|
71
71
|
await NetworkDiscovery.startDiscovery({
|
|
72
|
-
serviceType: '_http._tcp', // Must match the server's serviceType
|
|
72
|
+
serviceType: '_http._tcp', // Must match the server's serviceType
|
|
73
73
|
domain: 'local.' // Optional, defaults to 'local.'
|
|
74
74
|
});
|
|
75
75
|
|
|
@@ -94,7 +94,7 @@ async startServer() {
|
|
|
94
94
|
// Advertise server
|
|
95
95
|
await NetworkDiscovery.startAdvertising({
|
|
96
96
|
serviceName: 'MyAppServer',
|
|
97
|
-
serviceType: '
|
|
97
|
+
serviceType: '_myapp._tcp',
|
|
98
98
|
port: 8080,
|
|
99
99
|
txtRecord: {
|
|
100
100
|
ip: ip,
|
|
@@ -138,7 +138,7 @@ async findAndConnectToServer() {
|
|
|
138
138
|
|
|
139
139
|
// Start discovery
|
|
140
140
|
NetworkDiscovery.startDiscovery({
|
|
141
|
-
serviceType: '
|
|
141
|
+
serviceType: '_myapp._tcp'
|
|
142
142
|
});
|
|
143
143
|
|
|
144
144
|
// Timeout after 10 seconds
|
package/android/src/main/java/com/cappitolian/plugins/networkdiscovery/NetworkDiscovery.java
CHANGED
|
@@ -1,250 +1,225 @@
|
|
|
1
|
-
package com.cappitolian.plugins.networkdiscovery;
|
|
2
|
-
|
|
3
|
-
import android.content.Context;
|
|
4
|
-
import android.net.nsd.NsdManager;
|
|
5
|
-
import android.net.nsd.NsdServiceInfo;
|
|
6
|
-
import android.util.Log;
|
|
7
|
-
|
|
8
|
-
import com.getcapacitor.JSObject;
|
|
9
|
-
import com.getcapacitor.Plugin;
|
|
10
|
-
|
|
11
|
-
import org.json.JSONArray;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import java.
|
|
15
|
-
import java.util.Map;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
private static final String TAG = "NetworkDiscovery";
|
|
20
|
-
private NsdManager nsdManager;
|
|
21
|
-
private NsdManager.RegistrationListener registrationListener;
|
|
22
|
-
private NsdManager.DiscoveryListener discoveryListener;
|
|
23
|
-
private NsdServiceInfo serviceInfo;
|
|
24
|
-
private Plugin plugin;
|
|
25
|
-
|
|
26
|
-
public NetworkDiscovery(Plugin plugin, Context context) {
|
|
27
|
-
this.plugin = plugin;
|
|
28
|
-
this.nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public void startAdvertising(
|
|
32
|
-
String serviceName,
|
|
33
|
-
String serviceType,
|
|
34
|
-
int port,
|
|
35
|
-
JSObject txtRecord,
|
|
36
|
-
AdvertisingCallback callback
|
|
37
|
-
) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Log.
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
Log.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
Log.d(TAG, " TXT Record retrieved: " + entry.getKey() + " = " + value);
|
|
226
|
-
}
|
|
227
|
-
serviceData.put("txtRecord", txtRecordObj);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return serviceData;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Callbacks interfaces
|
|
234
|
-
public interface AdvertisingCallback {
|
|
235
|
-
void onSuccess();
|
|
236
|
-
void onError(String error);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
public interface StopCallback {
|
|
240
|
-
void onSuccess();
|
|
241
|
-
void onError(String error);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
public interface DiscoveryCallback {
|
|
245
|
-
void onDiscoveryStarted();
|
|
246
|
-
void onServiceFound(JSObject service);
|
|
247
|
-
void onServiceLost(JSObject service);
|
|
248
|
-
void onError(String error);
|
|
249
|
-
}
|
|
1
|
+
package com.cappitolian.plugins.networkdiscovery;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.net.nsd.NsdManager;
|
|
5
|
+
import android.net.nsd.NsdServiceInfo;
|
|
6
|
+
import android.util.Log;
|
|
7
|
+
|
|
8
|
+
import com.getcapacitor.JSObject;
|
|
9
|
+
import com.getcapacitor.Plugin;
|
|
10
|
+
|
|
11
|
+
import org.json.JSONArray;
|
|
12
|
+
import org.json.JSONException;
|
|
13
|
+
|
|
14
|
+
import java.net.InetAddress;
|
|
15
|
+
import java.util.Map;
|
|
16
|
+
import java.util.Iterator;
|
|
17
|
+
|
|
18
|
+
public class NetworkDiscovery {
|
|
19
|
+
private static final String TAG = "NetworkDiscovery";
|
|
20
|
+
private NsdManager nsdManager;
|
|
21
|
+
private NsdManager.RegistrationListener registrationListener;
|
|
22
|
+
private NsdManager.DiscoveryListener discoveryListener;
|
|
23
|
+
private NsdServiceInfo serviceInfo;
|
|
24
|
+
private Plugin plugin;
|
|
25
|
+
|
|
26
|
+
public NetworkDiscovery(Plugin plugin, Context context) {
|
|
27
|
+
this.plugin = plugin;
|
|
28
|
+
this.nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public void startAdvertising(
|
|
32
|
+
String serviceName,
|
|
33
|
+
String serviceType,
|
|
34
|
+
int port,
|
|
35
|
+
JSObject txtRecord,
|
|
36
|
+
AdvertisingCallback callback
|
|
37
|
+
) {
|
|
38
|
+
serviceInfo = new NsdServiceInfo();
|
|
39
|
+
serviceInfo.setServiceName(serviceName);
|
|
40
|
+
serviceInfo.setServiceType(serviceType);
|
|
41
|
+
serviceInfo.setPort(port);
|
|
42
|
+
|
|
43
|
+
// Agregar TXT records
|
|
44
|
+
if (txtRecord != null) {
|
|
45
|
+
Iterator<String> keys = txtRecord.keys();
|
|
46
|
+
while (keys.hasNext()) {
|
|
47
|
+
String key = keys.next();
|
|
48
|
+
try {
|
|
49
|
+
String value = txtRecord.getString(key);
|
|
50
|
+
serviceInfo.setAttribute(key, value);
|
|
51
|
+
} catch (Exception e) {
|
|
52
|
+
Log.e(TAG, "Error setting attribute: " + key, e);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
registrationListener = new NsdManager.RegistrationListener() {
|
|
58
|
+
@Override
|
|
59
|
+
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
|
60
|
+
Log.e(TAG, "Service registration failed: " + errorCode);
|
|
61
|
+
callback.onError("Registration failed with error code: " + errorCode);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Override
|
|
65
|
+
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
|
66
|
+
Log.e(TAG, "Service unregistration failed: " + errorCode);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@Override
|
|
70
|
+
public void onServiceRegistered(NsdServiceInfo serviceInfo) {
|
|
71
|
+
Log.d(TAG, "Service registered: " + serviceInfo.getServiceName());
|
|
72
|
+
callback.onSuccess();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@Override
|
|
76
|
+
public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
|
|
77
|
+
Log.d(TAG, "Service unregistered");
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public void stopAdvertising(StopCallback callback) {
|
|
85
|
+
if (registrationListener != null) {
|
|
86
|
+
try {
|
|
87
|
+
nsdManager.unregisterService(registrationListener);
|
|
88
|
+
registrationListener = null;
|
|
89
|
+
callback.onSuccess();
|
|
90
|
+
} catch (Exception e) {
|
|
91
|
+
callback.onError("Error stopping advertising: " + e.getMessage());
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
callback.onError("No active advertising to stop");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public void startDiscovery(String serviceType, DiscoveryCallback callback) {
|
|
99
|
+
discoveryListener = new NsdManager.DiscoveryListener() {
|
|
100
|
+
@Override
|
|
101
|
+
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
|
|
102
|
+
Log.e(TAG, "Discovery start failed: " + errorCode);
|
|
103
|
+
nsdManager.stopServiceDiscovery(this);
|
|
104
|
+
callback.onError("Discovery failed with error code: " + errorCode);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@Override
|
|
108
|
+
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
|
|
109
|
+
Log.e(TAG, "Discovery stop failed: " + errorCode);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@Override
|
|
113
|
+
public void onDiscoveryStarted(String serviceType) {
|
|
114
|
+
Log.d(TAG, "Service discovery started");
|
|
115
|
+
callback.onDiscoveryStarted();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@Override
|
|
119
|
+
public void onDiscoveryStopped(String serviceType) {
|
|
120
|
+
Log.d(TAG, "Service discovery stopped");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@Override
|
|
124
|
+
public void onServiceFound(NsdServiceInfo service) {
|
|
125
|
+
Log.d(TAG, "Service found: " + service.getServiceName());
|
|
126
|
+
|
|
127
|
+
nsdManager.resolveService(service, new NsdManager.ResolveListener() {
|
|
128
|
+
@Override
|
|
129
|
+
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
|
130
|
+
Log.e(TAG, "Resolve failed: " + errorCode);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@Override
|
|
134
|
+
public void onServiceResolved(NsdServiceInfo serviceInfo) {
|
|
135
|
+
Log.d(TAG, "Android: Service RESOLVED");
|
|
136
|
+
Log.d(TAG, " Name: " + serviceInfo.getServiceName());
|
|
137
|
+
Log.d(TAG, " Host: " + (serviceInfo.getHost() != null ? serviceInfo.getHost().getHostAddress() : "null"));
|
|
138
|
+
Log.d(TAG, " Port: " + serviceInfo.getPort());
|
|
139
|
+
|
|
140
|
+
JSObject serviceData = buildServiceObject(serviceInfo);
|
|
141
|
+
|
|
142
|
+
Log.d(TAG, "Android: Calling callback.onServiceFound with data: " + serviceData.toString());
|
|
143
|
+
|
|
144
|
+
callback.onServiceFound(serviceData);
|
|
145
|
+
|
|
146
|
+
Log.d(TAG, "Android: callback.onServiceFound COMPLETED");
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@Override
|
|
152
|
+
public void onServiceLost(NsdServiceInfo service) {
|
|
153
|
+
Log.d(TAG, "Service lost: " + service.getServiceName());
|
|
154
|
+
|
|
155
|
+
JSObject serviceData = new JSObject();
|
|
156
|
+
serviceData.put("serviceName", service.getServiceName());
|
|
157
|
+
serviceData.put("serviceType", service.getServiceType());
|
|
158
|
+
|
|
159
|
+
callback.onServiceLost(serviceData);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public void stopDiscovery(StopCallback callback) {
|
|
167
|
+
if (discoveryListener != null) {
|
|
168
|
+
try {
|
|
169
|
+
nsdManager.stopServiceDiscovery(discoveryListener);
|
|
170
|
+
discoveryListener = null;
|
|
171
|
+
callback.onSuccess();
|
|
172
|
+
} catch (Exception e) {
|
|
173
|
+
callback.onError("Error stopping discovery: " + e.getMessage());
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
callback.onError("No active discovery to stop");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private JSObject buildServiceObject(NsdServiceInfo serviceInfo) {
|
|
181
|
+
JSObject serviceData = new JSObject();
|
|
182
|
+
serviceData.put("serviceName", serviceInfo.getServiceName());
|
|
183
|
+
serviceData.put("serviceType", serviceInfo.getServiceType());
|
|
184
|
+
serviceData.put("hostName", serviceInfo.getHost() != null ? serviceInfo.getHost().getHostName() : "");
|
|
185
|
+
serviceData.put("port", serviceInfo.getPort());
|
|
186
|
+
|
|
187
|
+
// Agregar direcciones IP
|
|
188
|
+
InetAddress host = serviceInfo.getHost();
|
|
189
|
+
if (host != null) {
|
|
190
|
+
JSONArray addresses = new JSONArray();
|
|
191
|
+
addresses.put(host.getHostAddress());
|
|
192
|
+
serviceData.put("addresses", addresses);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Agregar TXT records
|
|
196
|
+
Map<String, byte[]> attributes = serviceInfo.getAttributes();
|
|
197
|
+
if (attributes != null && !attributes.isEmpty()) {
|
|
198
|
+
JSObject txtRecordObj = new JSObject();
|
|
199
|
+
for (Map.Entry<String, byte[]> entry : attributes.entrySet()) {
|
|
200
|
+
txtRecordObj.put(entry.getKey(), new String(entry.getValue()));
|
|
201
|
+
}
|
|
202
|
+
serviceData.put("txtRecord", txtRecordObj);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return serviceData;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Callbacks interfaces
|
|
209
|
+
public interface AdvertisingCallback {
|
|
210
|
+
void onSuccess();
|
|
211
|
+
void onError(String error);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public interface StopCallback {
|
|
215
|
+
void onSuccess();
|
|
216
|
+
void onError(String error);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public interface DiscoveryCallback {
|
|
220
|
+
void onDiscoveryStarted();
|
|
221
|
+
void onServiceFound(JSObject service);
|
|
222
|
+
void onServiceLost(JSObject service);
|
|
223
|
+
void onError(String error);
|
|
224
|
+
}
|
|
250
225
|
}
|
package/android/src/main/java/com/cappitolian/plugins/networkdiscovery/NetworkDiscoveryPlugin.java
CHANGED
|
@@ -8,6 +8,7 @@ import com.getcapacitor.annotation.CapacitorPlugin;
|
|
|
8
8
|
|
|
9
9
|
@CapacitorPlugin(name = "NetworkDiscovery")
|
|
10
10
|
public class NetworkDiscoveryPlugin extends Plugin {
|
|
11
|
+
|
|
11
12
|
private NetworkDiscovery implementation;
|
|
12
13
|
|
|
13
14
|
@Override
|
|
@@ -82,12 +83,24 @@ public class NetworkDiscoveryPlugin extends Plugin {
|
|
|
82
83
|
|
|
83
84
|
@Override
|
|
84
85
|
public void onServiceFound(JSObject service) {
|
|
85
|
-
|
|
86
|
+
// ✅ IMPORTANTE: Usar getBridge().executeOnMainThread
|
|
87
|
+
getBridge().executeOnMainThread(new Runnable() {
|
|
88
|
+
@Override
|
|
89
|
+
public void run() {
|
|
90
|
+
notifyListeners("serviceFound", service);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
@Override
|
|
89
96
|
public void onServiceLost(JSObject service) {
|
|
90
|
-
|
|
97
|
+
// ✅ IMPORTANTE: Usar getBridge().executeOnMainThread
|
|
98
|
+
getBridge().executeOnMainThread(new Runnable() {
|
|
99
|
+
@Override
|
|
100
|
+
public void run() {
|
|
101
|
+
notifyListeners("serviceLost", service);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
91
104
|
}
|
|
92
105
|
|
|
93
106
|
@Override
|
|
@@ -13,22 +13,13 @@ import Foundation
|
|
|
13
13
|
port: Int,
|
|
14
14
|
txtRecord: [String: String]?
|
|
15
15
|
) {
|
|
16
|
-
|
|
17
|
-
let normalizedServiceType = serviceType.hasSuffix(".") ? serviceType : serviceType + "."
|
|
18
|
-
|
|
19
|
-
print("📡 iOS: Starting advertising")
|
|
20
|
-
print(" Service name: \(serviceName)")
|
|
21
|
-
print(" Service type (normalized): \(normalizedServiceType)")
|
|
22
|
-
print(" Port: \(port)")
|
|
23
|
-
|
|
24
|
-
netService = NetService(domain: "local.", type: normalizedServiceType, name: serviceName, port: Int32(port))
|
|
16
|
+
netService = NetService(domain: "local.", type: serviceType, name: serviceName, port: Int32(port))
|
|
25
17
|
|
|
26
18
|
// Configurar TXT record
|
|
27
19
|
if let txtRecord = txtRecord, !txtRecord.isEmpty {
|
|
28
20
|
var txtData: [String: Data] = [:]
|
|
29
21
|
for (key, value) in txtRecord {
|
|
30
22
|
txtData[key] = value.data(using: .utf8)
|
|
31
|
-
print(" TXT Record: \(key) = \(value)")
|
|
32
23
|
}
|
|
33
24
|
let txtRecordData = NetService.data(fromTXTRecord: txtData)
|
|
34
25
|
netService?.setTXTRecord(txtRecordData)
|
|
@@ -39,26 +30,17 @@ import Foundation
|
|
|
39
30
|
}
|
|
40
31
|
|
|
41
32
|
@objc public func stopAdvertising() {
|
|
42
|
-
print("⛔ iOS: Stopping advertising")
|
|
43
33
|
netService?.stop()
|
|
44
34
|
netService = nil
|
|
45
35
|
}
|
|
46
36
|
|
|
47
37
|
@objc public func startDiscovery(serviceType: String, domain: String = "local.") {
|
|
48
|
-
// ✅ Normalizar service type
|
|
49
|
-
let normalizedServiceType = serviceType.hasSuffix(".") ? serviceType : serviceType + "."
|
|
50
|
-
|
|
51
|
-
print("🔍 iOS: Starting discovery")
|
|
52
|
-
print(" Service type (normalized): \(normalizedServiceType)")
|
|
53
|
-
print(" Domain: \(domain)")
|
|
54
|
-
|
|
55
38
|
netServiceBrowser = NetServiceBrowser()
|
|
56
39
|
netServiceBrowser?.delegate = self
|
|
57
|
-
netServiceBrowser?.searchForServices(ofType:
|
|
40
|
+
netServiceBrowser?.searchForServices(ofType: serviceType, inDomain: domain)
|
|
58
41
|
}
|
|
59
42
|
|
|
60
43
|
@objc public func stopDiscovery() {
|
|
61
|
-
print("⛔ iOS: Stopping discovery")
|
|
62
44
|
netServiceBrowser?.stop()
|
|
63
45
|
netServiceBrowser = nil
|
|
64
46
|
discoveredServices.removeAll()
|
|
@@ -67,60 +49,39 @@ import Foundation
|
|
|
67
49
|
|
|
68
50
|
// MARK: - NetServiceDelegate
|
|
69
51
|
extension NetworkDiscovery: NetServiceDelegate {
|
|
70
|
-
public func netServiceWillPublish(_ sender: NetService) {
|
|
71
|
-
print("🔄 iOS: Service WILL publish: \(sender.name)")
|
|
72
|
-
}
|
|
73
|
-
|
|
74
52
|
public func netServiceDidPublish(_ sender: NetService) {
|
|
75
|
-
print("
|
|
76
|
-
print(" Name: \(sender.name)")
|
|
77
|
-
print(" Type: \(sender.type)")
|
|
78
|
-
print(" Port: \(sender.port)")
|
|
53
|
+
print("Service published: \(sender.name)")
|
|
79
54
|
delegate?.advertisingDidStart()
|
|
80
55
|
}
|
|
81
56
|
|
|
82
57
|
public func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
|
|
83
|
-
print("
|
|
84
|
-
print(" Error dict: \(errorDict)")
|
|
58
|
+
print("Service did not publish: \(errorDict)")
|
|
85
59
|
let errorCode = errorDict[NetService.errorCode]?.intValue ?? -1
|
|
86
|
-
print(" Error code: \(errorCode)")
|
|
87
60
|
delegate?.advertisingDidFail(error: "Failed to publish service. Error code: \(errorCode)")
|
|
88
61
|
}
|
|
89
62
|
}
|
|
90
63
|
|
|
91
64
|
// MARK: - NetServiceBrowserDelegate
|
|
92
65
|
extension NetworkDiscovery: NetServiceBrowserDelegate {
|
|
93
|
-
public func netServiceBrowserWillSearch(_ browser: NetServiceBrowser) {
|
|
94
|
-
print("🔄 iOS: Browser WILL search")
|
|
95
|
-
}
|
|
96
|
-
|
|
97
66
|
public func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser) {
|
|
98
|
-
print("
|
|
67
|
+
print("Service discovery stopped")
|
|
99
68
|
}
|
|
100
69
|
|
|
101
70
|
public func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
|
|
102
|
-
print("
|
|
103
|
-
print(" Error dict: \(errorDict)")
|
|
71
|
+
print("Service discovery failed: \(errorDict)")
|
|
104
72
|
let errorCode = errorDict[NetService.errorCode]?.intValue ?? -1
|
|
105
|
-
print(" Error code: \(errorCode)")
|
|
106
73
|
delegate?.discoveryDidFail(error: "Discovery failed. Error code: \(errorCode)")
|
|
107
74
|
}
|
|
108
75
|
|
|
109
76
|
public func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
|
|
110
|
-
print("
|
|
111
|
-
print(" Name: \(service.name)")
|
|
112
|
-
print(" Type: \(service.type)")
|
|
113
|
-
print(" Domain: \(service.domain)")
|
|
114
|
-
print(" More coming: \(moreComing)")
|
|
115
|
-
|
|
77
|
+
print("Service found: \(service.name)")
|
|
116
78
|
discoveredServices.append(service)
|
|
117
79
|
service.delegate = self
|
|
118
80
|
service.resolve(withTimeout: 5.0)
|
|
119
81
|
}
|
|
120
82
|
|
|
121
83
|
public func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) {
|
|
122
|
-
print("
|
|
123
|
-
print(" Name: \(service.name)")
|
|
84
|
+
print("Service lost: \(service.name)")
|
|
124
85
|
|
|
125
86
|
let serviceData: [String: Any] = [
|
|
126
87
|
"serviceName": service.name,
|
|
@@ -134,33 +95,46 @@ extension NetworkDiscovery: NetServiceBrowserDelegate {
|
|
|
134
95
|
}
|
|
135
96
|
}
|
|
136
97
|
|
|
137
|
-
public func netServiceWillResolve(_ sender: NetService) {
|
|
138
|
-
print("🔄 iOS: Service WILL resolve: \(sender.name)")
|
|
139
|
-
}
|
|
140
|
-
|
|
141
98
|
public func netServiceDidResolveAddress(_ sender: NetService) {
|
|
142
|
-
print("
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
99
|
+
print("Service resolved: \(sender.name)")
|
|
100
|
+
|
|
101
|
+
var addresses: [String] = []
|
|
102
|
+
|
|
103
|
+
if let addressesData = sender.addresses {
|
|
104
|
+
for addressData in addressesData {
|
|
105
|
+
let address = addressData.withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> String? in
|
|
106
|
+
guard let baseAddress = pointer.baseAddress else { return nil }
|
|
107
|
+
let data = baseAddress.assumingMemoryBound(to: sockaddr.self)
|
|
108
|
+
|
|
109
|
+
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
|
110
|
+
if getnameinfo(data, socklen_t(addressData.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
|
|
111
|
+
return String(cString: hostname)
|
|
112
|
+
}
|
|
113
|
+
return nil
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if let addr = address {
|
|
117
|
+
addresses.append(addr)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
146
121
|
|
|
147
|
-
// ✅ NO incluir addresses - Solo usar txtRecord
|
|
148
122
|
var serviceData: [String: Any] = [
|
|
149
123
|
"serviceName": sender.name,
|
|
150
124
|
"serviceType": sender.type,
|
|
151
125
|
"domain": sender.domain,
|
|
152
126
|
"hostName": sender.hostName ?? "",
|
|
153
|
-
"port": sender.port
|
|
127
|
+
"port": sender.port,
|
|
128
|
+
"addresses": addresses
|
|
154
129
|
]
|
|
155
130
|
|
|
156
|
-
//
|
|
131
|
+
// Agregar TXT record
|
|
157
132
|
if let txtData = sender.txtRecordData() {
|
|
158
133
|
let txtRecord = NetService.dictionary(fromTXTRecord: txtData)
|
|
159
134
|
var txtRecordDict: [String: String] = [:]
|
|
160
135
|
for (key, value) in txtRecord {
|
|
161
136
|
if let strValue = String(data: value, encoding: .utf8) {
|
|
162
137
|
txtRecordDict[key] = strValue
|
|
163
|
-
print(" TXT Record retrieved: \(key) = \(strValue)")
|
|
164
138
|
}
|
|
165
139
|
}
|
|
166
140
|
serviceData["txtRecord"] = txtRecordDict
|
|
@@ -170,9 +144,7 @@ extension NetworkDiscovery: NetServiceBrowserDelegate {
|
|
|
170
144
|
}
|
|
171
145
|
|
|
172
146
|
public func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
|
|
173
|
-
print("
|
|
174
|
-
print(" Service: \(sender.name)")
|
|
175
|
-
print(" Error dict: \(errorDict)")
|
|
147
|
+
print("Service did not resolve: \(errorDict)")
|
|
176
148
|
}
|
|
177
149
|
}
|
|
178
150
|
|
|
@@ -2,32 +2,15 @@ import Foundation
|
|
|
2
2
|
import Capacitor
|
|
3
3
|
|
|
4
4
|
@objc(NetworkDiscoveryPlugin)
|
|
5
|
-
public class NetworkDiscoveryPlugin: CAPPlugin,
|
|
6
|
-
|
|
7
|
-
// MARK: - CAPBridgedPlugin Properties
|
|
8
|
-
public let identifier = "NetworkDiscoveryPlugin"
|
|
9
|
-
public let jsName = "NetworkDiscovery"
|
|
10
|
-
public let pluginMethods: [CAPPluginMethod] = [
|
|
11
|
-
CAPPluginMethod(name: "startAdvertising", returnType: CAPPluginReturnPromise),
|
|
12
|
-
CAPPluginMethod(name: "stopAdvertising", returnType: CAPPluginReturnPromise),
|
|
13
|
-
CAPPluginMethod(name: "startDiscovery", returnType: CAPPluginReturnPromise),
|
|
14
|
-
CAPPluginMethod(name: "stopDiscovery", returnType: CAPPluginReturnPromise)
|
|
15
|
-
]
|
|
16
|
-
|
|
17
|
-
// MARK: - Properties
|
|
5
|
+
public class NetworkDiscoveryPlugin: CAPPlugin, NetworkDiscoveryDelegate {
|
|
18
6
|
private var implementation: NetworkDiscovery?
|
|
19
7
|
|
|
20
|
-
|
|
21
|
-
public override func load() {
|
|
22
|
-
print("✅ NetworkDiscoveryPlugin: Plugin loaded")
|
|
8
|
+
override public func load() {
|
|
23
9
|
implementation = NetworkDiscovery()
|
|
24
10
|
implementation?.delegate = self
|
|
25
11
|
}
|
|
26
12
|
|
|
27
|
-
// MARK: - Plugin Methods
|
|
28
13
|
@objc func startAdvertising(_ call: CAPPluginCall) {
|
|
29
|
-
print("📞 NetworkDiscoveryPlugin: startAdvertising() called")
|
|
30
|
-
|
|
31
14
|
guard let serviceName = call.getString("serviceName"),
|
|
32
15
|
let serviceType = call.getString("serviceType"),
|
|
33
16
|
let port = call.getInt("port") else {
|
|
@@ -37,8 +20,6 @@ public class NetworkDiscoveryPlugin: CAPPlugin, CAPBridgedPlugin, NetworkDiscove
|
|
|
37
20
|
|
|
38
21
|
let txtRecord = call.getObject("txtRecord") as? [String: String]
|
|
39
22
|
|
|
40
|
-
print("📡 NetworkDiscoveryPlugin: Starting advertising - \(serviceName)")
|
|
41
|
-
|
|
42
23
|
implementation?.startAdvertising(
|
|
43
24
|
serviceName: serviceName,
|
|
44
25
|
serviceType: serviceType,
|
|
@@ -50,14 +31,11 @@ public class NetworkDiscoveryPlugin: CAPPlugin, CAPBridgedPlugin, NetworkDiscove
|
|
|
50
31
|
}
|
|
51
32
|
|
|
52
33
|
@objc func stopAdvertising(_ call: CAPPluginCall) {
|
|
53
|
-
print("📞 NetworkDiscoveryPlugin: stopAdvertising() called")
|
|
54
34
|
implementation?.stopAdvertising()
|
|
55
35
|
call.resolve(["success": true])
|
|
56
36
|
}
|
|
57
37
|
|
|
58
38
|
@objc func startDiscovery(_ call: CAPPluginCall) {
|
|
59
|
-
print("📞 NetworkDiscoveryPlugin: startDiscovery() called")
|
|
60
|
-
|
|
61
39
|
guard let serviceType = call.getString("serviceType") else {
|
|
62
40
|
call.reject("Missing serviceType parameter")
|
|
63
41
|
return
|
|
@@ -65,40 +43,33 @@ public class NetworkDiscoveryPlugin: CAPPlugin, CAPBridgedPlugin, NetworkDiscove
|
|
|
65
43
|
|
|
66
44
|
let domain = call.getString("domain") ?? "local."
|
|
67
45
|
|
|
68
|
-
print("🔍 NetworkDiscoveryPlugin: Starting discovery for \(serviceType)")
|
|
69
|
-
|
|
70
46
|
implementation?.startDiscovery(serviceType: serviceType, domain: domain)
|
|
71
47
|
call.resolve()
|
|
72
48
|
}
|
|
73
49
|
|
|
74
50
|
@objc func stopDiscovery(_ call: CAPPluginCall) {
|
|
75
|
-
print("📞 NetworkDiscoveryPlugin: stopDiscovery() called")
|
|
76
51
|
implementation?.stopDiscovery()
|
|
77
52
|
call.resolve(["success": true])
|
|
78
53
|
}
|
|
79
54
|
|
|
80
55
|
// MARK: - NetworkDiscoveryDelegate
|
|
81
56
|
public func advertisingDidStart() {
|
|
82
|
-
print("
|
|
57
|
+
print("Advertising started successfully")
|
|
83
58
|
}
|
|
84
59
|
|
|
85
60
|
public func advertisingDidFail(error: String) {
|
|
86
|
-
print("
|
|
61
|
+
print("Advertising failed: \(error)")
|
|
87
62
|
}
|
|
88
63
|
|
|
89
64
|
public func serviceFound(serviceData: [String : Any]) {
|
|
90
|
-
print("📨 NetworkDiscoveryPlugin: Service found, notifying listeners")
|
|
91
|
-
print(" Service data: \(serviceData)")
|
|
92
65
|
notifyListeners("serviceFound", data: serviceData)
|
|
93
66
|
}
|
|
94
67
|
|
|
95
68
|
public func serviceLost(serviceData: [String : Any]) {
|
|
96
|
-
print("📨 NetworkDiscoveryPlugin: Service lost, notifying listeners")
|
|
97
|
-
print(" Service data: \(serviceData)")
|
|
98
69
|
notifyListeners("serviceLost", data: serviceData)
|
|
99
70
|
}
|
|
100
71
|
|
|
101
72
|
public func discoveryDidFail(error: String) {
|
|
102
|
-
print("
|
|
73
|
+
print("Discovery failed: \(error)")
|
|
103
74
|
}
|
|
104
75
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cappitolian/network-discovery",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "A Capacitor plugin for network service discovery using mDNS/Bonjour. Allows automatic server-client connection without manual IP configuration.",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"prepublishOnly": "npm run build"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@capacitor/android": "^7.
|
|
56
|
-
"@capacitor/core": "^7.
|
|
55
|
+
"@capacitor/android": "^7.0.0",
|
|
56
|
+
"@capacitor/core": "^7.0.0",
|
|
57
57
|
"@capacitor/docgen": "^0.3.1",
|
|
58
|
-
"@capacitor/ios": "^7.
|
|
58
|
+
"@capacitor/ios": "^7.0.0",
|
|
59
59
|
"@ionic/eslint-config": "^0.4.0",
|
|
60
60
|
"@ionic/prettier-config": "^4.0.0",
|
|
61
61
|
"@ionic/swiftlint-config": "^2.0.0",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"typescript": "^5.9.3"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"@capacitor/core": "
|
|
71
|
+
"@capacitor/core": "^7.0.0"
|
|
72
72
|
},
|
|
73
73
|
"prettier": "@ionic/prettier-config",
|
|
74
74
|
"swiftlint": "@ionic/swiftlint-config",
|