With google cast iOS SDK, The GCKMediaControlChannel's sendTextMessage method is straightforward and it's hard to mis-use so I am guessing this may be a bug in the SDK ... hopefully someone will prove me wrong so I can get back to work!
Here's the code:
NSDictionary *messageDict = #{
#"message": #"blah",
#"num":[NSNumber numberWithInt:2]
};
NSError *error;
NSData *msgData = [NSJSONSerialization dataWithJSONObject:messageDict
options:0
error:&error];
NSString *message = #"" ;
if (!msgData) {
DDLogError(#"ERROR serializing message: %#", error);
return NO ;
} else {
message = [[NSString alloc] initWithData:msgData encoding:NSUTF8StringEncoding];
[self sendTextMessage:message] ;
}
...the receiver produces this error when the message is received [cast.receiver.mediaManager] Ignoring request, requestId is not an integer: undefined
At first view it seems like GCKMediaControlChannel inherits directly its sendTextMessage method from the GCKCastChannel, failing to implement some of the messaging aspects specific to the media channel (in particular failing to wrap the message in a media-style envelope with the requestId and mediaSessionID attributes)
Has anybody else encountered this? Am I missing something? Is there a workaround?
I followed the recommendation on the ticket I created, messaging to the receiver media app using a custom namespace using GCKCastChannel instead of he dedicated GCKMediaControlChannel to work around the issue. The ticket response confirms "don't use sendTextMessage directly with the GCKMediaControlChannel"
Related
I'm trying out Snpachat's SnapKit login api, and I've setup my project as described in the documentation/guide. I've allowed the use of all the scopes, i.e. external id, display name and bitmoji in the dashboard and added the required fields in the .plist of my app.
The login and authentication proceed normal and return successfully, but when I try to fetch user data, that request fails every time with the SCOAuth2ClientErrorDomain error.
I'm using the snippet provided within the guide (although that code has a typo and doesn't build as is so I doubt in the validity of that code):
[SCSDKLoginClient loginFromViewController:self completion:^(BOOL success, NSError * _Nullable error) {
NSString *graphQLQuery = [#"{me{displayName, bitmoji{avatar}, externalId}}" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSDictionary *variables = #{#"page": #"bitmoji"};
[SCSDKLoginClient fetchUserDataWithQuery:graphQLQuery
variables:variables
success:^(NSDictionary *resources) {
NSDictionary *data = resources[#"data"];
NSDictionary *me = data[#"me"];
NSString *displayName = me[#"displayName"];
NSDictionary *bitmoji = me[#"bitmoji"];
NSString *bitmojiAvatarUrl = bitmoji[#"avatar"];
} failure:^(NSError * error, BOOL isUserLoggedOut) {
// handle error as appropriate
}];
}];
I've even tried configurin my app without the bitmoji and tried the request without it, it still fails.
[SCSDKLoginClient loginFromViewController:self completion:^(BOOL success, NSError * _Nullable error) {
NSString *graphQLQuery = [#"{me{displayName, externalId}}" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[SCSDKLoginClient fetchUserDataWithQuery:graphQLQuery
variables:nil
success:^(NSDictionary *resources) {
NSDictionary *data = resources[#"data"];
NSDictionary *me = data[#"me"];
NSString *displayName = me[#"displayName"];
} failure:^(NSError * error, BOOL isUserLoggedOut) {
// handle error as appropriate
}];
}];
Anyone have any idea what I might be doing wrong?
Ok, I got it working.
First of all, I re-added the user I was testing with to the demo users in the developer portal. After that, the SCOAuth2ClientErrorDomain error was gone and I was getting the success callback.
But, the response data was an error in the query string. The problem is that they're using a deprecated method stringByAddingPercentEscapesUsingEncoding. I'm not sure what the exact problem is but I've just sent the raw string as a query and I got a valid response.
UPDATE: I think encoding here is not needed. It doesn't make sense for the user of the api to encode the query. The api should handle it internally, and I think that is what might be happening here. So you probably get a double encoded query which then isn't encoded properly and is invalid. I tested encoding with non-deprecated methods for URL queries and it still didn't work. A raw query string is the way to go.
I have a method that accepts an NSString by reference, and the idea is that if an error occurs, the string will contain a specific error message; otherwise, it'll be nil.
-(BOOL)doStuffThatCouldProduceAnError:(NSString *)error {
...
// An error occurred, so set the string
error = #"Foo Bar is invalid"
return NO;
}
But the problem is, the caller of doStuffThatCouldProduceAnError doesn't see the error message:
-(void)someMethod {
NSString *error;
[self doStuffThatCouldProduceAnError:error];
[NSLog #"Message: %#", error]; // Logs "[nil]"
}
I'm not sure how to search for a solution, and what I did try to search on doesn't cover the passing by reference and setting from another method. I've also tried NSMutableString, but that doesn't seem to make any difference.
Thank you in advance!
Edit: I forgot to mention that I've tried using error = [error stringByAppendingString:...], but that didn't work either.
You are not passing by reference.
You got to do
-(BOOL)doStuffThatCouldProduceAnError:(NSString **)error {
*error = #"Foo Bar is invalid"
and
[self doStuffThatCouldProduceAnError:&error];
I'm trying to resolve the Cocoa error 3840 for a couple hours now. I've read all the answers posted here on stackoverflow and on any other sources I could find but nothing seems to help...
The problem is that I know this error occurs when there is something wrong with the JSON object you receive from the server but the JSON I'm receiving is valid. I've tested it on multiple JSON validators online and its checks out every time.
Here's my code:
NSError *localError = nil;
NSDictionary *parsedObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&localError];
if (localError != nil) {
NSLog(#"%#", [localError localizedDescription]);
} else {
//NSDictionary *dict = [parsedObject objectForKey:#"status"];
//NSLog(#"%#", [dict objectForKey:#"message"]);
}
return parsedObject;
Heres a google drive link to the JSON: https://docs.google.com/document/d/1rC_--QiS85A82L2AohuqjC0JWIgVEAj68i7UUOxpvMw/edit?usp=sharing
This error only occurs for some responses that i get from the server. The same code works fine for other links from the same API.
I've tried this with NSArray instead of NSDictionary thinking that maybe the server might be serving an array instead of a hash, also tried changing the option value for JSONObjectWithData:data:options:error method but as you can guess nothing worked.
I'll greatly appreciate any help I can get.
I have the following code to read in passed URLs. I'm testing this with the Pocket app and although hasItemConformingToTypeIdentifier is returning YES for kUTTypeURL, trying to load it in returns a error instead stating
"Unexpected value class."
. If I try to load it as an id<NSSecureCoding> item and debug, I find that the passed in object is indeed just the title of the page and not the URL. How do I read the URL?
NSURL *pageURL = nil;
for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *itemProvider in item.attachments) {
if ([itemProvider hasItemConformingToTypeIdentifier: (NSString*) kUTTypeURL]) {
[itemProvider loadItemForTypeIdentifier:(NSString*) kUTTypeURL options:nil completionHandler:^(id <NSSecureCoding> urlItem, NSError *error) {
if ([((NSObject*)urlItem) isKindOfClass: [NSURL class]]) {
pageURL = [((NSURL*)urlItem) absoluteString];
}
}];
}
}
}
If you read the documentation for:
loadItemForTypeIdentifier(_:options:completionHandler:)
You'll see that:
The type information for the first parameter of your completionHandler
block should be set to the class of the expected type. For example,
when requesting text data, you might set the type of the first
parameter to NSString or NSAttributedString. An item provider can
perform simple type conversions of the data to the class you specify,
such as from NSURL to NSData or NSFileWrapper, or from NSData to
UIImage (in iOS) or NSImage (in OS X). If the data could not be
retrieved or coerced to the specified class, an error is passed to the
completion block’s.
Maybe you can experiment by coercing to different types?
Try this
__block NSURL *pageURL = nil;
for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *itemProvider in item.attachments) {
if ([itemProvider hasItemConformingToTypeIdentifier: (NSString*) kUTTypeURL]) {
[itemProvider loadItemForTypeIdentifier:(NSString*) kUTTypeURL options:nil completionHandler:^(NSURL *urlItem, NSError *error) {
if (urlItem) {
pageURL = urlItem;
}
}];
}
}
}
And now if you want take URL of your current site use
NSString *output = [pageURL absolutestring];
Output - will be your URL.
I stumbled over this issue now myself. The Pocket App seems to be the only App which shows this issue. The strange thing is that there are Apps which can get the URL form Pocket. Like for example Firefox for iOS. Firefox is Open Source so I looked at its code (at Github) and found that it is doing exactly the same to get the URL that is shown here. The only difference is that Firefox is written in Swift, and my code (and the one posted here) is Objective C. So I wonder if the Pocket App is doing something strange that is triggering a bug in the Objective C API of the iOS only, so Swift Apps are not affected? I do not have any Swift experience yet, so I haven’t checked if switching to Swift would „solve“ this.
The fact that the method "hasItemConformingToTypeIdentifier:“ states that there is a URL available but „loadItemForTypeIdentifier:“ can not deliver it, is a clear indication that the iOS itself has a bug here (at least in the Objective C API). But there still must be something special the Pocket App is doing to trigger this bug, because otherwise this would not work in all other Apps.
I've developed some iOS 6.1 code to deal with NSError. But, I'm not happy with it. It is at best a hack:
-(bool) reptErrAtModule: (NSString *) module
atSubr: (NSString *) subr
atFunc: (NSString *) func
withErr: (NSError *) err
{
id value = [[err userInfo] objectForKey: NSUnderlyingErrorKey];
NSString * errDesc = (value != nil) ?
[value localizedDescription]:
(NSString *)[[err userInfo] objectForKey: #"reason"];
NSLog( #"ERR -> %#",[NSString stringWithFormat:
#"(%#>%#) %# failed! %#",module,subr,func,errDesc] );
}
I had a simpler form (without the (NSString *)[[err userInfo] objectForKey: #"reason"] case) and it worked for errors that I got back from calls to removeItemAtPath.
But then I got an error back from this code:
NSPersistentStore * entStor =
[myPerStoCor addPersistentStoreWithType: NSSQLiteStoreType
configuration: nil
URL: [NSURL fileURLWithPath: Path]
options: nil
error: &err];
And my routine failed to extract the error. So I added the #"reason" logic because I could see the text I wanted in the Info data in the debugger.
Now the code works with both types of errors but I'm thinking this is not the way to do this. There must be a better, more generic way to deal with all the types of errors stuff the system can give you back in NSError.
I use this:
NSString *description = error.localizedDescription;
NSString *reason = error.localizedFailureReason;
NSString *errorMessage = [NSString stringWithFormat:#"%# %#", description, reason];
For debugging purposes, you ideally want to log out the entire contents of the error. Roughly speaking this is the domain, code, and userInfo. Bear in mind that userInfo might well include an underlying error, which you want to apply the same logic to. And in some cases, the error might supply a description (or failure reason etc.) which isn't present in the userInfo.
If you scroll down my blog post at http://www.mikeabdullah.net/easier-core-data-error-debugging.html, there's a snippet there showing how to generate a dictionary representation of an NSError object, and then get a string representation of that. This is pretty handy for debugging/logging purposes.
For presentation to users though, -[NSError localizedDescription] is expressly designed for such purposes. -localizedFailureReason serves a similar role, tending to specify what went wrong, without the context of the operation being tried. (One way to think of it is localizedDescription = task desceription + localizedFailureReason)