Building a desktop version of my mobile app and providing the user syncing over wifi. Everything works great in the simulator - no problems resolving net services (which are published by the desktop app) or noticing when services become unavailable.
The problem is when I run the app on the phone services are discovered and resolved (sometiems) but the NSNetServiceBrowser never notices when a service becomes unavailable. When this happens the net service browser constantly finds a net service (that is no longer published) resolves it but then can't connect to it. After several failed attempts the service browser delegate's "didRemoveService" is finally called and the app begins to behave correctly again.
I'd post my code but I've discovered the same issue is happening in Apple's WiTap example. Services are published and discovered but once they are made unavailable the client running the service browser doesn't update - and repeatedly tries to resolve a service that "shouldn't" exist.
I've discovered that running WiTap with wifi turned off (so Bonjour uses bluetooth) everything works fine. I can't find anyone complaining about WiTap not working and can't find this issue anywhere else online. Any reason - possibly with iPhone OS or my wireless network - why a net service browser can find and correctly resolve (but can't connect to) services that are unavailable?
Bonjour/NSNetServiceBrowser on the iPhone/iPod Touch will utilize both Wifi and Bluetooth for service discovery--at least on supported devices. Each time you begin browsing for services, it will search both WiFi and Bluetooth (which you can verify in the iPhone's Console, in Organizer). Since your Simulator "device" cannot use Bluetooth, your iPhone discovers it over WiFi. However, if you are using NSNetService to publish on your iPhone, then you are publishing over both WiFi and Bluetooth as well (if supported and enabled). NSNetServiceBrowser, when running on BT-capable hardware, will dutifully find that both instances, and report both via delegate callbacks.
Bluetooth PAN setup takes longer than publishing via Wifi, so the BT-discovered services often show up well after all the Wifi-based services have been discovered and resolved. When testing two real devices, I've even seen both services show up in my UI (usually only after the other phone crashes).
It does make for some frustrating coding, though. Your best bet is to utilize netService:didNotResolve: to either (i) retry resolution, or (ii) invalidate the netService instance and wait for the other phone to relaunch their app.
Also, there are a couple of other areas things can go wrong. Since the NSNetService instance provided to you is autoreleased, you need to retain it. Most people add it to an NSMutableArray or NSMutableDictionary. If that's the case, make sure that you have properly initialized it before adding the object. Since messages to nil are perfectly ok, if you send addObject: to nil it will appear as though everything is working fine. Except that it isn't. This crops up very often in Bonjour troubleshooting, and happens to the best of us. Make sure that your NSNetService gets scheduled into an actively running runloop, and one that is running in default or common modes.
There is an open bug filed with Apple (as of 10/4/09) whereby every so often, a Bonjour update will not result in a delegate method getting fired. I have only observed this occurring on a 3GS. The result is a client app that is out of sync with the network.
NSNetServiceBrowser should consistently notify when a service leaves the network (under nominal conditions). The bug above is only an intermittent one, and apparently, hardware specific. If you see it occurring consistently, then it's likely that your app is throwing an exception. If you are using background threads, this can occur without causing your whole app to crash. You may want to check your iPhones Console and logs for error messages. Make sure you have set a breakpoint on the symbol objc_exception_throw.
Here's another troubleshooting tip that I've found invaluable. Monitor Bonjour broadcasts on your dev machine via Terminal using the following command: dns-sd -B _serviceName. This will let you see all comings and goings on your local network for your service. If your app quits, but dns-sd does not show a Remove event, then your code needs revisiting. If dns-sd shows a remove event, but your other apps don't process it correctly, you may be seeing the above mentioned bug. It may also be the case that your code isn't doing what you think it's doing. And remember, this will only help you troubleshoot Wifi-to-Wifi service Bonjour. Bluetooth to Bluetooth is not supported from the iPhone Simulator.
Read the full article, Troubleshooting Bonjour Networking for the iPhone, at my dev blog.
Related
What is the best way to COMPLETELY restart the iOS Bluetooth BTLE central and peripheral managers, after communication stops between two iOS devices (iPad-mini)?
Sometimes after a few minutes, my BTLE communication stops (central can not get response from peripheral, though debug output of each device shows app still running and central app still is trying to scan peripheral, and peripheral is still advertising), and will not start again:
after stopping scanning and stopping advertising, comm still doesn't work;
after re-opening the app, comm still doesn't work(!);
after POWER CYCLING the iPads comm works again, but then after a few minutes dies.
Therefore, something I'm doing is clobbering maybe the iOS core Bluetooth software.
Sometimes there are error messages from the underlying BTLE layer.
BACKGROUND:
Each iPad in this system alternately works as central, to read/write data to others, and then as peripheral, to be read by others. Never at the same time, and with a 1 second delay between transistions.
The bluetooth stack is not the most robust part of iOS. This may have improved in iOS7 but issues have always existed. You most probably are stressing the system so that this hang happens more often. You should create a bug report and send it to Apple. Or create a TSI, as a developer you have two of those every year. They are the only ones who can do something about it.
To solve the issue, restarting the app usually helps but sometimes bluetooth needs to be turned on/off or worst case the device needs to be power cycled. Unfortunately, there is not programmatic way to do any of these.
I'm behind a corporate firewall and all network traffic goes thru the main proxy. In my iOS simulator, I get proxy popups a few times each time I run my app. The thing is, my app doesn't make any network calls (yet), and doesn't import any network frameworks. In fact, I can reproduce this by making a new project in XCode using one of the standard templates and run it straight away; it'll still prompt for the proxy credentials every time.
In my OSX network settings, I've obviously set my proxy credentials in all the different protocols (HTTP, HTTPS, FTP, Socks, RTSP, Gopher). I found that I needed to put the domain and backslash before my username to allow web access in any OSX browsers etc...so given that I did that and then the OSX proxy prompts went away and I was allowed access, I would have thought that the iOS simulator would just inherit those settings...?
Any ideas?
One more bit which may be unrelated: we haven't yet figured out how to get access to the App Store on this Mac; despite supposedly getting past the proxy, any use of the App Store just results in timeouts and we can't even see the "home page". I'm wondering if somehow the iOS simulator is making similar network calls using some other protocol that is like the App Store...? (I would have thought App Store would have been HTTPS but I don't know).
Any thoughts appreciated.
If you put *.apple.com in your proxy passthrough list, the simulator will stop whining about it.
Like you, I can't get the Apple Store to work through our corporate proxy either. I've worked around it by using a wireless network that doesn't use a proxy when I have to use the App Store.
I've found plenty of other things in the OS that don't work through our proxy.
I had the same issue and found another way without touching the proxy settings!
I'm working on a Mac with OSX-El Capitan so maybe in other versions these steps might be slightly different:
Go to System Preferences
Go to Network
Choose your connection (Wireless/Ethernet/Thunderbolt-Ethernet)
Click on Advanced Options
Go to the tab Proxies
The two boxes Automatically detect proxy (for the internet connection on your mac) and Web-Proxy (HTTP)
Insert your login credentials at Web-Proxy (HTTP).
This reduced the occurence of the Proxy-PopUp greatly on all the 3 macs I work with. (At least it doesn't appear periodically anymore when I start my app from xcode)
Despite working earlier, my socket chat app now refuses to write to socket on the iPhone!
It works fine on the simulator and again, used to run fine on my phone. I don't really know where to start troubleshooting this issue --- just seems weird. My server doesn't detect anything trying to connect.
Any ideas on how to start troubleshooting this?
Thanks tons.
I did run into a problem where using sockets on the iPhone would not open up the cell phone network unless something else opened it first. I had to run an http call to a generic web site first, and then the sockets would communicate normally. Try putting a call, like sendSynchronousRequest, to a generic web site, like www.apple.com, before opening your socket, and see if it works in that case.
I need to stop wasting all you nice peoples' time.
Long story, my friend updated to iOS 5.1. Now the 3G network reads 4G on iOS 5.1. So I turned off my (5.0) wifi to see if mine cell network was "4G" (which, of course, it wasn't).
But yeah, having turned off wifi my app could no longer join my locally hosted server...
I grabbed Charles though, and it looks handy, so thanks for that anyways. Also Owen's comment about the cell network originally made me think about checking my wifi, as my app shouldn't even be using the cell network yet. But I'll keep in mind what you said for the future.
Thanks everybody!
I have an iOS app that publishes a Bonjour service. On my network, the Mac app recognizes the service and everything runs smoothly. On some networks however, the Bonjour service is not "seen" by the Mac. I can't reproduce this on my own network. I have had users check for the service using Bonjour Browser and it's not found. Is there a way to diagnose this problem further? I thought it might be a firewall / router issue but some users have very simple Apple-based networks (Airport). Any ideas on what could be causing this?
Have you tried implementing the
- (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary *)errorDict
method? it can occasionally provide useful information although I have found the NSNetService to have strange behaviour sometimes also. Stopping the NSNetService and re-publishing is an ugly option which seemed to work for me to some extent.
Make sure you implement ...didNotPublish... as above. Some routers filter out multicast packets, and unfortunately if you don't control the network there's not an awful lot you can do about it.
Another followup: modifying the device name seems to resolve the issue. One user noted that his iPad was discovered but not his iPhone. Bonjour Browser confirmed the presence of the iPad service with no iPhone service. Renaming the iPhone resolved the issue. This is truly an odd behavior.
Is there any way that we can programatically identify when the wifi of a user becomes available/unavailable?
My application requires exchanging messages between two different devices. It is working good in stable wifi setups. But if the wifi is unstable, I am having trouble in detecting if the other device is available or not.
I am not sure if this is expected, but my bonjour based NSNetService discoverer is not updating the available devices list automatically. This leaves me with a list of services that are not available for the exchange.
My line of thinking was to remove all the available services from the list and start a fresh search.
Please let me know if I am thinking in the right direction to solve the right problem.
Thanks in advance.
-Murali
Perhaps the Reachability sample code provided by Apple will help you in this regard. Although there have been people who say it hasn't been updated in a while, in which case, here is an actively maintained fork.
It seems like you can register for notifications so you can get frequent information on the state of the network.