Open oscadev opened 4 years ago
Same issue for me as well, please help to resolve
Same issue. Any solution?
I have same issue.
found
event is firing, but resolved
is not.
zeroconf.getServices()
returns object with name field only.
This npm package [1]: https://github.com/tableau/react-native-dns-lookup is the only option if you want to get the ip address (local ip too) using mdns hostname.
Here is an example by the contributor
I got mine working, on Android it turns out battery optimizations were causing the resolve failures, I set com.android.server.NetworkPermissionConfig to 'don't optimise' in my android settings under: Apps & Notifications -> Advanced -> Special App Access -> Battery Optimization, now it works every time.
Hello, has anyone found a solution to this problem? I am using react-native version 0.63.4
iOS "resolved" is working great. What's up with Android? Can't get it to go.
This appears to be a duplicate of https://github.com/balthazar/react-native-zeroconf/issues/85
And a related issue in a different repo: https://github.com/watson/bonjour/issues/25
Using the Android debugger, I see this line being repeatedly invoked. I think this retry loop is intentional, but the NSD state never changes.
I do not have any issue when there is only 1 device to resolve. Per this stack overflow question, it looks like there is a concurrency problem, so the issue can likely be fixed by resolving services one at a time.
I've been struggling to get this package to work properly. Before anything here is my latest patch-package that aims to solve the issues. A detailed breakdown at the end.
diff --git a/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroConfImplFactory.java b/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroConfImplFactory.java
index 3550238..27a4218 100644
--- a/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroConfImplFactory.java
+++ b/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroConfImplFactory.java
@@ -3,8 +3,6 @@ package com.balthazargronon.RCTZeroconf;
import com.balthazargronon.RCTZeroconf.nsd.NsdServiceImpl;
import com.balthazargronon.RCTZeroconf.rx2dnssd.DnssdImpl;
import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
-
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
diff --git a/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/nsd/NsdServiceImpl.java b/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/nsd/NsdServiceImpl.java
index c59850d..6a90efd 100644
--- a/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/nsd/NsdServiceImpl.java
+++ b/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/nsd/NsdServiceImpl.java
@@ -1,6 +1,6 @@
package com.balthazargronon.RCTZeroconf.nsd;
-import android.annotation.SuppressLint;
+import java.lang.Thread;
import android.content.Context;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
@@ -17,12 +17,15 @@ import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.util.RNLog;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
public class NsdServiceImpl implements Zeroconf {
private NsdManager mNsdManager;
@@ -31,6 +34,7 @@ public class NsdServiceImpl implements Zeroconf {
private Map<String, NsdManager.RegistrationListener> mPublishedServices;
private ZeroconfModule zeroconfModule;
private ReactApplicationContext reactApplicationContext;
+ private final Semaphore semaphore = new Semaphore(1);
public NsdServiceImpl(ZeroconfModule zeroconfModule, ReactApplicationContext reactApplicationContext) {
this.zeroconfModule = zeroconfModule;
@@ -47,7 +51,7 @@ public class NsdServiceImpl implements Zeroconf {
this.stop();
if (multicastLock == null) {
- @SuppressLint("WifiManagerLeak") WifiManager wifi = (WifiManager) getReactApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ WifiManager wifi = (WifiManager) getReactApplicationContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();
@@ -57,35 +61,42 @@ public class NsdServiceImpl implements Zeroconf {
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
String error = "Starting service discovery failed with code: " + errorCode;
- zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_ERROR, error);
+ // zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_ERROR, error);
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
String error = "Stopping service discovery failed with code: " + errorCode;
- zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_ERROR, error);
+ // zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_ERROR, error);
}
@Override
public void onDiscoveryStarted(String serviceType) {
System.out.println("On Discovery Started");
- zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_START, null);
+ // zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_START, null);
}
@Override
public void onDiscoveryStopped(String serviceType) {
System.out.println("On Discovery Stopped");
- zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_STOP, null);
+ // zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_STOP, null);
}
@Override
public void onServiceFound(NsdServiceInfo serviceInfo) {
- System.out.println("On Service Found");
WritableMap service = new WritableNativeMap();
service.putString(ZeroconfModule.KEY_SERVICE_NAME, serviceInfo.getServiceName());
- zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_FOUND, service);
- mNsdManager.resolveService(serviceInfo, new NsdServiceImpl.ZeroResolveListener());
+ // put it into a "thread" so the semaphore doesn't block everything
+ Executors.newSingleThreadExecutor().submit(() -> {
+ try {
+ semaphore.acquire();
+ mNsdManager.resolveService(serviceInfo, new NsdServiceImpl.ZeroResolveListener());
+ } catch (InterruptedException e) {
+ RNLog.e("Zeroconf: Could not aquire semaphore");
+ }
+ });
+
}
@Override
@@ -162,18 +173,22 @@ public class NsdServiceImpl implements Zeroconf {
private class ZeroResolveListener implements NsdManager.ResolveListener {
@Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
- if (errorCode == NsdManager.FAILURE_ALREADY_ACTIVE) {
- mNsdManager.resolveService(serviceInfo, this);
- } else {
- String error = "Resolving service failed with code: " + errorCode;
- zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_ERROR, error);
- }
+ String error = "Resolving service failed with code: " + errorCode;
+ zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_ERROR, error);
+ semaphore.release();
+// if (errorCode == NsdManager.FAILURE_ALREADY_ACTIVE) {
+// mNsdManager.resolveService(serviceInfo, this);
+// } else {
+// String error = "Resolving service failed with code: " + errorCode;
+// zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_ERROR, error);
+// }
}
@Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
WritableMap service = serviceInfoToMap(serviceInfo);
zeroconfModule.sendEvent(getReactApplicationContext(), ZeroconfModule.EVENT_RESOLVE, service);
+ semaphore.release();
}
}
diff --git a/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/rx2dnssd/DnssdImpl.java b/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/rx2dnssd/DnssdImpl.java
index fda45d6..1cf6027 100644
--- a/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/rx2dnssd/DnssdImpl.java
+++ b/node_modules/react-native-zeroconf/android/src/main/java/com/balthazargronon/RCTZeroconf/rx2dnssd/DnssdImpl.java
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.util.Log;
+import android.os.Build;
import com.balthazargronon.RCTZeroconf.Zeroconf;
import com.balthazargronon.RCTZeroconf.ZeroconfModule;
@@ -17,6 +18,7 @@ import com.facebook.react.bridge.WritableNativeMap;
import com.github.druk.rx2dnssd.BonjourService;
import com.github.druk.rx2dnssd.Rx2Dnssd;
import com.github.druk.rx2dnssd.Rx2DnssdBindable;
+import com.github.druk.rx2dnssd.Rx2DnssdEmbedded;
import java.net.InetAddress;
import java.util.HashMap;
@@ -49,7 +51,11 @@ public class DnssdImpl implements Zeroconf {
this.reactApplicationContext = reactApplicationContext;
mPublishedServices = new HashMap<String, BonjourService>();
mRegisteredDisposables = new HashMap<String, Disposable>();
- rxDnssd = new Rx2DnssdBindable(reactApplicationContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ rxDnssd = new Rx2DnssdEmbedded(reactApplicationContext);
+ } else {
+ rxDnssd = new Rx2DnssdBindable(reactApplicationContext);
+ }
}
@Override
@@ -57,7 +63,7 @@ public class DnssdImpl implements Zeroconf {
this.stop();
if (multicastLock == null) {
- @SuppressLint("WifiManagerLeak") WifiManager wifi = (WifiManager) reactApplicationContext.getSystemService(Context.WIFI_SERVICE);
+ WifiManager wifi = (WifiManager) reactApplicationContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();
diff --git a/node_modules/react-native-zeroconf/ios/RNZeroconf/RNZeroconf.m b/node_modules/react-native-zeroconf/ios/RNZeroconf/RNZeroconf.m
index 1ff5371..e0fe5ef 100644
--- a/node_modules/react-native-zeroconf/ios/RNZeroconf/RNZeroconf.m
+++ b/node_modules/react-native-zeroconf/ios/RNZeroconf/RNZeroconf.m
@@ -85,8 +85,8 @@ RCT_EXPORT_METHOD(unregisterService:(NSString *) serviceName)
return;
}
- NSDictionary *serviceInfo = [RNNetServiceSerializer serializeServiceToDictionary:service resolved:NO];
- [self.bridge.eventDispatcher sendDeviceEventWithName:@"RNZeroconfFound" body:serviceInfo];
+ // NSDictionary *serviceInfo = [RNNetServiceSerializer serializeServiceToDictionary:service resolved:NO];
+ // [self.bridge.eventDispatcher sendDeviceEventWithName:@"RNZeroconfFound" body:serviceInfo];
// resolving services must be strongly referenced or they will be garbage collected
// and will never resolve or timeout.
Here is a detailed rundown of my findings and workarounds:
NsdService
, the official Android API for using Bounjour/Mdns, and one based on RxDNSSD
which is a custom implementation that uses RxJava to stream events.NsdService
implementation (resolving multiple services concurrently seems to create an infinite loop). NsdService
because Android tries to save battery when not listening for messages using the official API. There is a workaround using an embeddable version of RxDNSSD
, which I also had to monkey patch (still in the patch I posted but not used). Even though RxDNSSD
is implemented and the package takes (in theory) a parameter to use it, I had to monkey patch the Java sources to be able to use it. (removed in current patch).RxDNSSD
.NsdService
work. I've implemented the solution suggested by @MixMasterMitch in this StackOverflow question (using a simple semaphore to resolve one service at the time)I also started with a new JSI C++ implementation but emitting events from Java->C++->Java->C++ is too complex and I also have to deal with memory sharing and the awfulness that is the JNI interface. I haven't given up, but the resulting code is a lot harder to understand that the current implementation and might still not work.
I still need to test this latest package thoroughly but I've tried a lot of things and thought it might be useful if somebody has already worked around this issue
It seems that Android cached previously founded devices and send this in the question request. Cited devices will not answer this question request because the app already know them.
But the problem is that the app already know them but don't has IP Adresses on Android.
It's possible to check that with Wireshark and filter by IP Adresses of mobile and wanted devices
I don't really know why, but adding DNSSD like this zeroconf.scan(undefined, undefined, undefined, 'DNSSD')
works every time on android
on.start runs per the console.log callback, but on.scan never triggers the callback (as if not finding anything). The exact same code works fine in iOS, and I have added the user-permissions mentioned: