Connecting to external URL from WatchKit 2.0 - apple-watch

I would like to load some information in the WatchKit interface from a REST backoffice. Is there some fast way to execute a URL request passing by the host iOS app or I must concoct a specific protocol taking advantage of the bare WatchConnectivity functionalities?

You should use NSURLSession directly from your WatchKit extension.

NSURLSession works fine with Watchkit, but you will need to add Allows Arbitrary Loads on Watchkit Extension too if it is relevant.
Please see this post,
NSURLSession returns data as Null on Watch OS2 using Objective-C

I am using sendMessageData:replyHandler:, yet I have problems in having it properly working. The relative ticket is at:
https://stackoverflow.com/questions/33211760/sendmessagedata-does-not-call-didreceivemessagedata-on-the-counterpart

Although Apple's example is in swift see https://developer.apple.com/videos/play/wwdc2015-228/?time=345 , I've pasted a snippet in obejctive-c utlisin the NSProcessInfo wrapper.
Apple's example also makes use of Semaphore's, should the extension be put to sleep, which I have omitted from below.
Following the below pattern enables you to hit a desired service directly from the watch.
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
[processInfo performExpiringActivityWithReason:#"networkReq" usingBlock:^(BOOL expired) {
if (!expired){
NSLog(#"we have an assertion");
NSTimeInterval secondsInThreeHours = 3 * 60 * 60;
NSURL *forecast = [NSURL URLWithString:#"http::address"];
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:forecast
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// handle response
}] resume];
else{
NSLog(#"Not background assertion or we are out of time");
}
}];

Related

Right way to handle user session with IOS NSURLSession

Hi I am beginner to IOS development. I am developing small IOS application. Required functionality of that application is like this. Application have login for user. once your logged in it will not ask for login again until user do logout. I completed login part. I done with login using NSURLSession.Now after login I want to fetch some thing from server but it is giving error with status code 0 or 1012. I don't know why it is giving this error. So my questions are like this
How NSURLConnection works?
Is it taking care of session for user or I have to take care of that?
After login process I am not able to do anything, mostly because of unauthorised access. I did login in following way
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:url completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error)
{
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
NSLog(#"sttaus code %i", httpResp.statusCode);
if(error)
{
[self.delegate signinWithError:error];
}
else
{
[self.delegate signinWithJson:data];
}
}] resume];
I have to set NSURLSession globally or I can use it locally as well?
Is there any one have good explanation about it? Any good example ? Need Help. Thank you.

How to correctly provide networking feedback to the user? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
My app retrieves currency exchange rates from a web service using a synchronous NSURLConnection in a background GCD queue, like this:
// This method is called in background queue
- (NSData*)fetchDataWithURLStr:(NSString*)urlStr {
NSData *jsonData = nil;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSURL *url = [NSURL URLWithString:urlStr];
NSURLResponse *response = nil;
NSError *error = nil;
NSURLRequest *request = [NSURLRequest requestWithURL:url];
jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error != nil) {
NSString *errorMsg = nil;
NSInteger ec = [error code];
if (ec == NSURLErrorTimedOut || ec == NSURLErrorCannotConnectToHost) {
errorMsg = #"Data temporarily not available.";
}
// Call on main thread
dispatch_async(dispatch_get_main_queue(), ^{
// Present the error
[self showErrorWithCode:ec title:#"ERROR" message:errorMsg];
});
jsonData = nil;
}
return jsonData;
}
But the problem is often the app tries to fetch data, and the download seems to be running forever and nothing happens. No status updates just nothing. Often my WiFi is just stalled and I must go to Settings, disable and re-enable this. Or internet connectivity of my WiFi router at home is down but the device is connected to WiFi.
What I really want to do is give precise feedback about what exactly is happening on the network right now. For example
"Trying to contact server..."
"Wait... still trying..."
"Your internet seems broken..."
"Trying again..."
"Response received..."
"Downloaded 20%"
"Downloaded 40%"
"Finished!"
Just exact feedback about what is going on.
Someone recommended MKNetworkKit but it just feels as dead, no feedback whatsoever.
Are there solutions to this problem which work for iOS?
EDIT: I have Reachability in place but it does not give me this kind of feedback I want to display during networking. Also, Reachability does not tell me what is going on when there is a WiFi connection but the internet is stalled.
The fundamental problem here is that it is impossible (yes impossible) to give a reliable diagnosis of a network problem based on the information that is available to your app. There are simply too many possible causes, and some of them are simply not distinguishable without knowledge of the actual networks and / or access to other sources of diagnostic information.
U can user Reachability classes.
Here is a sample code which uses this reachability classes, and notifies us which type connection we are using. The sample code is from apple.
Have a look at & implement in the same way.
In order for showing the progress to the user, i suggest to use NSURLConnection from the its delegate methods you can easily get the status of the connection/request.
In one of its delegate it gives error description.
You should use the asynchronous API instead. Using the synchronous API in a separate worker thread/queue is often not the right way to go (see the WWDC'12 videos about those subjects)
A better solution would be to use the newer NSURLConnection API and the +sendAsynchronousRequest:queue:completionHandler: method instead of using sendSynchronousRequest: returningResponse: error:. This way you would avoid blocking your API and be informed when the request fails (either fails starting or fails while running because the network went down etc).
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse*, NSData*, NSError*) {
// Code that will be executed asynchronously
// when the response to the request has been received
}];
// After the call to this method above, the code will continue executing
// WITHOUT WAITING for the network request to have its response.
This way your UI won't "freeze" and the rest of your code will continue to run, so you can, like, show some progress indicator on your views for example, and so on. The code in the completionHandler block will be called asynchronously (independently of the rest of your code) only once the response has arrived.
Moreover, to be informed when the network itself is unreachable (went down, etc), use Reachability for that [EDIT] You seem to do this already as you added in the EDIT of your question, so you should already be informed about that and being able to inform the user in this case)
Tip: you may also use some third party frameworks, like the excellent [AFNetworking(https://github.com/AFNetworking/AFNetworking), that allows you to do much more when sending network requests, like having an Objective-C block of code to be called while the network request is in progress, allowing you to know the progression of the download easily.
Once you have integrated the AFNetworking project in your workspace, you would be able to do stuff like this:
AFHTTPRequestOperation* reqOp = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
[reqOp setCompletionBlockWithSuccess: ^(AFHTTPRequestOperation *operation, id responseObject)
{
// Code to execute asynchronously when you successfully received the whole page/file requested
// The received data is accessible in the responseObject variable.
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Code to execute asynchronously when you request failed, for example if you have a network error, or received some 404 error code, etc.
progressLabel.text = [NSString stringWithFormat:#"Download error: %#", error];
}];
[reqOp setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead)
{
// Code to execute periodically each time a partial chunk of data is received
// So that you can update your progression. For example:
progressLabel.text = [NSString stringWithFormat:#"Downloading %.1f%%", (float)totalBytesRead*100.f/totalBytesExpectedToRead];
}];
[reqOp start]; // start the request
// The rest of the code will continue to execute, and the blocks mentioned above will be called asynchronously when necessary.
Here is how i check for internet connection . You need to add the Reachability first .
+ (BOOL) checkNetworkStatus
{
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [reachability currentReachabilityStatus];
return !(networkStatus == NotReachable);
}

Facebook iOS SDK 3.0, implement like action on a url?

I'm trying to implement Like via the facebook open-graph-api with the Facebook iOS SDK 3.0.
Everything seems to work except the FbGraphObject and that's because I have no idea how it should look because this clearly does not work.
What I'm trying to do is to like a url posted as an object. A simple Like with via the open-graph.
The error message I get the the code below is:
The action you're trying to publish is invalid because it does not specify any
reference objects. At least one of the following properties must be specified: object.
The code I use is this:
FBGraphObject *objectToLike = [[FBGraphObject alloc]initWithContentsOfURL:[NSURL URLWithString:facebookLike.titleLabel.text]];
FBRequest *requestLike = [[FBRequest alloc]initForPostWithSession:[FBSession activeSession] graphPath:#"me/og.likes" graphObject:objectToLike];
FBRequestConnection *connection = [[FBRequestConnection alloc] init];
[connection addRequest:requestLike
completionHandler:
^(FBRequestConnection *connection, id result, NSError *error) {
if (!error &&
result) {
DLog(#"NothingWentWrong");
}
DLog(#"MajorError: %#", error);
}
];
[connection start];
UPDATE:
Checked some more info and my guess it to use this method:
https://developers.facebook.com/docs/sdk-reference/iossdk/3.0/class/FBGraphObject/#//api/name/graphObject
To somehow create an object. It's the graphObject method that I probably need to do something with. Any help at all would be appreciated.
I've actually manage to create a simple and quite dirty solution of this.
The solution does not seem optimal but it's currently a working solution.
If anybody has used the explorer tool on facebook on this url:
https://developers.facebook.com/tools/explorer/
You know how the URL will look like when facebook is sharing a like. It has to have the URL and an access-token.
So my solution became just to disregard sending anything from the Facebook SDK and just send a post request to the same URL that I've used in the explorer tool.
There seems to be some referencing to it on the facebooks docs if you look closely and deep, but no one explains exactly how to actually make the connection, so this is my solution:
NSString *urlToLikeFor = facebookLike.titleLabel.text;
NSString *theWholeUrl = [NSString stringWithFormat:#"https://graph.facebook.com/me/og.likes?object=%#&access_token=%#", urlToLikeFor, FBSession.activeSession.accessToken];
NSLog(#"TheWholeUrl: %#", theWholeUrl);
NSURL *facebookUrl = [NSURL URLWithString:theWholeUrl];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:facebookUrl];
[req setHTTPMethod:#"POST"];
NSURLResponse *response;
NSError *err;
NSData *responseData = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&err];
NSString *content = [NSString stringWithUTF8String:[responseData bytes]];
NSLog(#"responseData: %#", content);
If you look at the code I just take the url and puts two dynamic strings in the url, one with the object-url and one with the access token. I create a URLRequest and make it a POST request, and the response from facebook gets logged so one actually can see if the like go through or not.
There might be some performance improvements that can be done with the actual requests but I will leave it up to you if you see any slowdowns.
I'm still interested in other solutions but this is the one I will use for now.
We don't currently support Like through our Graph API.
What you can look through is something like this :
https://developers.facebook.com/docs/opengraph/actions/builtin/likes/
I’m not sure what initWithContentsOfURL does, but from the name I guess it tries to actually load content from a given URL(?).
You only have to give the URL as a text parameter – a URL is what represents an Open Graph object. Facebook will do the rest, scraping the page behind that URL and reading it’s OG meta tags, etc.
Maybe just this?
FBRequest *requestLike = [[FBRequest alloc]initForPostWithSession:[FBSession activeSession]
graphPath:#"me/og.likes"
graphObject:[NSURL URLWithString:facebookLike.titleLabel.text]];

GET and POST requests from ios5

I'm working on making a client for my REST service on the iPhone. I'm a little lost as to how I go about making the GET and POST requests. I make the url from a NSString, convert it to an NSURL and create the NSURLRequest based off of the url. After that I'm pretty lost. Also, sometimes I care about the response, other times I don't. For example, when making a request for a new id, I care about the response because it's the id I'll use to upload my file later, but when I upload the file I don't care because the server doesn't send a response.


Does anyone have some (hopefully)simple sample code that they could point me to / share?

What I have so far:
-(NSString *) makeGetRequest:(NSString *)url :(Boolean)careAboutResult
{
NSString *results = nil;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSError *reqError;
NSURLResponse *response = nil;
if(careAboutResult == YES)
{
//get the result
}
return results;
}

In the code I'm testing with, the URL is
http://192.168.0.108:8081/TestUploadService/RestfulUpload.svc/id/test123_DOT_png
and I'm saying I do care about the result.

Any help would be greatly appreciated.
#nick its good you have created a NSURLRequest now you just need to create a connection to send this request and receive response, this request is GET request.
To make POST request you will need to use NSMutableURLRequest and set its method name and body content. Here in documentation you will find how you can do this.

What's the simplest way to check the current version of your app against the latest version in the app store?

If the iOS SDK doesn't have functionality for this, then what if I have a basic (static) website, and somewhere on that website I manually set a piece of data that specifies the latest version of my app in the app store every time I release an update? How can I make my app query the website for that version data and check it against the version running on the iOS device?
You are on the right track. You need to make an HTTP request to your static version web page. To do this you can use an NSURLConnection object. So something like:
NSURL * url = [NSURL URLWithString:#"http://yourweb.com/version.txt"];
NSURLRequest * request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:60];
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
Then in your delegate implementation:
(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSHTTPURLResponse*)response
{
if(response.statusCode != 200)
// you got an error
}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
// again with the errors ...
}
// you got some data ... append it to your chunk
// in your case all the data should come back in one callback
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
[mData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// your request finished ... check the version here
}
So in your connectionDidFinishLoading you have a look at mData that you have collected. Parse out the version number and compare it to your bundle version number:
[self infoValueForKey:#"CFBundleVersion"];
You can make a query like http://itunes.apple.com/en/lookup?bundleId=com.easi6.doorsndots to AppStore.
Returning JSON has an version information (currently on AppStore) which can be compared the other in bundle.
I had used the same solution #RedBlueThing recommended in many of my apps. I have scaled it to a service that other app developers can use at CleverStork - an Update Manager for Apps. Hope you guys like it :)