becvert / cordova-plugin-zeroconf

Cordova ZeroConf Plugin
MIT License
81 stars 57 forks source link

Works on Android 5.1.1 but not on Android 7 #61

Closed jcrosby10 closed 5 years ago

jcrosby10 commented 6 years ago

I am detecting a device on a private network with no internet access. The only devices on the network are the device I'm detecting and the mobile devices or PC's that have app I am currently working on. This words just fine on Android 5.1.1 but on 7, I'm getting no response like its not finding anything. Here is the code I'm using to detect the device. The type I am using is _telnet._tcp.

find(type) {
    return new Promise((resolve, reject) => {
        cordova.plugins.zeroconf.watch(type, "local.", (result) => {
            var action = result.action;
            var service = result.service;

            if (action == 'added') {
                console.debug('service added', service);
            }
            else if (action == 'resolved') {
                console.debug('service resolved', service);
                resolve({ status: "resolved", service: service });
            }
            else {
                console.debug('service removed', service);
                resolve({ status: "removed", service: service });
            }
        }, (error) => {
            reject(error);
        });
    });
}

I originally thought it might be because of permissions so I added this to the MainActivity in the Cordova Android project. And I can see it logs "has permission".

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    Log.d(TAG, "version 23 or more");
    if (checkSelfPermission(Manifest.permission.ACCESS_WIFI_STATE) == PackageManager.PERMISSION_GRANTED &&
            checkSelfPermission(Manifest.permission.CHANGE_WIFI_MULTICAST_STATE) == PackageManager.PERMISSION_GRANTED &&
            checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
        Log.d(TAG, "has permission");
    }
    else {
        Log.d(TAG, "no permission");
        requestPermissions(new String[] { Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, 
                Manifest.permission.WRITE_EXTERNAL_STORAGE }, 0);
    }
}
emcniece commented 6 years ago

Can you try disabling cell network data or if possible the cell connection entirely, then scanning again? I have this problem too with an ad-hoc connection.

Oh also if possible, grab an mDNS scanner (Mac, Win) and confirm that your devices are broadcasting properly.

jcrosby10 commented 6 years ago

It is broadcasting fine as the Android 5.1.1 device does find it and later can connect to it with a socket. The Android 7 device does not find it. So I know the device is broadcasting.

I am using tablets so there is no cell network, only wifi.

emcniece commented 6 years ago

Hm, interesting... not sure what the issue is, this might get painful. Some more troubleshooting ideas:

jcrosby10 commented 6 years ago

When I am connected to the wifi on the Android 5.1.1 tablet and I type cordova.plugins.zeroconf.watch('_telnet._tcp.', 'local.', console.log, console.error); into the console I get a log with data about my device and that its added. When I do the same thing on the Android 7 tablet nothing happens. Nothing shows up in the log.

I have been keeping an eye on the Android logcat as well this is the logcat for the Android 5.1.1 tablet that works

03-22 11:12:52.733 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(5006)] "Initializing catena-tcp-client", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (5006)
03-22 11:12:52.753 4983-5080/com.tsi.fitpro D/ZeroConf: Watch _telnet._tcp.local.
03-22 11:12:52.753 4983-6928/com.tsi.fitpro D/ZeroConf: Added
03-22 11:12:52.753 4983-6928/com.tsi.fitpro D/ZeroConf: Sending result: {"action":"added","service":{"domain":"local.","type":"_telnet._tcp.","name":"deviceName","port":3603,"hostname":"","ipv4Addresses":[],"ipv6Addresses":[],"txtRecord":{}}}
03-22 11:12:52.773 4983-5080/com.tsi.fitpro W/CordovaPlugin: Attempted to send a second callback for ID: networkinterface838043946 Result was: "Invalid action"
03-22 11:12:52.773 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 4916 : All modules initialized
03-22 11:12:52.773 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(4916)] "All modules initialized", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (4916)
03-22 11:12:52.803 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 54 : successfully unwatched
03-22 11:12:52.803 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(54)] "successfully unwatched", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (54)
03-22 11:12:52.803 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 54 : Unwatch error
03-22 11:12:52.803 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(54)] "Unwatch error", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (54)
03-22 11:12:52.803 4983-5080/com.tsi.fitpro D/ZeroConf: Unwatch _telnet._tcp.local.
03-22 11:12:52.803 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 55 : successfully closed
03-22 11:12:52.803 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(55)] "successfully closed", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (55)
03-22 11:12:52.803 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 55 : Close error
03-22 11:12:52.803 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(55)] "Close error", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (55)
03-22 11:12:52.803 4983-5080/com.tsi.fitpro D/ZeroConf: Close
03-22 11:12:52.803 4983-5080/com.tsi.fitpro D/ZeroConf: Watch _telnet._tcp.local.
03-22 11:12:52.813 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 6909 : Not initialized to send
03-22 11:12:52.813 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(6909)] "Not initialized to send", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (6909)
03-22 11:12:52.813 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 6909 : Not initialized to send
03-22 11:12:52.813 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(6909)] "Not initialized to send", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (6909)
03-22 11:12:52.853 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 18 : service added
03-22 11:12:52.853 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(18)] "service added", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (18)
03-22 11:12:53.174 4983-6943/com.tsi.fitpro D/ZeroConf: Added
03-22 11:12:53.184 4983-6943/com.tsi.fitpro D/ZeroConf: Sending result: {"action":"added","service":{"domain":"local.","type":"_telnet._tcp.","name":"deviceName","port":0,"hostname":"deviceName._telnet._tcp.local.","ipv4Addresses":[],"ipv6Addresses":[],"txtRecord":{"deviceName._telnet._tcp.local.":"true"}}}
03-22 11:12:53.194 4983-6943/com.tsi.fitpro D/ZeroConf: Resolved
03-22 11:12:53.194 4983-4983/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 18 : service added
03-22 11:12:53.194 4983-4983/com.tsi.fitpro I/chromium: [INFO:CONSOLE(18)] "service added", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (18)
03-22 11:12:53.194 4983-6943/com.tsi.fitpro D/ZeroConf: Sending result: {"action":"resolved","service":{"domain":"local.","type":"_telnet._tcp.","name":"deviceName","port":3603,"hostname":"deviceName.local.","ipv4Addresses”:[“deviceIP”],”ipv6Addresses":[],"txtRecord":{}}}

Here is the log of the Android 7 tablet that does not find the device

03-22 12:59:39.866 3909-4060/com.tsi.fitpro D/ZeroConf: Watch _telnet._tcp.local.
03-22 12:59:39.877 3909-4060/com.tsi.fitpro W/CordovaPlugin: Attempted to send a second callback for ID: networkinterface33089216
                                                             Result was: "Invalid action"
03-22 12:59:39.880 3909-3909/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 4916 : All modules initialized
03-22 12:59:39.881 3909-3909/com.tsi.fitpro I/chromium: [INFO:CONSOLE(4916)] "All modules initialized", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (4916)
03-22 12:59:39.900 3909-3909/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 54 : successfully unwatched
03-22 12:59:39.900 3909-3909/com.tsi.fitpro I/chromium: [INFO:CONSOLE(54)] "successfully unwatched", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (54)
03-22 12:59:39.900 3909-4060/com.tsi.fitpro D/ZeroConf: Unwatch _telnet._tcp.local.
03-22 12:59:39.901 3909-3909/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 54 : Unwatch error
03-22 12:59:39.901 3909-3909/com.tsi.fitpro I/chromium: [INFO:CONSOLE(54)] "Unwatch error", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (54)
03-22 12:59:39.902 3909-3909/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 55 : successfully closed
03-22 12:59:39.902 3909-3909/com.tsi.fitpro I/chromium: [INFO:CONSOLE(55)] "successfully closed", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (55)
03-22 12:59:39.903 3909-3909/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 55 : Close error
03-22 12:59:39.903 3909-3909/com.tsi.fitpro I/chromium: [INFO:CONSOLE(55)] "Close error", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (55)
03-22 12:59:39.904 3909-4060/com.tsi.fitpro D/ZeroConf: Close
03-22 12:59:39.905 3909-4060/com.tsi.fitpro D/ZeroConf: Watch _telnet._tcp.local.
03-22 12:59:39.912 3909-3909/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 6909 : Not initialized to send
03-22 12:59:39.912 3909-3909/com.tsi.fitpro I/chromium: [INFO:CONSOLE(6909)] "Not initialized to send", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (6909)
03-22 12:59:39.915 3909-3909/com.tsi.fitpro D/SystemWebChromeClient: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js: Line 6909 : Not initialized to send
03-22 12:59:39.915 3909-3909/com.tsi.fitpro I/chromium: [INFO:CONSOLE(6909)] "Not initialized to send", source: file:///android_asset/www/FitPro/build/electronUV/bundleUV.js (6909)
03-22 12:59:40.798 3909-4159/com.tsi.fitpro W/System.err: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
03-22 12:59:40.798 3909-4159/com.tsi.fitpro W/System.err: SLF4J: Defaulting to no-operation (NOP) logger implementation
03-22 12:59:40.798 3909-4159/com.tsi.fitpro W/System.err: SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
03-22 12:59:44.862 3909-4060/com.tsi.fitpro W/CordovaPlugin: Attempted to send a second callback for ID: networkinterface33089221
                                                             Result was: "Invalid action"
03-22 12:59:49.861 3909-4060/com.tsi.fitpro W/CordovaPlugin: Attempted to send a second callback for ID: networkinterface33089223
                                                             Result was: "Invalid action"
03-22 12:59:53.269 3909-4071/com.tsi.fitpro W/cr_MediaCodecBridge: Releasing: OMX.Nvidia.h264.decode
03-22 12:59:53.297 3909-4071/com.tsi.fitpro W/cr_MediaCodecBridge: Codec released
03-22 12:59:54.860 3909-4060/com.tsi.fitpro W/CordovaPlugin: Attempted to send a second callback for ID: networkinterface33089225
                                                             Result was: "Invalid action"
emcniece commented 6 years ago

Wow, very neat. I'm interested in the CordovaPlugin: Attempted to send a second callback and "Not initialized to send" output. Doesn't seem to be much out there for related issues.

Can you provide some versions for us? Zeroconf plugin version, Cordova, NodeJS, etc.

Is your find(type) function protected behind a platform.ready() check? I'm curious as to whether the Zeroconf watch is starting too soon, or if it's being called too many times. I see that the first Zeroconf watch happens before a "All modules initialized" message.

As I understand it, watch() is a long-running promise that doesn't end after the first time it gets called or the first time it returns. I actually wrap mine in an observable so that it can emit endlessly.

the Attempted to send a second callback message is a bit more worrying - it could be referring to the org.apache.cordova.CallbackContext interface. I could guess that double or premature initialization of the plugin might mess up the provided contexts, but I don't understand enough about Android to say for sure.

jcrosby10 commented 6 years ago

"Not initialized to send" is a warning log if the app makes an attempt to communicate with the device before its connected. So it should be unrelated to this issue.

cordova-plugin-zeroconf 1.3.1 "ZeroConf" cordova 8.0.0 node 8.9.4

Yes I wait to run the app until cordova is ready. The reason its called twice is because the app calls the find function to watch for devices when the app first starts but there is also a function that is called when a new network interface is found and that resets and calls find. So the first time the app opens its called twice. It happens on both tablets so I didn't think that was an issue. However the newer tablet is also faster so it may be something timing related that the older tablet is a little slower and gets the response before it resets. But also when I call cordova.plugins.zeroconf.watch directly in the console nothing happens. So that might not be the problem after all.

jcrosby10 commented 6 years ago

Any other suggestions I can try?

becvert commented 6 years ago

Attempted to send a second callback for ID: networkinterface33089216 is related to another plugin for me. Are you using a networkinterface plugin?

becvert commented 6 years ago

did you try to grab and install another mDNS scanner on your Android 7 tablet, to see if it can find your device? "ServiceBrowser", "BonjourBrowser", "ZeroConf Browser" for instance

jcrosby10 commented 6 years ago

I installed Service Browser on the Android 7 tablet and it can find the device. And yes Attempted to send a second callback for ID: networkinterface33089216 is related to a network interface plugin.

jcrosby10 commented 6 years ago

I have tried this on 2 Android devices running 7.0 and one running 7.1.1 and they all do not find this device I need to connect to. Were there any changes made to Android starting in 7.0 that makes this not work?

becvert commented 6 years ago

I got myself an android 7 device. I'll have a look very soon.

becvert commented 6 years ago

my device running 7.0 finds an iPad, an android 4 and Android 6 without any problems :confused:

jcrosby10 commented 6 years ago

When I go to look at the app permissions in the app settings, all I see is Storage even though in the manifest and in the Java code I'm requesting ACCESS_WIFI_STATE, CHANGE_WIFI_MULTICAST_STATE, and WRITE_EXTERNAL_STORAGE. The app logs it has all three permissions as stated previously however in settings it only shows storage. On the tablet that works I see it has all 3 permissions stated in settings. Am I incorrectly requesting permissions?

emcniece commented 6 years ago

That is interesting. My (functional) app has the following permissions in platforms/android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
jcrosby10 commented 6 years ago

My permissions in the manifest

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

However on devices running 6.0 and above the permissions have to be requested at runtime not in the manifest so I added the code to check for permissions when we are 6 and above and request them if needed. It always seems to return granted for all three I request at runtime but on these devices that are failing the only permission stated in the app settings is the Storage permission.

jcrosby10 commented 6 years ago

I also have android:minSdkVersion="21" android:targetSdkVersion="27" declared in the manifest.

jcrosby10 commented 6 years ago

Ok I see that I was a little off on permissions. Since INTERNET, ACCESS_WIFI_STATE, and CHANGE_WIFI_MULTICAST_STATE are normal (not dangerous) permissions the system should automatically grant those when they are declared in the manifest at install time, and users cant revoke them according to the docs https://developer.android.com/guide/topics/permissions/overview.html#normal-dangerous. So by that there should be no reason why this is not working or why the normal permissions declared in the manifest do not show up in the app permission settings.

jcrosby10 commented 6 years ago

Turns out there is an "All Permissions" option in a menu in the permission settings screen that I was not aware of. In the all permissions area it does actually show the permissions. So its not apparently permission related.

KevinSib commented 6 years ago

Any idea? I have tested on an Android 5 and 7 but the device see nothing. However on iOS it's work perfectly

vishnuprasad7 commented 6 years ago

I get all values in service object except ipv4 address . should i register before watching for services ?

zeroconf.watch('_http._tcp.', 'local.', function (result) { var action = result.action; var service = result.service; if (action == 'added') { console.log('service added', service); } else if (action == 'resolved') { console.log('service resolved', service); } else { console.log('service removed', service); } });

becvert commented 5 years ago

Closing old issue. Feel free to reopen.