NSNetService Not Resolving - ios

I have an existing application (actually a pair of iOS applications) which have a very basic Bonjour implementation so the 'client' can find the 'server' on the network. This worked fine until a recent test (I'm not completely for sure that this is related to iOS8, but this is the first time I've compiled these apps with iOS 8). In this case, all works as expected until the client goes to resolve the address of the server. At this point, it always times out. Also, I've tried a few Bonjour discovery apps from the app store and they timeout also (so I'm assuming this is a problem with the server code).
In the client application my NSNetServiceDelegate methods are called in this order:
netServiceWillResolve:
(then it waits the full timeout period that I specified in resolveWithTimeout:)
netService:didNotResolve:
This code has worked flawlessly in the past. I'm not entirely sure what would cause this behavior.
Here is the code for publishing the service:
- (void)initializeServerServiceStatus
{
NSString *deviceName = [[UIDevice currentDevice] name];
NSString *serviceName = [NSString stringWithFormat:#"iPad Server - %#", deviceName];
self.serverPresentationService = [[NSNetService alloc] initWithDomain:#"local."
type:SERVICE_NAME_IPAD_SERVER
name:serviceName
port:self.port];
self.serverPresentationService.delegate = self;
[self.serverPresentationService publish];
self.isPublishing = YES;
}
I have verified that the netServiceDidPublish: method is called and that the netServiceDidStop: is not called.
UPDATE: I have verified that if the service is published on an iOS 7 device, all works as expected (even if the resolving device is on iOS 8).
UPDATE 2: I have verified that Apple knows of some problems with Bonjour in the iOS 8 release: https://devforums.apple.com/message/1045870#1045870

Related

Why Apple send me message saying my app did not support Ipv6?

My application is rejected with the follow information:
发件人 Apple
1. 5 SAFETY: DEVELOPER INFORMATION
2. 1 PERFORMANCE: APP COMPLETENESS
Safety - 1.5
The support URL specified in your app’s metadata, http://hxsq.luminginfo.cn/, does not properly navigate to the intended destination.
Specifically, your support URL displayed “This site can’t be reached” error message.
Next Steps
Please revise your app’s support URL to ensure it directs users to a webpage with support information.
Performance - 2.1
We discovered one or more bugs in your app when reviewed on iPhone and iPad running iOS 10.2.1 on Wi-Fi connected to an IPv6 network.
Specifically, your app displayed a connection error when logging in with the provided demo accounts.
Please see attached screenshots for details.
Next Steps
Please run your app on a device while connected to an IPv6 network (all apps must support IPv6) to identify any issues, then revise and resubmit your app for review.
If we misunderstood the intended behavior of your app, please reply to this message in Resolution Center to provide information on how these features were intended to work.
For new apps, uninstall all previous versions of your app from a device, then install and follow the steps to reproduce the issue. For updates, install the new version as an update to the previous version, then follow the steps to reproduce the issue.
Resources
For information about supporting IPv6 Networks, please refer to Supporting IPv6 DNS64/NAT64 Networks and About Networking.
With the two follow images:
http://a1198.phobos.apple.com/us/r30/Purple122/v4/60/8b/eb/608bebae-1c3b-cc93-2a01-9f512965f622/attachment-3951093649653869315Screenshot-0217-073348.png?downloadKey3=1487836993_30f3e33d7be2d3ba3c3e89d7e3393952
http://a1225.phobos.apple.com/us/r30/Purple111/v4/58/78/7a/58787a76-b8a2-8016-e5fe-412c7fcaf8dc/attachment-8366771332257964417Screenshot-0217-073415.png?downloadKey3=1487836993_592f44ae84cf1f391301263be58175b6
1.First, I do not understand the issue 1.5.
2.Secondly, my application is use AFNetworking 3.1.0, and in a swift-oc mixture project.
My network Util is this, one of the method is list:
#import "Mysevers.h"
#import "AFNetworking.h"
#import "HUD.h"
#implementation Mysevers
+(void)AFPOSTWithHud:(BOOL)hud andAddressname:(NSString*)addressName parmas:(NSDictionary*)parmas RequestSuccess:(void(^)(id result))success failBlcok:(void(^)(void))failBlcok
{
if (hud) {
[HUD addHUD];
}
AFHTTPSessionManager *requestManager = [AFHTTPSessionManager manager];
NSString *urlStr = [NSString stringWithFormat:#"%#%#",BASE_URL,addressName];
NSLog(#"%#",urlStr);
[requestManager POST:urlStr parameters:parmas progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (hud) {
[HUD removeHUD];
}
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (error != nil) {
NSLog(#"error==%#",[error localizedDescription]);
if (hud) {
[HUD removeHUD];
}
failBlcok();
}
return ;
}];
}
Attention
My BASE_URL is:
#define BASE_URL #"https://hxsq.luminginfo.cn:8043/app/"
Additional -1
I have tested my local ipv6 condition, and it can login.
The DNS is ipv6's.
And my app can login too, so I feel uncertain, my application is support ipv6! but apple send me ipv6 issue, the only doubtful point is my url(hxsq.luminginfo.cn) in app can not visit in foreign, such as USA.
It says that your support URL is not supported over IPv6. Therefore, it may not actually be related to your in-app networking code. I just tried to load that URL in my browser and it also failed. You have to have a working support URL.
If you confirm that it is a problem with your in-app networking, you should check out this post by Eskimo who is an engineer at apple. Specifically, you should test against an IPv6 network, which you can setup using these instructions. If you've gone through the checklist and verified that IPv6 works for you locally, you should respond to app review and ask them to try it again. We had the same problem a couple of weeks ago.
Safety - 1.5: In my opinion, at least the support URL (http://hxsq.luminginfo.cn/) should navigate the user to download your application. Your URL is just a login page and they may see "Can not access this site" error message when reviewing your app.
Performance - 2.1: You should test your app in IPv6-Only. The official website: https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html
You can just read the part "Test for IPv6 DNS64/NAT64 Compatibility Regularly".
I also had this problem before, through my tests, there may fulfill three conditions:
1. App must support https and runs in Ipv6.
2. The BaseUrl shouldn't be ip url(like "122.223.1.1"), it must be public domain name.
3. App need use legal https certificate.
At last, I found our web-server is not available in USA, but available in China, and I tested ipv6 in my network, it is supported ipv6.
But I send my server page to USA friend they say it is not available in USA, so my server is not available in USA.
So, it is a wrong information from Apple audit team.
They may default verify our app in Ipv6 network, regardless of the server network if is available.
My issue is caused by:
I use qcloud, (which is Tencent subordinate cloud server).
At first our backend java colleague only set the second record, point at Inland network, the Foreign can not access our server.Then I add the first record, point at Foreign, so in USA can access the server now.
Then I send my application to Itunes Connect to review, it success.
I think i have found the solution. The main problem is Cocoapods is setting the "Deployment Target" of Pod Project to "IOS 7.0". so this makes "AFNetworkReachabilityManager.m" class to use old "ipv4" code instad of the new ipv6 block because the "if statement" falls into the wrong side.
the "__IPHONE_OS_VERSION_MIN_REQUIRED" statement return "7000" because cocoapods deployment target is set as "7.0" instead of useing the same deployment target as the main project.
+ (instancetype)manager
{
NSLog(#"min iphoneos: %i - %i",__IPHONE_OS_VERSION_MIN_REQUIRED,__IPHONE_OS_VERSION_MIN_REQUIRED);
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
struct sockaddr_in6 address;
bzero(&address, sizeof(address));
address.sin6_len = sizeof(address);
address.sin6_family = AF_INET6;
NSLog(#"IPV6 Block");
#else
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
NSLog(#"IPV4 Block");
#endif
return [self managerForAddress:&address];
}

iOS 10 - WLAN Access Setting Doesn't Appear In Some iOS Devices

Our app is using WLAN to communicate with a wireless device. When our app is installed in iOS 10. Sometimes, udp socket doesn't work. The reason for that is, in iOS 10 they added a new setting or permission under your app that allows the user to switch on or off the user of WLAN or cellular data.
The following would appear in the settings of the app:
When I tap on the Wireless... It will bring me to this UI:
After allowing WLAN use. The app would work fine.
Now, the problem is, sometimes, or in some devices running iOS 10, the settings that I just showed you doesn't appear(I am referring to the setting shown on the first image). So, is there anything I can do to make that settings always appear? It seems that sometimes iOS system doesn't recognize that my app is using wireless data. And it would result in my app would never get to use WLAN forever.
There is no user permission to use WIFI in iOS10.
The application in your screenshot (BSW SMART KIT) is using Wireless Accessories (WAC), i.e. is able to connect to wireless speakers. To accomplish this the Wireless Accessory Configuration capability is required. This is what you can dis/enable in the systems settings (your screenshot).
The switch in the settings shows up after connecting to a device via WIFI through WAC. You can see this behaviour in your sample app (BSW SMART KIT) too.
This sample code might let you get the idea. Detailed information in Apples documentation.
After a time of researching. I ended up seeking help with Apple Code Level Support. Apple states that this problem would most probably occur when you reskin your app. They say that probably it's because of the Image UUID of the main app and the reskinned app are the same. When you install both of them in your phone, the system will treat the reskinned app as the same app compared to the main app. So, if the one app fails to access WLAN, then it will also affect the other one. According to them, this appears to be a bug in iOS. And currently, they don't have any solution for the developers. This is the radar bug number:
What I did to somehow lessen the occurrence of the problem is to add tracking to the Network Restriction by using the following code.
- (void)startCheckingNetworkRestriction
{
__weak AppDelegate *weakSelf = self;
_monitor = [[CTCellularData alloc] init];
_monitor.cellularDataRestrictionDidUpdateNotifier = ^(CTCellularDataRestrictedState state)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
NSString * statusStr;
switch(state)
{
case kCTCellularDataRestrictedStateUnknown:
{
statusStr = #"restriction status:Unknown";
}
break;
case kCTCellularDataRestricted:
{
statusStr = #"restriction status:restricted";
[weakSelf performUrlSession];
}
break;
case kCTCellularDataNotRestricted:
{
statusStr = #"restriction status:not restricted";
}
break;
default:
{
abort();
}
break;
}
NSLog(#"Restriction state: %#", statusStr);
}];
};
}
Take note that you have to import CoreTelephony to do this.
#import CoreTelephony;
when I detect that the network is restricted. I will open a URL session to force internet access attempt and would hope that the restriction alert dialog would pop out. Once the alert is pop out, then the WLAN Access Settings that I was talking about would definitely appear under the settings. There are times that this doesn't work. If it happens, then you'll just have to rename the bundle ID, and make a couple of changes to your code and then rebuild it a couple of times (Well, that's what I did when I was experimenting this). Reinstalling the app won't do a thing. Restarting and resetting the phone won't do either.
Hope this helps.

NSNetServiceBrowser issues on iOS - not detecting all changes

I think this may be an iOS bug.
I run the following simple code, to broadcast a net service:
self.netService = [[NSNetService alloc] initWithDomain:#"local."
type:#"_testnetwork._tcp."
name:[[UIDevice currentDevice] name]
port:port];
self.netService.delegate = self;
[self.netService publish];
On another device, I run this code, to detect net services:
self.netServiceBrowser = [[NSNetServiceBrowser alloc] init];
self.netServiceBrowser.delegate = (id)self;
[self.netServiceBrowser searchForServicesOfType:#"_testnetwork._tcp." inDomain:#"local."];
What proceeds to happen is that the browser will detect when the net service appears for the first time, and then when the service goes away, most of the time it won't detect it, and still thinks the NSNetService is still broadcasting. Interestingly, the apps can be stopped on both devices and the browser can be started and will still detect the old service as being currently broadcast - it hangs around.
Using this code in terminal on mac shows correctly when the services appear and disappear:
dns-sd -B _test._tcp
Any solution to this problem? Is this an iOS bug?

Programmatically get own phone number in iOS

Is there any way to get own phone number by standard APIs from iPhone SDK?
At the risk of getting negative marks, I want to suggest that the highest ranking solution (currently the first response) violates the latest SDK Agreement as of Nov 5, 2009. Our application was just rejected for using it. Here's the response from Apple:
"For security reasons, iPhone OS restricts an application (including its preferences and data) to a unique location in the file system. This restriction is part of the security feature known as the application's "sandbox." The sandbox is a set of fine-grained controls limiting an application's access to files, preferences, network resources, hardware, and so on."
The device's phone number is not available within your application's container. You will need to revise your application to read only within your directory container and resubmit your binary to iTunes Connect in order for your application to be reconsidered for the App Store.
This was a real disappointment since we wanted to spare the user having to enter their own phone number.
No, there's no legal and reliable way to do this.
If you find a way, it will be disabled in the future, as it has happened with every method before.
Update: capability appears to have been removed by Apple on or around iOS 4
Just to expand on an earlier answer, something like this does it for me:
NSString *num = [[NSUserDefaults standardUserDefaults] stringForKey:#"SBFormattedPhoneNumber"];
Note: This retrieves the "Phone number" that was entered during the iPhone's iTunes activation and can be null or an incorrect value. It's NOT read from the SIM card.
At least that does in 2.1. There are a couple of other interesting keys in NSUserDefaults that may also not last. (This is in my app which uses a UIWebView)
WebKitJavaScriptCanOpenWindowsAutomatically
NSInterfaceStyle
TVOutStatus
WebKitDeveloperExtrasEnabledPreferenceKey
and so on.
Not sure what, if anything, the others do.
Using Private API you can get user phone number on the following way:
extern NSString* CTSettingCopyMyPhoneNumber();
+(NSString *) phoneNumber {
NSString *phone = CTSettingCopyMyPhoneNumber();
return phone;
}
Also include CoreTelephony.framework to your project.
You cannot use iOS APIs alone to capture the phone number (even in a private app with private APIs), as all known methods of doing this have been patched and blocked as of iOS 11. Even if a new exploit is found, Apple has made clear that they will reject any apps from the app store for using private APIs to do this. See #Dylan's answer for details.
However, there is a legal way to capture the phone number without any user data entry. This is similar to what Snapchat does, but easier, as it does not require the user to type in their own phone number.
The idea is to have the app programmatically send a SMS message to a server with the app’s unique installation code. The app can then query the same server to see if it has recently received a SMS message from a device with this unique app installation code. If it has, it can read the phone number that sent it. Here’s a demo video showing the process. As you can see, it works like a charm!
This is not super easy to set up, but it be configured in a few hours at no charge on a free AWS tier with the sample code provided in the tutorial here.
As you probably all ready know if you use the following line of code, your app will be rejected by Apple
NSString *num = [[NSUserDefaults standardUserDefaults] stringForKey:#"SBFormattedPhoneNumber"];
here is a reference
http://ayeapi.blogspot.com/2009/12/sbformatphonenumber-is-lie.html
you can use the following information instead
NSString *phoneName = [[UIDevice currentDevice] name];
NSString *phoneUniqueIdentifier = [[UIDevice currentDevice] uniqueIdentifier];
and so on
#property(nonatomic,readonly,retain) NSString *name; // e.g. "My iPhone"
#property(nonatomic,readonly,retain) NSString *model; // e.g. #"iPhone", #"iPod Touch"
#property(nonatomic,readonly,retain) NSString *localizedModel; // localized version of model
#property(nonatomic,readonly,retain) NSString *systemName; // e.g. #"iPhone OS"
#property(nonatomic,readonly,retain) NSString *systemVersion; // e.g. #"2.0"
#property(nonatomic,readonly) UIDeviceOrientation orientation; // return current device orientation
#property(nonatomic,readonly,retain) NSString *uniqueIdentifier; // a string unique to each device based on various hardware info.
Hope this helps!
To get you phone number you can read a plist file. It will not work on non-jailbroken iDevices:
NSString *commcenter = #"/private/var/wireless/Library/Preferences/com.apple.commcenter.plist";
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:commcenter];
NSString *PhoneNumber = [dict valueForKey:#"PhoneNumber"];
NSLog([NSString stringWithFormat:#"Phone number: %#",PhoneNumber]);
I don't know if Apple allow this but it works on iPhones.
No official API to do it. Using private API you can use following method:
-(NSString*) getMyNumber {
NSLog(#"Open CoreTelephony");
void *lib = dlopen("/Symbols/System/Library/Framework/CoreTelephony.framework/CoreTelephony",RTLD_LAZY);
NSLog(#"Get CTSettingCopyMyPhoneNumber from CoreTelephony");
NSString* (*pCTSettingCopyMyPhoneNumber)() = dlsym(lib, "CTSettingCopyMyPhoneNumber");
NSLog(#"Get CTSettingCopyMyPhoneNumber from CoreTelephony");
if (pCTSettingCopyMyPhoneNumber == nil) {
NSLog(#"pCTSettingCopyMyPhoneNumber is nil");
return nil;
}
NSString* ownPhoneNumber = pCTSettingCopyMyPhoneNumber();
dlclose(lib);
return ownPhoneNumber;
}
It works on iOS 6 without JB and special signing.
As mentioned creker on iOS 7 with JB you need to use entitlements to make it working.
How to do it with entitlements you can find here:
iOS 7: How to get own number via private API?
AppStore will reject it, as it's reaching outside of application container.
Apps should be self-contained in their bundles, and may not read or write data outside the designated container area
Section 2.5.2 :
https://developer.apple.com/app-store/review/guidelines/#software-requirements

Getting the HostName of a Remote iOS Device with NSNetService

After more than a few hours of searching, I got in what looks like a dead end. In this case, all that I am trying to do, is to get all the iOS Devices of the network with Bonjour. I did so like this
self.serviceBrowser = [[NSNetServiceBrowser alloc] init];
[self.serviceBrowser setDelegate:self];
[self.serviceBrowser searchForServicesOfType:#"_apple-mobdev2._tcp." inDomain:#"local."];
This works fine, though what I get is the following:
local. _apple-mobdev2._tcp. [MAC ADDRESS HERE]
I tried to resolve the connection by using the sync port (62078), since service.port returns -1.
for (NSNetService *service in self.services) {
NSLog(#"%#", service);
NSNetService *newService = [[NSNetService alloc] initWithDomain:service.domain type:service.type name:service.name port:62078];
[newService setDelegate:self];
[newService resolveWithTimeout:30];
}
This in its own turn calls netServiceWillResolve: with no problem at all, but, it doesn't make it to netServiceDidResolveAddress:
But neither does this fail. netService:didNotResolve: isn't called either, I believe it is just waiting for a response to be resolved.
To support this claim, once it did make it to the method and actually [service hostName]; did return Yanniss-iPhone, but that happened at a completely random time that I had left the Mac App running for around half an hour. What could have invoked this to run? Or does anyone know of a different way to get the hostName of the remote device? The other answers do not answer my question, since I am looking for the hostName of the remote device, not of the Mac device.
Relative to that, I've found that when you kill and restart iTunes, along with iTunes Helper, the very log I mentioned below is sent again. Which is why I believe the correct log was an iTunes related event. Any help is very much appreciated!
iTunes search bonjour for wifi sync capability. As for the didNotResolve or resolve delay, bonjour services randomly cast itself anywhere between a few seconds to 30 minutes.
I am actually trying to connect to iOS devices too, but I could not get any response or any devices returned. :\

Resources