NSNetService: Handle name conflicts when publish service - ios

According to the Apple documentation :
If that service name conflicts with an existing service on the network, Bonjour chooses a new name. ... your service is automatically renamed if it conflicts with the name of an existing service on the network
How can I achieve this function?
My implementation:
self.publishService = [[NSNetService alloc] initWithDomain:#"local." type:#"_http._tcp." name:#"MyName" port:80];
self.publishService.delegate = self;
[self.publishService publish];
- (void)netServiceDidPublish:(NSNetService *)sender {
NSLog(#"did publish: %#", sender.name);
}
- (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary *)errorDict {
NSLog(#"did not publish: %#", errorDict);
}
When this service is already published the didNotPublish delegate method will be called. I assume the service won't be published?
I thought that the netServiceDidPublish: delegate method should be called again for the service with the new name, but it isn't.

The problem here is the port, not the name.
If there is a name collision, it automatically renames the service by appending " (2)" to the name, increasing the number as far as it needs to. In this case it will publish successfully and call netServiceDidPublish:.
If the port is already used by another published service it won't publish it, and will call netService:didNotPublish: with the error dictionary set to NSNetServicesErrorCode = 48; NSNetServicesErrorDomain = 1;.

Related

Azure Push Notification Error from IOS Xcode

I feel I am the first one in the universe trying to get iOS swift working with Azure, not much help out there.
I followed this Create an iOS app
and then Add Push Notifications to your iOS App. I am supposed to be able to do a successful push notification from iPhone, but I get this error. btw: I can get my C# code to trigger in visual studio in my pc (using this tutorial), so the request seems to be working, but the response sucks. Any one knows how to fix it!!
Error registering for notifications: Optional("Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1302 \"{\"message\":\"An error has occurred.\"}\" UserInfo={com.Microsoft.MicrosoftAzureMobile.ErrorRequestKey=<NSMutableURLRequest: 0x14cebf780> { URL: http://<mysite>.azurewebsites.net/push/installations/1E32E9B5-E976-4CCD-BD61-D026D3F4FF1C }, com.Microsoft.MicrosoftAzureMobile.ErrorResponseKey=<NSHTTPURLResponse: 0x14cec54b0> { URL: http://<mysite>.azurewebsites.net/push/installations/1E32E9B5-E976-4CCD-BD61-D026D3F4FF1C } { status code: 500, headers {\n \"Content-Length\" = 36;\n \"Content-Type\" = \"application/json; charset=utf-8\";\n Date = \"Wed, 11 May 2016 21:39:39 GMT\";\n Server = \"Microsoft-IIS/8.0\";\n \"Set-Cookie\" = \"ARRAffinity=8d79cd782ff16b44f7f280b76e2bc5564d86e0d1b228227b8e0033f4bb1c4582;Path=/;Domain=<mysite>.azurewebsites.net\";\n \"X-Powered-By\" = \"ASP.NET\";\n} }, NSLocalizedDescription={\"message\":\"An error has occurred.\"}}")
UPDATE #1
The only url I have is the one per the tutorial. The rest of the code is identical to the ones I mentioned in the links (I copied it character by character):
class ClientManager {
static let sharedClient = MSClient(applicationURLString: "http://<mysite>.azurewebsites.net")
}
UPDATE #2
#Pau Senabre I am working with swift not Objective-C per my question (see my tags under question), so I don't have an .m file per your step #1. I also don't have the logErrorIfNotNil you mentioned. My method (which is generated by Azure before modifications) looks like this:
#IBAction func addItem(sender : AnyObject) {
self.performSegueWithIdentifier("addItem", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!)
{
if segue.identifier == "addItem" {
let todoController = segue.destinationViewController as! ToDoItemViewController
todoController.delegate = self
}
}
UPDATE #3
#Pau Senabre My goal is to do mobile apps/services, not mobile engagement. See the difference here. btw: I had followed the azure engagement example when I started playing with it and had worked for me. But my need now is web/mobile apps. So, does what you suggested still apply for my need?
Could you please post some code? I think you may be using a wrong URL in a certain place.
To UPDATE #2
Check the following link:
https://github.com/Azure/azure-content/blob/master/articles/mobile-engagement/mobile-engagement-ios-swift-get-started.md
In section Modify your Application Delegate make sure you create a reach module and your existing Engagement initialization has all the init Values.
EngagementAgent.init("Endpoint={YOUR_APP_COLLECTION.DOMAIN};SdkKey={YOUR_SDK_KEY};AppId={YOUR_APPID}", modulesArray:[reach])
The error Code provided Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1302 matches to a bad request. If you are entering some data, make beforehand a Data Input Validation:
1 In the TodoService.m file, locate the addItem method search for the [self logErrorIfNotNil:error]; line of code. Beneath that line of code, replace the remainder of the completion block with the following code that checks to see if there was an error in the request and if that error code was –1302, indicating a bad request:
BOOL badRequest = ((error) && (error.code == -1302));
// detect text validation error from service.
if (!badRequest) // The service responded appropriately
{
NSUInteger index = [itemscount];
[(NSMutableArray *)itemsinsertObject:result atIndex:index];
// Let the caller know that we finished
completion(index);
}
2 Build and run; you can see in the Xcode output window that the bad request error from the service was handled:
2012-10-23 22:01:32.169 Quickstart[5932:11303] ERROR Error Domain=com.Microsoft.WindowsAzureMobileServices.ErrorDomain Code=-1302 “Text length must be under 10″ UserInfo=0x7193850 {NSLocalizedDescription=Text length must be under 10, com.Microsoft.WindowsAzureMobileServices.ErrorResponseKey=, com.Microsoft.WindowsAzureMobileServices.ErrorRequestKey=https://task.azure-mobile.net/tables/TodoItem>}
3 Finally, in the TodoService.m file, locate the logErrorIfNotNil method, which handles the logging of errors to the output window. Inside the if code block, just below the line NSLog(#”ERROR %#”, error); add the following if block:
// added to display description of bad request
if (error.code == -1302){
UIAlertView *av =
[[UIAlertView alloc]
initWithTitle:#”Request Failed”
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#”OK”
otherButtonTitles:nil
];
[av show];
}
Aditionally, review the following steps in the Azure Setup, maybe you are missing something at some point:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-ios-get-started-push/
1 Create a Notification Hub
This creates a new notification hub and connects it to your mobile app. If you have an existing notification hub, you can choose to connect it to your Mobile App backend instead of creating a new one.
2 Register app for push notifications
Register an App ID for your app. Create an explicit App ID (not a wildcard App ID) and for Bundle ID, use the exact Bundle ID that is in your Xcode quickstart project. It is also crucial that you check the Push Notifications option.
Next, configuring push notifications. You may create either a "Development" or "Distribution" SSL certificate (remember to select the corresponding option in the Azure portal later.)
3 Configure Azure to send push notifications
In the Azure portal, click Browse All > App Services > your Mobile App backend > Settings > Mobile > Push > Apple Push Notification Services > Upload Certificate. Upload the .p12 file, selecting the correct Mode (corresponding to whether the client SSL certificate you generated earlier was Development or Distribution.)
4 Update server project to send push notifications
Replace the PostTodoItem method with the following code:
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
// Get the settings for the server project.
HttpConfiguration config = this.Configuration;
MobileAppSettingsDictionary settings =
this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();
// Get the Notification Hubs credentials for the Mobile App.
string notificationHubName = settings.NotificationHubName;
string notificationHubConnection = settings
.Connections[MobileAppSettingsKeys.NotificationHubConnectionString].ConnectionString;
// Create a new Notification Hub client.
NotificationHubClient hub = NotificationHubClient
.CreateClientFromConnectionString(notificationHubConnection, notificationHubName);
// iOS payload
var appleNotificationPayload = "{\"aps\":{\"alert\":\"" + item.Text + "\"}}";
try
{
// Send the push notification and log the results.
var result = await hub.SendAppleNativeNotificationAsync(appleNotificationPayload);
// Write the success result to the logs.
config.Services.GetTraceWriter().Info(result.State.ToString());
}
catch (System.Exception ex)
{
// Write the failure result to the logs.
config.Services.GetTraceWriter()
.Error(ex.Message, null, "Push.SendAsync Error");
}
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
this is the proper answer from another question I had earlier, which fixes both: Registration and Receiving push notifications. I said this in here:
I finally have been able to receive notifications last night. I went ahead and redid an entire walk-through of all apple-side installation steps using this tutorial: Sending push notifications to iOS with Azure Notification Hubs then the azure-side of things using this: Create an iOS app and Add Push Notifications to your iOS App. That took care of the registering the app of the device successfully, which I was able to verify using the note of AdrianHall in this thread. But that wasn't enough. The Azure tutorials fell short detailing the steps needed in Xcode, which I found here: [How To] Setup Remote Push Notification in iOS - Swift 2.0 Code I didn't have to setup any "push notification" in Xcode or anything like that.
I hope this detailed answer will save you many hours of digging through.

How to setup reachability test for specific domain through AFNetworking?

AFNetworkReachabilityManager *mgr=[AFNetworkReachabilityManager sharedManager];
[mgr startMonitoring];
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
//NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));
if ([AFNetworkReachabilityManager sharedManager].reachable) {
NSLog(#" ONLINE");
}
else
{
NSLog(#"OFFLINE");
}
}];
This is how I tested reachability through AFNetworking now! How to check reachability in specific domain? And how does AFNetworking uses to test the reachability ?
[AFNetworkReachabilityManager managerForDomain:#"www.google.com"]; didn't work
Couple of things.
First, you really should configure the manager before starting monitoring. In this case this means you should call setReachabilityStatusChangeBlock before calling startMonitoring.
Second, when you're creating new AFNetworkReachabilityManager by using managerForDomain:, you are responsible for managing lifetime of the object. If you use code above with ARC enabled, mgr will be deallocated as soon as it goes out of scope meaning that there will be no manager to monitor reachability. One solution is to make mgr an instance variable of a class, e.g. an application delegate.
/**
Creates and returns a network reachability manager for the specified domain.
#param domain The domain used to evaluate network reachability.
#return An initialized network reachability manager, actively monitoring the specified domain.
*/
+ (instancetype)managerForDomain:(NSString *)domain;
this is from the afnetworking source code,
to monitor a specified domain, just create a reachability manager for that domain using this class method. like this
AFNetworkReachabilityManager *mgr= [AFNetworkReachabilityManager managerForDomain:#"www.google.com"];

Setting up XMPPFramework for iOS

I am working on an iOS app with a chat function. I want to know if there is any resource to configure the XMPPFramework in order to connect my iOS app with Openfire server.
I am new to XMPP Protocol.
I am currently learning about XMPP Stream and Rosters but I need to at least get the connection to work.
Please help.
To get yourself started, dive into the sample iOS project in XMPPFramework-master > Xcode > iPhoneXMPP.
Preferably, begin tweaking in the project itself, and get your understanding from there before moving on to create your own XMPP project.
Basically to connect XMPP to OpenFire server, most of the configurations lie in AppDelegate.
Set your OpenFire server's details in the XMPP setup:
- (void)setupStream
{
...
// Specify your server's IP address
[xmppStream setHostName:#"123.12.123.12"];
// Specify your host port
[xmppStream setHostPort:5222];
}
Assuming you have already created a contact in your OpenFire's roster, set a contact's credentials in the XMPP connection method:
- (BOOL)connect
{
/**
* Of course, do not hardcode in an actual implementation
* Appending the server name at the back of user ID is necessary
*/
myJID = #"user#openfire";
myPassword = #"password goes here";
}
Ensure you call the connect method in app launch method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self connect];
}
Ensure you are connected here:
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
NSLog(#"User Connected");
// You are connected to the server at this point.
}
Ensure you are authenticated here:
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
NSLog(#"User Authenticated");
/**
* Once you've reached this point,
* Check your server for the online users.
* You should now be seen as "available".
* Cheers!
*/
}

iOS XMPP Framework, how to handle wrong credential?

All the codes I use are from https://github.com/robbiehanson/XMPPFramework. Inside the sample code.
In my iOS7 messaging app, I invoke the "connect" function inside XMPP Framework after the user has entered their login credential and clicked the "login" button. The connect function works fine if they entered the correct credentials the first time, but would not work if the user entered the wrong credential. Because this very first line inside connect would simply return TRUE:
if (![_xmppStream isDisconnected]) {
return YES;
}
Which means any further presses on the login button would do nothing.
Should I manually invoke authenticateWithPassword? Is this the right practice assuming a connection between the client and the server has been setup?
Thank you.
You need to use the methods in the delegate to handle authentication. First you need to connect to the server if it's not already connected:
[_xmppStream connectWithTimeout:10 error:&error];
Once the stream is connected to the server the delegate method will be invoked:
- (void)xmppStreamDidConnect:(XMPPStream *)sender;
Inside that method, you can call authenticateWithPassword. If the stream was previously connected (would be the else part of the if you posted) you can just call authenticateWithPassword.
If authentication fails, the following delegate method is called:
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error;
There you can decide to show a message to the user and start over. If authentication succeeds, the following method is called:
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender;

XMPPFramework - Auto Accept of Presence Subscription Requests

I think the title is illustrating enough, but here's the story:
I'm new to XMPPFramework for iOS, and I want to set my client to automatically accept any subscription request it receives. So that other clients can see this client's presence status, when they request it.
According to developer comments In XMPPRoster.h file, there's this method which is called when a subscription request is received:
/**
* Sent when a presence subscription request is received.
* That is, another user has added you to their roster,
* and is requesting permission to receive presence broadcasts that you send.
*
* The entire presence packet is provided for proper extensibility.
* You can use [presence from] to get the JID of the user who sent the request.
*
* The methods acceptPresenceSubscriptionRequestFrom: and rejectPresenceSubscriptionRequestFrom: can
* be used to respond to the request.
**/
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence;
But it is not implemented in XMPPRoster.m. So I implemented it as following :
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
[self acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Since I'm new to XMPPFramework I dunno if I have done anything wrong, but I still cannot get this client's presence in other clients.
I also have seen similar topics like Accept buddy request in xmpp client iphone or Xmpp Accepting buddy request but the solution does not seem to be even related !
Any suggestions is really appreciated.
Thanks.
You did it wrong. You do not have to implement something in XMPPRoster.m or other library files.
This function
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence;
is a callback fired when your xmpp client receives presence subscription request. If you want to execute some code when this callback fired you have to implement a protocol called XMPPRosterDelegate. Protocol is a feature like interface in Java and C# or like abstract class in C++. You have to have a class that inherits from this XMPPRosterDelegate and finally implements this function (and other functions if you want so).
If you want to autoaccept all requests you have to implement your protocol function implementation like this:
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
[sender acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Also roster object got to know who is its delegate (an object who implements XMPPRosterDelegate), cause if you want to send someone a message you have to know two things: target and selector. Selector is specified in protocol. Target is a delegate property. You have to set roster's delegate during its initialization. In my code I added line
[xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
before line
[xmppRoster activate:xmppStream];
Of course self implements XMPPRosterDelegate and especially has this piece of code
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
[sender acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Good luck and sorry for long post.

Resources