react-native-zeroconf 0.17.4 → 1.0.0-rc.2
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/NOTICE +2 -6
- package/Package.swift +19 -3
- package/README.md +1 -3
- package/android/CMakeLists.txt +64 -0
- package/android/build.gradle +1 -17
- package/android/generated/java/com/balthazargronon/RCTZeroconf/NativeZeroconfSpec.java +96 -0
- package/android/generated/jni/CMakeLists.txt +28 -0
- package/android/generated/jni/RNZeroconfSpec-generated.cpp +77 -0
- package/android/generated/jni/RNZeroconfSpec.h +31 -0
- package/android/generated/jni/react/renderer/components/RNZeroconfSpec/RNZeroconfSpecJSI.h +798 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/{ZeroconfModule.java → NsdHost.java} +97 -140
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/NsdPayload.java +87 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/NsdPromise.java +40 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/Zeroconf.java +4 -6
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfNativeSupport.java +60 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfOptions.java +15 -26
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfReactPackage.java +5 -15
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/nsd/NsdServiceImpl.java +90 -96
- package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_clientshim.c +31 -6
- package/cpp/Backend.cpp +16 -0
- package/cpp/Backend.h +116 -0
- package/cpp/ZeroconfModule.cpp +280 -0
- package/cpp/ZeroconfModule.h +144 -0
- package/cpp/android/NsdBackend.cpp +462 -0
- package/cpp/android/NsdBackend.h +61 -0
- package/cpp/android/ZeroconfAndroidModule.cpp +49 -0
- package/cpp/android/ZeroconfAndroidModule.h +15 -0
- package/cpp/apple/DispatchExecutor.cpp +66 -0
- package/cpp/apple/DispatchExecutor.h +37 -0
- package/cpp/apple/LocalNetworkAccess.h +19 -0
- package/cpp/apple/LocalNetworkAccess.mm +87 -0
- package/cpp/dnssd/DnssdBackend.cpp +976 -0
- package/cpp/dnssd/DnssdBackend.h +114 -0
- package/cpp/dnssd/Executor.h +28 -0
- package/cpp/embedded/EmbeddedExecutor.cpp +124 -0
- package/cpp/embedded/EmbeddedExecutor.h +57 -0
- package/ios/ZeroconfOnLoad.mm +34 -0
- package/ios/generated/ReactCodegen/RNZeroconfSpec/RNZeroconfSpec-generated.mm +140 -0
- package/ios/generated/ReactCodegen/RNZeroconfSpec/RNZeroconfSpec.h +189 -0
- package/ios/generated/ReactCodegen/RNZeroconfSpecJSI.h +798 -0
- package/lib/module/NativeZeroconf.js +15 -0
- package/lib/module/NativeZeroconf.js.map +1 -0
- package/lib/module/bridge.js +124 -0
- package/lib/module/bridge.js.map +1 -0
- package/{dist → lib/module}/index.js +149 -149
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +24 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeZeroconf.d.ts +75 -0
- package/lib/typescript/src/NativeZeroconf.d.ts.map +1 -0
- package/lib/typescript/src/bridge.d.ts +22 -0
- package/lib/typescript/src/bridge.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +111 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +175 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +64 -29
- package/react-native-zeroconf.podspec +2 -1
- package/react-native.config.js +17 -0
- package/src/NativeZeroconf.ts +120 -0
- package/src/bridge.ts +153 -0
- package/src/index.ts +607 -0
- package/{index.d.ts → src/types.ts} +5 -99
- package/windows/RNZeroconf/RNZeroconf.vcxproj +17 -2
- package/windows/RNZeroconf/RNZeroconf.vcxproj.filters +0 -6
- package/windows/RNZeroconf/ReactPackageProvider.cpp +23 -20
- package/windows/RNZeroconf/WindowsBackend.cpp +156 -0
- package/windows/RNZeroconf/WindowsBackend.h +13 -0
- package/windows/RNZeroconf/ZeroconfCore.cpp +2 -2
- package/windows/RNZeroconf/ZeroconfCore.h +2 -2
- package/windows/RNZeroconf/ZeroconfWindowsModule.cpp +22 -0
- package/windows/RNZeroconf/ZeroconfWindowsModule.h +14 -0
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroConfImplFactory.java +0 -56
- package/android/src/main/java/com/balthazargronon/RCTZeroconf/dnssd/DnssdImpl.java +0 -654
- package/android/src/main/java/com/github/druk/dnssd/BaseListener.java +0 -33
- package/android/src/main/java/com/github/druk/dnssd/BrowseListener.java +0 -67
- package/android/src/main/java/com/github/druk/dnssd/DNSRecord.java +0 -47
- package/android/src/main/java/com/github/druk/dnssd/DNSSD.java +0 -681
- package/android/src/main/java/com/github/druk/dnssd/DNSSDEmbedded.java +0 -198
- package/android/src/main/java/com/github/druk/dnssd/DNSSDException.java +0 -66
- package/android/src/main/java/com/github/druk/dnssd/DNSSDRecordRegistrar.java +0 -55
- package/android/src/main/java/com/github/druk/dnssd/DNSSDRegistration.java +0 -54
- package/android/src/main/java/com/github/druk/dnssd/DNSSDService.java +0 -35
- package/android/src/main/java/com/github/druk/dnssd/DomainListener.java +0 -57
- package/android/src/main/java/com/github/druk/dnssd/InternalBrowseListener.java +0 -76
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSD.java +0 -870
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRecordRegistrar.java +0 -30
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRegistration.java +0 -34
- package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDService.java +0 -29
- package/android/src/main/java/com/github/druk/dnssd/InternalDomainListener.java +0 -62
- package/android/src/main/java/com/github/druk/dnssd/InternalQueryListener.java +0 -61
- package/android/src/main/java/com/github/druk/dnssd/InternalRegisterListener.java +0 -51
- package/android/src/main/java/com/github/druk/dnssd/InternalResolveListener.java +0 -58
- package/android/src/main/java/com/github/druk/dnssd/NSClass.java +0 -16
- package/android/src/main/java/com/github/druk/dnssd/NSType.java +0 -58
- package/android/src/main/java/com/github/druk/dnssd/QueryListener.java +0 -54
- package/android/src/main/java/com/github/druk/dnssd/RegisterListener.java +0 -46
- package/android/src/main/java/com/github/druk/dnssd/RegisterRecordListener.java +0 -35
- package/android/src/main/java/com/github/druk/dnssd/ResolveListener.java +0 -55
- package/android/src/main/java/com/github/druk/dnssd/TXTRecord.java +0 -293
- package/android/src/main/jni/Android.mk +0 -73
- package/android/src/main/jni/Application.mk +0 -3
- package/android/src/main/jni/DNSSD.java.h +0 -290
- package/android/src/main/jni/JNISupport.c +0 -1221
- package/ios/RNZeroconf/RNNetServiceSerializer.h +0 -31
- package/ios/RNZeroconf/RNNetServiceSerializer.m +0 -84
- package/ios/RNZeroconf/RNZeroconf.h +0 -17
- package/ios/RNZeroconf/RNZeroconf.m +0 -1025
- package/ios/RNZeroconf.xcodeproj/project.pbxproj +0 -261
- package/ios/RNZeroconf.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/src/index.js +0 -563
- package/windows/RNZeroconf/RNZeroconf.cpp +0 -228
- package/windows/RNZeroconf/RNZeroconf.h +0 -70
package/android/src/main/java/com/balthazargronon/RCTZeroconf/{ZeroconfModule.java → NsdHost.java}
RENAMED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package com.balthazargronon.RCTZeroconf;
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import android.content.Context;
|
|
5
4
|
import android.content.pm.PackageManager;
|
|
6
5
|
import android.net.ConnectivityManager;
|
|
@@ -9,25 +8,21 @@ import android.net.Network;
|
|
|
9
8
|
import android.os.Build;
|
|
10
9
|
import android.util.Log;
|
|
11
10
|
|
|
12
|
-
import com.
|
|
13
|
-
import com.facebook.
|
|
14
|
-
import com.facebook.react.bridge.ReactContext;
|
|
15
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
16
|
-
import com.facebook.react.bridge.ReactMethod;
|
|
17
|
-
import com.facebook.react.bridge.ReadableArray;
|
|
18
|
-
import com.facebook.react.bridge.ReadableMap;
|
|
19
|
-
import com.facebook.react.bridge.WritableMap;
|
|
20
|
-
import com.facebook.react.bridge.WritableNativeMap;
|
|
21
|
-
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
11
|
+
import com.balthazargronon.RCTZeroconf.nsd.NsdServiceImpl;
|
|
12
|
+
import com.facebook.proguard.annotations.DoNotStrip;
|
|
22
13
|
|
|
23
|
-
import
|
|
14
|
+
import java.util.LinkedHashMap;
|
|
15
|
+
import java.util.Map;
|
|
24
16
|
|
|
17
|
+
import javax.annotation.Nullable;
|
|
25
18
|
|
|
26
19
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
20
|
+
* Android NSD for the C++ module (cpp/android/NsdBackend): it calls these methods through JNI, events,
|
|
21
|
+
* errors and results come back through native methods. Also the constants and helpers of the NSD code.
|
|
29
22
|
*/
|
|
30
|
-
|
|
23
|
+
@DoNotStrip
|
|
24
|
+
public final class NsdHost {
|
|
25
|
+
private static final String TAG = "NsdHost";
|
|
31
26
|
|
|
32
27
|
public static final String EVENT_START = "RNZeroconfStart";
|
|
33
28
|
public static final String EVENT_STOP = "RNZeroconfStop";
|
|
@@ -50,7 +45,6 @@ public class ZeroconfModule extends ReactContextBaseJavaModule {
|
|
|
50
45
|
|
|
51
46
|
// Where an error code comes from
|
|
52
47
|
public static final String ERROR_DOMAIN_NSD = "NsdManager";
|
|
53
|
-
public static final String ERROR_DOMAIN_DNSSD = "DNSSD";
|
|
54
48
|
public static final String ERROR_DOMAIN_LIBRARY = "RNZeroconf";
|
|
55
49
|
public static final String ERROR_CODE_EXCEPTION = "EXCEPTION";
|
|
56
50
|
public static final String ERROR_CODE_TIMEOUT = "TIMEOUT";
|
|
@@ -60,121 +54,137 @@ public class ZeroconfModule extends ReactContextBaseJavaModule {
|
|
|
60
54
|
public static final String PERMISSION_ACCESS_LOCAL_NETWORK = "android.permission.ACCESS_LOCAL_NETWORK";
|
|
61
55
|
public static final String ERROR_CODE_NOT_PUBLISHED = "NOT_PUBLISHED";
|
|
62
56
|
|
|
63
|
-
|
|
57
|
+
// The C++ backend's id, 0 once it is gone
|
|
58
|
+
private volatile long handle;
|
|
59
|
+
private final Context context;
|
|
60
|
+
private final NsdServiceImpl nsd;
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
@DoNotStrip
|
|
63
|
+
public NsdHost(long handle) {
|
|
64
|
+
this.handle = handle;
|
|
65
|
+
this.context = ZeroconfNativeSupport.application();
|
|
66
|
+
this.nsd = new NsdServiceImpl(this, context);
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return "RNZeroconf";
|
|
69
|
+
public Context getContext() {
|
|
70
|
+
return context;
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
@
|
|
76
|
-
public void scan(String scanId, String type, String protocol, String domain, String
|
|
73
|
+
@DoNotStrip
|
|
74
|
+
public void scan(String scanId, String type, String protocol, String domain, String subtype, String networkInterface, double resolveTimeout) {
|
|
77
75
|
try {
|
|
78
|
-
|
|
76
|
+
nsd.scan(scanId, type, protocol, domain, new ZeroconfOptions(subtype, null, networkInterface, 5, resolveTimeout));
|
|
79
77
|
} catch (Throwable e) {
|
|
80
|
-
Log.e(
|
|
78
|
+
Log.e(TAG, e.getMessage(), e);
|
|
81
79
|
sendError(ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, "Exception during scan: " + e.getMessage(), null, scanId);
|
|
82
80
|
}
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@ReactMethod
|
|
89
|
-
public void stop(@Nullable String scanId, String implType) {
|
|
83
|
+
// Stops the scan with this id, or every scan without one
|
|
84
|
+
@DoNotStrip
|
|
85
|
+
public void stop(String scanId) {
|
|
90
86
|
try {
|
|
91
|
-
Zeroconf impl = getZeroconfImpl(implType);
|
|
92
87
|
if (scanId == null || scanId.isEmpty()) {
|
|
93
|
-
|
|
88
|
+
nsd.stopAll();
|
|
94
89
|
} else {
|
|
95
|
-
|
|
90
|
+
nsd.stop(scanId);
|
|
96
91
|
}
|
|
97
92
|
} catch (Throwable e) {
|
|
98
|
-
Log.e(
|
|
93
|
+
Log.e(TAG, e.getMessage(), e);
|
|
99
94
|
sendError(ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, "Exception during stop: " + e.getMessage(), null, scanId);
|
|
100
95
|
}
|
|
101
96
|
}
|
|
102
97
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
@ReactMethod
|
|
108
|
-
public void registerService(String type, String protocol, String domain, String name, int port, ReadableArray txt, String implType, @Nullable ReadableMap options, Promise promise) {
|
|
98
|
+
@DoNotStrip
|
|
99
|
+
public void registerService(String type, String protocol, String domain, String name, int port, String[] txtKeys, String[] txtValues,
|
|
100
|
+
String[] subtypes, String networkInterface, NsdPromise promise) {
|
|
109
101
|
try {
|
|
110
|
-
|
|
102
|
+
nsd.registerService(type, protocol, domain, name, port, txt(txtKeys, txtValues),
|
|
103
|
+
new ZeroconfOptions(null, subtypes, networkInterface, 5, 5), promise);
|
|
111
104
|
} catch (Throwable e) {
|
|
112
|
-
Log.e(
|
|
105
|
+
Log.e(TAG, e.getMessage(), e);
|
|
113
106
|
String message = "Exception while registering service: " + e.getMessage();
|
|
114
107
|
sendError(ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, message, name);
|
|
115
108
|
reject(promise, ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, message, name);
|
|
116
109
|
}
|
|
117
110
|
}
|
|
118
111
|
|
|
119
|
-
@
|
|
120
|
-
public void updateService(String
|
|
112
|
+
@DoNotStrip
|
|
113
|
+
public void updateService(String name, String[] txtKeys, String[] txtValues, NsdPromise promise) {
|
|
114
|
+
try {
|
|
115
|
+
nsd.updateService(name, txt(txtKeys, txtValues), promise);
|
|
116
|
+
} catch (Throwable e) {
|
|
117
|
+
Log.e(TAG, e.getMessage(), e);
|
|
118
|
+
reject(promise, ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, "Exception while updating service: " + e.getMessage(), name);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@DoNotStrip
|
|
123
|
+
public void unregisterService(String name, NsdPromise promise) {
|
|
121
124
|
try {
|
|
122
|
-
|
|
125
|
+
nsd.unregisterService(name, promise);
|
|
123
126
|
} catch (Throwable e) {
|
|
124
|
-
Log.e(
|
|
125
|
-
|
|
127
|
+
Log.e(TAG, e.getMessage(), e);
|
|
128
|
+
String message = "Exception while unregistering service: " + e.getMessage();
|
|
129
|
+
sendError(ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, message, name);
|
|
130
|
+
reject(promise, ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, message, name);
|
|
126
131
|
}
|
|
127
132
|
}
|
|
128
133
|
|
|
129
|
-
@
|
|
130
|
-
public void resolveService(String name, String type, String protocol, String domain, String
|
|
134
|
+
@DoNotStrip
|
|
135
|
+
public void resolveService(String name, String type, String protocol, String domain, String networkInterface, double timeout, NsdPromise promise) {
|
|
131
136
|
try {
|
|
132
|
-
|
|
137
|
+
nsd.resolveService(name, type, protocol, domain, new ZeroconfOptions(null, null, networkInterface, timeout, 5), promise);
|
|
133
138
|
} catch (Throwable e) {
|
|
134
|
-
Log.e(
|
|
139
|
+
Log.e(TAG, e.getMessage(), e);
|
|
135
140
|
reject(promise, ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, "Exception while resolving service: " + e.getMessage(), name);
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
143
|
|
|
144
|
+
// Stops the scans and unpublishes the services, when the module goes away
|
|
145
|
+
@DoNotStrip
|
|
146
|
+
public void shutdown() {
|
|
147
|
+
try {
|
|
148
|
+
nsd.stopAll();
|
|
149
|
+
nsd.unregisterAllServices();
|
|
150
|
+
} catch (Throwable e) {
|
|
151
|
+
Log.e(TAG, e.getMessage(), e);
|
|
152
|
+
}
|
|
153
|
+
handle = 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
139
156
|
/**
|
|
140
|
-
*
|
|
157
|
+
* "granted" or "denied". On Android 17 (API 37) devices, the ACCESS_LOCAL_NETWORK runtime permission
|
|
141
158
|
* is enforced for apps targeting API 37 and for apps declaring it in their manifest. Otherwise there is nothing to grant.
|
|
142
159
|
*/
|
|
143
|
-
@
|
|
144
|
-
public
|
|
145
|
-
Context context =
|
|
160
|
+
@DoNotStrip
|
|
161
|
+
public static String checkLocalNetworkAccess() {
|
|
162
|
+
Context context = ZeroconfNativeSupport.application();
|
|
163
|
+
if (context == null) {
|
|
164
|
+
return "unknown";
|
|
165
|
+
}
|
|
146
166
|
boolean required = Build.VERSION.SDK_INT >= 37
|
|
147
167
|
&& (context.getApplicationInfo().targetSdkVersion >= 37 || declaresPermission(context, PERMISSION_ACCESS_LOCAL_NETWORK));
|
|
148
168
|
if (!required) {
|
|
149
|
-
|
|
150
|
-
return;
|
|
169
|
+
return "granted";
|
|
151
170
|
}
|
|
152
171
|
boolean granted = context.checkSelfPermission(PERMISSION_ACCESS_LOCAL_NETWORK) == PackageManager.PERMISSION_GRANTED;
|
|
153
|
-
|
|
172
|
+
return granted ? "granted" : "denied";
|
|
154
173
|
}
|
|
155
174
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
} catch (Throwable e) {
|
|
161
|
-
Log.e(getClass().getName(), e.getMessage(), e);
|
|
162
|
-
String message = "Exception while unregistering service: " + e.getMessage();
|
|
163
|
-
sendError(ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, message, serviceName);
|
|
164
|
-
reject(promise, ERROR_DOMAIN_LIBRARY, ERROR_CODE_EXCEPTION, message, serviceName);
|
|
175
|
+
private static Map<String, String> txt(String[] keys, String[] values) {
|
|
176
|
+
Map<String, String> txt = new LinkedHashMap<>();
|
|
177
|
+
for (int i = 0; i < keys.length && i < values.length; i++) {
|
|
178
|
+
txt.put(keys[i], values[i]);
|
|
165
179
|
}
|
|
180
|
+
return txt;
|
|
166
181
|
}
|
|
167
182
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
174
|
-
.emit(eventName, params);
|
|
175
|
-
} catch (Throwable e) {
|
|
176
|
-
// The JS side may already be gone, e.g. callbacks arriving during teardown
|
|
177
|
-
Log.w(getClass().getName(), "Could not send " + eventName + ": " + e.getMessage());
|
|
183
|
+
// Events of the NSD code, with the scan id in the payload for scan events
|
|
184
|
+
public void sendEvent(String eventName, NsdPayload body) {
|
|
185
|
+
long current = handle;
|
|
186
|
+
if (current != 0) {
|
|
187
|
+
nativeEvent(current, eventName, body);
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
190
|
|
|
@@ -191,35 +201,17 @@ public class ZeroconfModule extends ReactContextBaseJavaModule {
|
|
|
191
201
|
* @param scanId the scan the error belongs to, null for errors not related to a scan
|
|
192
202
|
*/
|
|
193
203
|
public void sendError(String domain, Object code, String message, @Nullable String serviceName, @Nullable String scanId) {
|
|
194
|
-
|
|
195
|
-
if (
|
|
196
|
-
|
|
204
|
+
long current = handle;
|
|
205
|
+
if (current != 0) {
|
|
206
|
+
nativeError(current, scanId == null ? "" : scanId, domain, String.valueOf(code), message, serviceName == null ? "" : serviceName);
|
|
197
207
|
}
|
|
198
|
-
sendEvent(getReactApplicationContext(), EVENT_ERROR, error);
|
|
199
208
|
}
|
|
200
209
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
*/
|
|
204
|
-
public static void reject(@Nullable Promise promise, String domain, Object code, String message, @Nullable String serviceName) {
|
|
210
|
+
// Rejects a call with the same { message, code, domain, serviceName } as error events
|
|
211
|
+
public static void reject(@Nullable NsdPromise promise, String domain, Object code, String message, @Nullable String serviceName) {
|
|
205
212
|
if (promise != null) {
|
|
206
|
-
promise.reject(String.valueOf(code), message,
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private static WritableMap buildError(String domain, Object code, String message, @Nullable String serviceName) {
|
|
211
|
-
WritableMap error = new WritableNativeMap();
|
|
212
|
-
error.putString("message", message);
|
|
213
|
-
error.putString("domain", domain);
|
|
214
|
-
if (code instanceof Integer) {
|
|
215
|
-
error.putInt("code", (Integer) code);
|
|
216
|
-
} else {
|
|
217
|
-
error.putString("code", String.valueOf(code));
|
|
218
|
-
}
|
|
219
|
-
if (serviceName != null) {
|
|
220
|
-
error.putString("serviceName", serviceName);
|
|
213
|
+
promise.reject(domain, String.valueOf(code), message, serviceName);
|
|
221
214
|
}
|
|
222
|
-
return error;
|
|
223
215
|
}
|
|
224
216
|
|
|
225
217
|
public static final String SERVICE_TYPES_TYPE = "services._dns-sd";
|
|
@@ -296,42 +288,7 @@ public class ZeroconfModule extends ReactContextBaseJavaModule {
|
|
|
296
288
|
}
|
|
297
289
|
}
|
|
298
290
|
|
|
299
|
-
|
|
300
|
-
* Readable description of a DNSServiceErrorType code, as on iOS
|
|
301
|
-
*/
|
|
302
|
-
public static String describeDnssdError(int errorCode) {
|
|
303
|
-
switch (errorCode) {
|
|
304
|
-
case -65548: return "name already in use"; // kDNSServiceErr_NameConflict
|
|
305
|
-
case -65540: return "bad parameter"; // kDNSServiceErr_BadParam
|
|
306
|
-
case -65538: return "no such name"; // kDNSServiceErr_NoSuchName
|
|
307
|
-
case -65554: return "no such record"; // kDNSServiceErr_NoSuchRecord
|
|
308
|
-
case -65563: return "mDNSResponder is not running"; // kDNSServiceErr_ServiceNotRunning
|
|
309
|
-
case -65539: return "out of memory"; // kDNSServiceErr_NoMemory
|
|
310
|
-
case -65544: return "unsupported"; // kDNSServiceErr_Unsupported
|
|
311
|
-
default: return "error " + errorCode;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Called on teardown by current React Native versions.
|
|
316
|
-
// No @Override so it still compiles against versions that don't declare it.
|
|
317
|
-
public void invalidate() {
|
|
318
|
-
teardown();
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Called on teardown by older React Native versions, deprecated in favor of invalidate().
|
|
322
|
-
// No @Override so it still compiles once it is removed.
|
|
323
|
-
public void onCatalystInstanceDestroy() {
|
|
324
|
-
teardown();
|
|
325
|
-
}
|
|
291
|
+
private static native void nativeEvent(long handle, String eventName, NsdPayload body);
|
|
326
292
|
|
|
327
|
-
private void
|
|
328
|
-
try {
|
|
329
|
-
for (Zeroconf impl : zeroConfFactory.getCreatedImpls()) {
|
|
330
|
-
impl.stopAll();
|
|
331
|
-
impl.unregisterAllServices();
|
|
332
|
-
}
|
|
333
|
-
} catch (Throwable e) {
|
|
334
|
-
Log.e(getClass().getName(), e.getMessage(), e);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
293
|
+
private static native void nativeError(long handle, String scanId, String domain, String code, String message, String serviceName);
|
|
337
294
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
package com.balthazargronon.RCTZeroconf;
|
|
2
|
+
|
|
3
|
+
import com.facebook.proguard.annotations.DoNotStrip;
|
|
4
|
+
|
|
5
|
+
import java.util.ArrayList;
|
|
6
|
+
import java.util.LinkedHashMap;
|
|
7
|
+
import java.util.List;
|
|
8
|
+
import java.util.Map;
|
|
9
|
+
|
|
10
|
+
import javax.annotation.Nullable;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* An event or result of the NSD implementation, read by the C++ module (cpp/android/NsdBackend) through JNI:
|
|
14
|
+
* a service's name, full name, host, port, addresses and TXT record.
|
|
15
|
+
*/
|
|
16
|
+
@DoNotStrip
|
|
17
|
+
public final class NsdPayload {
|
|
18
|
+
private final Map<String, Object> values = new LinkedHashMap<>();
|
|
19
|
+
|
|
20
|
+
public void putString(String key, @Nullable String value) {
|
|
21
|
+
values.put(key, value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public void putInt(String key, int value) {
|
|
25
|
+
values.put(key, value);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public void putArray(String key, List<String> value) {
|
|
29
|
+
values.put(key, new ArrayList<>(value));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public void putMap(String key, NsdPayload value) {
|
|
33
|
+
values.put(key, value);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@DoNotStrip
|
|
37
|
+
@Nullable
|
|
38
|
+
public String getString(String key) {
|
|
39
|
+
Object value = values.get(key);
|
|
40
|
+
return value instanceof String ? (String) value : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@DoNotStrip
|
|
44
|
+
public int getInt(String key) {
|
|
45
|
+
Object value = values.get(key);
|
|
46
|
+
return value instanceof Integer ? (Integer) value : 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@DoNotStrip
|
|
50
|
+
public String[] getStrings(String key) {
|
|
51
|
+
Object value = values.get(key);
|
|
52
|
+
if (!(value instanceof List)) {
|
|
53
|
+
return new String[0];
|
|
54
|
+
}
|
|
55
|
+
List<?> list = (List<?>) value;
|
|
56
|
+
String[] strings = new String[list.size()];
|
|
57
|
+
for (int i = 0; i < strings.length; i++) {
|
|
58
|
+
strings[i] = String.valueOf(list.get(i));
|
|
59
|
+
}
|
|
60
|
+
return strings;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The keys, then the values, of a nested map of strings (the TXT record), in order
|
|
64
|
+
@DoNotStrip
|
|
65
|
+
public String[] getMapKeys(String key) {
|
|
66
|
+
Object value = values.get(key);
|
|
67
|
+
if (!(value instanceof NsdPayload)) {
|
|
68
|
+
return new String[0];
|
|
69
|
+
}
|
|
70
|
+
return ((NsdPayload) value).values.keySet().toArray(new String[0]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@DoNotStrip
|
|
74
|
+
public String[] getMapValues(String key) {
|
|
75
|
+
Object value = values.get(key);
|
|
76
|
+
if (!(value instanceof NsdPayload)) {
|
|
77
|
+
return new String[0];
|
|
78
|
+
}
|
|
79
|
+
Map<String, Object> map = ((NsdPayload) value).values;
|
|
80
|
+
String[] strings = new String[map.size()];
|
|
81
|
+
int i = 0;
|
|
82
|
+
for (Object entry : map.values()) {
|
|
83
|
+
strings[i++] = entry == null ? "" : String.valueOf(entry);
|
|
84
|
+
}
|
|
85
|
+
return strings;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package com.balthazargronon.RCTZeroconf;
|
|
2
|
+
|
|
3
|
+
import com.facebook.proguard.annotations.DoNotStrip;
|
|
4
|
+
|
|
5
|
+
import javax.annotation.Nullable;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Settles a call of the C++ module (cpp/android/NsdBackend) once: with a service, or with
|
|
9
|
+
* { domain, code, message, serviceName }.
|
|
10
|
+
*/
|
|
11
|
+
@DoNotStrip
|
|
12
|
+
public final class NsdPromise {
|
|
13
|
+
private final long id;
|
|
14
|
+
private boolean settled = false;
|
|
15
|
+
|
|
16
|
+
@DoNotStrip
|
|
17
|
+
public NsdPromise(long id) {
|
|
18
|
+
this.id = id;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public synchronized void resolve(@Nullable NsdPayload service) {
|
|
22
|
+
if (settled) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
settled = true;
|
|
26
|
+
nativeResolve(id, service);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public synchronized void reject(String domain, String code, String message, @Nullable String serviceName) {
|
|
30
|
+
if (settled) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
settled = true;
|
|
34
|
+
nativeReject(id, domain, code, message, serviceName == null ? "" : serviceName);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private static native void nativeResolve(long id, @Nullable NsdPayload service);
|
|
38
|
+
|
|
39
|
+
private static native void nativeReject(long id, String domain, String code, String message, String serviceName);
|
|
40
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
package com.balthazargronon.RCTZeroconf;
|
|
2
2
|
|
|
3
|
-
import com.facebook.react.bridge.Promise;
|
|
4
|
-
import com.facebook.react.bridge.ReadableArray;
|
|
5
3
|
|
|
6
4
|
import javax.annotation.Nullable;
|
|
7
5
|
|
|
@@ -19,23 +17,23 @@ public interface Zeroconf {
|
|
|
19
17
|
/**
|
|
20
18
|
* @param promise resolved with the service once unregistered, null when nobody waits for it
|
|
21
19
|
*/
|
|
22
|
-
public void unregisterService(String serviceName, @Nullable
|
|
20
|
+
public void unregisterService(String serviceName, @Nullable NsdPromise promise);
|
|
23
21
|
|
|
24
22
|
/**
|
|
25
23
|
* @param txt TXT records as ordered [key, value] pairs
|
|
26
24
|
* @param promise resolved with the service once registered
|
|
27
25
|
*/
|
|
28
|
-
public void registerService(String type, String protocol, String domain, String name, int port,
|
|
26
|
+
public void registerService(String type, String protocol, String domain, String name, int port, java.util.Map<String, String> txt, ZeroconfOptions options, NsdPromise promise);
|
|
29
27
|
|
|
30
28
|
/**
|
|
31
29
|
* Replaces the TXT record of a published service
|
|
32
30
|
*/
|
|
33
|
-
void updateService(String serviceName,
|
|
31
|
+
void updateService(String serviceName, java.util.Map<String, String> txt, NsdPromise promise);
|
|
34
32
|
|
|
35
33
|
/**
|
|
36
34
|
* Resolves one service by name, without scanning
|
|
37
35
|
*/
|
|
38
|
-
void resolveService(String name, String type, String protocol, String domain, ZeroconfOptions options,
|
|
36
|
+
void resolveService(String name, String type, String protocol, String domain, ZeroconfOptions options, NsdPromise promise);
|
|
39
37
|
|
|
40
38
|
/**
|
|
41
39
|
* Unregister every service published through this implementation
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
package com.balthazargronon.RCTZeroconf;
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint;
|
|
4
|
+
import android.app.Application;
|
|
5
|
+
import android.content.Context;
|
|
6
|
+
import android.net.wifi.WifiManager;
|
|
7
|
+
import android.util.Log;
|
|
8
|
+
|
|
9
|
+
import com.facebook.proguard.annotations.DoNotStrip;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Android services for the C++ module (cpp/android): it calls these through JNI.
|
|
13
|
+
*/
|
|
14
|
+
@DoNotStrip
|
|
15
|
+
public final class ZeroconfNativeSupport {
|
|
16
|
+
private static final String TAG = "ZeroconfNativeSupport";
|
|
17
|
+
|
|
18
|
+
private static WifiManager.MulticastLock multicastLock;
|
|
19
|
+
|
|
20
|
+
private ZeroconfNativeSupport() {}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Android drops multicast packets unless an app holds a multicast lock: held while scans, resolves
|
|
24
|
+
* or published services are active, released when there are none.
|
|
25
|
+
*/
|
|
26
|
+
@DoNotStrip
|
|
27
|
+
public static synchronized void setMulticastLock(boolean held) {
|
|
28
|
+
if (held) {
|
|
29
|
+
if (multicastLock == null) {
|
|
30
|
+
Context context = application();
|
|
31
|
+
if (context == null) {
|
|
32
|
+
Log.w(TAG, "No application context, multicast stays filtered");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
@SuppressLint("WifiManagerLeak")
|
|
36
|
+
WifiManager wifi = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
|
37
|
+
if (wifi == null) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
multicastLock = wifi.createMulticastLock("react-native-zeroconf");
|
|
41
|
+
multicastLock.setReferenceCounted(false);
|
|
42
|
+
}
|
|
43
|
+
multicastLock.acquire();
|
|
44
|
+
} else if (multicastLock != null && multicastLock.isHeld()) {
|
|
45
|
+
multicastLock.release();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// The application, without a ReactContext: the C++ module has none
|
|
50
|
+
static Context application() {
|
|
51
|
+
try {
|
|
52
|
+
@SuppressLint("PrivateApi")
|
|
53
|
+
Class<?> activityThread = Class.forName("android.app.ActivityThread");
|
|
54
|
+
return (Application) activityThread.getMethod("currentApplication").invoke(null);
|
|
55
|
+
} catch (Exception e) {
|
|
56
|
+
Log.w(TAG, "Cannot get the application", e);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
package com.balthazargronon.RCTZeroconf;
|
|
2
2
|
|
|
3
|
-
import com.facebook.react.bridge.ReadableArray;
|
|
4
|
-
import com.facebook.react.bridge.ReadableMap;
|
|
5
|
-
import com.facebook.react.bridge.ReadableType;
|
|
6
3
|
|
|
7
4
|
import java.util.ArrayList;
|
|
8
5
|
import java.util.List;
|
|
@@ -24,30 +21,27 @@ public class ZeroconfOptions {
|
|
|
24
21
|
/** Scan: seconds to resolve each service, retried once before a TIMEOUT error */
|
|
25
22
|
public double resolveTimeoutSeconds = 5;
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
String label = subtypes.getType(i) == ReadableType.String ? subtypeLabel(subtypes.getString(i)) : null;
|
|
24
|
+
/**
|
|
25
|
+
* @param timeout resolveService's timeout in seconds, ignored unless positive
|
|
26
|
+
* @param resolveTimeout scans' resolve timeout in seconds, ignored unless positive
|
|
27
|
+
*/
|
|
28
|
+
public ZeroconfOptions(@Nullable String subtype, @Nullable String[] subtypes, @Nullable String networkInterface, double timeout, double resolveTimeout) {
|
|
29
|
+
this.subtype = subtypeLabel(subtype);
|
|
30
|
+
if (subtypes != null) {
|
|
31
|
+
for (String candidate : subtypes) {
|
|
32
|
+
String label = subtypeLabel(candidate);
|
|
37
33
|
if (label != null) {
|
|
38
|
-
|
|
34
|
+
this.subtypes.add(label);
|
|
39
35
|
}
|
|
40
36
|
}
|
|
41
37
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
options.timeoutSeconds = map.getDouble("timeout");
|
|
38
|
+
this.networkInterface = networkInterface == null || networkInterface.isEmpty() ? null : networkInterface;
|
|
39
|
+
if (timeout > 0) {
|
|
40
|
+
this.timeoutSeconds = timeout;
|
|
46
41
|
}
|
|
47
|
-
if (
|
|
48
|
-
|
|
42
|
+
if (resolveTimeout > 0) {
|
|
43
|
+
this.resolveTimeoutSeconds = resolveTimeout;
|
|
49
44
|
}
|
|
50
|
-
return options;
|
|
51
45
|
}
|
|
52
46
|
|
|
53
47
|
/**
|
|
@@ -61,11 +55,6 @@ public class ZeroconfOptions {
|
|
|
61
55
|
return type.toString();
|
|
62
56
|
}
|
|
63
57
|
|
|
64
|
-
@Nullable
|
|
65
|
-
private static String getString(ReadableMap map, String key) {
|
|
66
|
-
return map.hasKey(key) && map.getType(key) == ReadableType.String ? map.getString(key) : null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
58
|
// "printer" or "_printer" -> "_printer"
|
|
70
59
|
@Nullable
|
|
71
60
|
private static String subtypeLabel(@Nullable String subtype) {
|