I've registered the Notification Action properly and confirmed with a call to [[UIApplication sharedApplication] currentUserNotificationSettings].
I'm using Parse to assemble and send the push like this:
NSString *pushMessage = [NSString stringWithFormat:#"%# just directly asked: %#", [[PFUser currentUser] username], [self.question objectForKey:#"text"]];
NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:
pushMessage, #"alert",
#"questionNotification", #"category",
nil];
PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery];
[push setData:data];
[push sendPushInBackground];
The notification does get delivered to the device but it does not have any of the custom actions available that have been registered for the category.
At this point I feel like Parse cannot properly convey the category in the payload? Has anyone gotten them to work with Parse?
Edit:
This is the response I get from currentUserNotificationSettings that make me thing the action has been registered successfully:
<UIUserNotificationSettings: 0x14e3eaa0; types: (UIUserNotificationTypeAlert UIUserNotificationTypeBadge UIUserNotificationTypeSound);categories: {(
<UIUserNotificationCategory: 0x14e54c40; identifier: questionNotification, actions: {
1 = (
"<UIMutableUserNotificationAction: 0x14e4b860; identifier: yupAction, title: YUP activationMode: UIUserNotificationActivationModeBackground, isAuthenticationRequired:NO, isDestructive:NO>"
);}>)};>
Update: More research, in case anyone else is having this problem, when I output the userInfo received from the push notification I get:
{aps = {alert = "m just directly asked: Abaxinj";}; category = "QUESTION_CATEGORY";}
So it appears that Parse is putting the category field outside of the aps container, which is probably the problem.
Opened a bug with Parse, they confirmed they're not equipped to handle this yet. They said to check the Parse.com blog for updates when they add ios8's new functionality.
Related
I have code that executes a youtube upload that's working fine, when it's done, it then attempts to move the video to a specific playlist.
For testing, I have hardcoded the playlist (it's correct and re-verified) and the videoid (it does exist in my channel) into the code.
I cannot get the video to to the playlist I specify and get the output below from the NSlog query1, but no errors.
Query1: GTLQueryYouTube 0x1700b0860: {method:youtube.playlistItems.insert params:(part) bodyObject:GTLYouTubePlaylistItem}
Any ideas what I am missing?
// Enter PlaylistItem Code
GTLYouTubePlaylistItem *playlistitem = [[GTLYouTubePlaylistItem alloc] init];
GTLYouTubePlaylistItemSnippet *playlistitemSnippet = [[GTLYouTubePlaylistItemSnippet alloc] init];
playlistitemSnippet.playlistId = #"PL4YcQc6s41BjKOoAPAQ_B-KNC2JBB3gl2";
playlistitemSnippet.resourceId.kind = #"youtube#video";
playlistitemSnippet.resourceId.videoId = #"4frmxoGMOcQ";
GTLQueryYouTube *query1 = [GTLQueryYouTube queryForPlaylistItemsInsertWithObject:playlistitem part:#"snippet"];
UIAlertView *waitIndicator1 = [Utils showWaitIndicator:#"Moving Video to Playlist"];
NSLog(#"Query1: %#", query1);
[service executeQuery:query1
completionHandler:^(GTLServiceTicket *ticket,
GTLYouTubePlaylistItem *resource, NSError *error) {
[waitIndicator1 dismissWithClickedButtonIndex:0 animated:YES];
Ended up scrapping this and used the playlist auto add feature in youtube. Way easier.
I am trying to fetch youtube channel id using the google-api-objectivec-client. The problem I am having is basically that for some reason I am receiving exception when trying to access the channelId. The code I am using:
GTLServiceYouTube *service = [[GTLServiceYouTube alloc] init];
service.APIKey = _MY_API_KEY_;
GTLQueryYouTube *query = [GTLQueryYouTube queryForSearchListWithPart:#"id"];
query.q = #"google";
query.type = #"channel";
query.maxResults = 1;
GTLServiceTicket *ticket = [service executeQuery:query completionHandler:^(GTLServiceTicket *ticket, id object, NSError *error) {
if (error == nil) {
GTLYouTubeSearchListResponse *products = object;
for (id item in products.items) {
GTLYouTubeSearchResult *result = item;
NSLog(#"Identifier:%#",result.identifier);
GTLYouTubeResourceId* resourceId = result.identifier;
NSLog(#"kind:%#",resourceId.kind);
NSLog(#"channel:%#",resourceId.channelId);
}
}else{
NSLog(#"Error: %#", error.description);
}
}];
The output I get when i am running this code is:
2013-04-05 11:37:12.615 YouTest[21704:11303] Identifier:GTLYouTubeChannel 0x7233b00: {kind:"youtube#channel" channelId?:"UCK8sQmJBp8GCxrOtXWBpyEA"}
2013-04-05 11:37:12.617 YouTest[21704:11303] kind:youtube#channel
2013-04-05 11:37:12.617 YouTest[21704:11303] -[GTLYouTubeChannel channelId]: unrecognized selector sent to instance 0x7233b00
2013-04-05 11:37:12.618 YouTest[21704:11303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GTLYouTubeChannel channelId]: unrecognized selector sent to instance 0x7233b00'
So my implementation crashes on the point where I am trying to access the channelId of the resourceId. From the documentation I understood that the channelId should be there as the type of the resourceId is youtube#channel. The channelId can be off course parsed from the result.identifier string that I am also printing, but since there is a property for the channelId I would prefer using that.
Any ideas about what is wrong with my code?
There is indeed a bug in the Google libraries. However I solved this problem by accessing the JSON string directly and parsing it with the help of the NSString+SBJSON.h class, as in this example.
#import "NSString+SBJSON.h"
...
GTLYouTubeResourceId *resource = channel.snippet.resourceId;
NSDictionary *jsonObject = [resource.JSONString JSONValue];
NSString *channelid = [jsonObject valueForKey:#"channelId"];
I'm not very familiar with Objective-C, but yeah, that looks like there's something wrong with the generated client library's YouTube Data API v3 bindings. Are you using the latest version from the project page? You might want to file a bug against the client library if you can reproduce it with the latest version. While troubleshooting this further, I'd check to see if you have the same problem when query.type = #"video"; and you try to access the videoId of the response item.
Here's an alternative you could try, though. The channel's id is also returned in the snippet.channelId property. If you request the snippet part via GTLQueryYouTube *query = [GTLQueryYouTube queryForSearchListWithPart:#"snippet"]; see if you can read that value instead.
I had the same issue. Solved it with the following...
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:[resourceId.JSONString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSString *channelId = [jsonObject valueForKey:#"channelId"];
NSLog(#"channelId is %#", channelId);
Workaround Code:
channel.snippet.resourceId.JSON[#"channelId"];
No need to parse the JSON yourself as the underlying JSON is exposed.
It looks like the automatic binding is not working for GTLYouTubeResourceId because the "kind" element of "youtube#channel" is throwing off the runtime object creation and creating a GTLYouTubeChannel instead.
Thorough Workaround Code:
ticket.surrogates = #{ (id)[GTLYouTubeChannel class] : [GTLYouTubeResourceId class] };
If you really want to force that binding to work you can workaround a little further upstream on the ticket when you execute the query.
Global Workaround Patch:
https://github.com/google/google-api-objectivec-client/pull/109
There's open tickets for the issue:
https://github.com/google/google-api-objectivec-client/issues/63
https://github.com/google/google-api-objectivec-client/issues/92
It seems they want to change the API to not call the resourceId.kind 'kind' to avoid this problem. But while we wait for the API to change, any of these three workarounds should serve your purposes.
Using the new Facebook SDK 3.1 and iOS 6 there are 2 (actually 3) ways to post.
(Seems the new trend is to have more options to make it more simple??) OMG!!
Here is one:
SLComposeViewController *fbPost = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[fbPost addURL:[NSURL URLWithString:href]];
[self presentViewController:fbPost animated:YES completion:nil];
And this is another way using native dialogs:
[FBNativeDialogs presentShareDialogModallyFrom:self
initialText: nil
image: nil
url: [NSURL URLWithString:href]
handler:^(FBNativeDialogResult result, NSError *error) {
if (error) {
}
else
{
switch (result) {
case FBNativeDialogResultSucceeded:
break;
case FBNativeDialogResultCancelled:
break;
case FBNativeDialogResultError:
break;
}
}
}];
We, developers, think this is cool because we give a nice functionality to the user and also because our app name appears in the post and that can make some promotion of the app.
The funny thing is that latest implementations are not allowing to specify the app name was posting, the name appears after 'via'.
I tried aswell using SLRequest:
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountType *fbType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
(options)[#"ACFacebookAppIdKey"] = kFacebookAppID;
(options)[#"ACFacebookPermissionsKey"] = #[#"publish_stream"];
(options)[#"ACFacebookAudienceKey"] = ACFacebookAudienceFriends;
[store requestAccessToAccountsWithType:fbType options:options completion:^(BOOL granted, NSError *error) {
if(granted) {
// Get the list of Twitter accounts.
NSArray *fbAccounts = [store accountsWithAccountType:fbType];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
(params)[#"link"] = href;
// (params)[#"picture"] = picture;
// (params)[#"name"] = name;
(params)[#"actions"] = #"{\"name\": \"Go Gabi\", \"link\": \"http://www.gogogabi.com\"}";
//Set twitter API call
SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodPOST
URL:[NSURL URLWithString:#"https://www.facebook.com/dialog/feed"] parameters:params];
//Set account
[postRequest setAccount: [fbAccounts lastObject]];
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if(error)
{
NSLog(#"%#", error.description);
}
else
{
NSLog(#"%#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
}
}];
} else {
}
}];
Unfortunatelly to share that name is not so trivial anymore, I wonder why and who was designing the new implementation...
I would appreciate to get some help on that, thanks in advance.
I try to make my questions funny because is soo boring spend time in so trivial topics...
When you use the SLComposeViewController, it's actually the system presenting to you their controller, and it's the user who sends using the post button. Therefore on Facebook it appears as "via iOS".
There's no way to change that.
Using the Facebook SDK 3.1, under the hood it is also using the iOS 6 native integration, so when you're calling the FBNativeDialogs, on iOS 6, it's using SLComposeViewController.
Facebook continued to develop their SDK because they provide a couple of nice modules to use "out of the box" - this includes friends list selector etc... But I believe the biggest reason for Facebook to continue supporting their SDK it for backward compatibility. Under the hood if you're not on iOS 6, it falls back to it's library, and if you are on iOS 6, it uses the system integration.
Facebook is a big thing, and now it's natively available a lot of developers will be using it, just like Twitter's integration last year. The problem of course is at that point the developer has the option to drop older iOS support, or... have a lot of duplicate code, in the sense that they will check for SLComposeViewController and if it's not available (iOS 5) then use the old Facebook SDK... You can imagine how this would become very messy very quickly.
So, the Facebook SDK (3.1) is using iOS system Facebook integration if available, or if not, it's own. In a nutshell, unless you really want the Facebook SDK goodies (friend picket to name one), and you're not planning on supporting iOS < 6 then you don't need to worry about their SDK, just use the Social framework.
So, back to your question, there are 3 ways to post to Facebook ? Actually taking into consideration what I mentioned, there are 2 ways in iOS 6: SLComposeViewController or, SLRequest. On older iOS versions, only 1: Facebook SDK.
Since the SLComposeViewController is owned by the system, not your app, it will always share as "via iOS".
On the other hand SLRequest will show your apps name. When you specify an account for your SLRequest, that account was acquired via the ACAccountStore as a result of passing in some options including ACFacebookAppIdKey, which will be used to determine your Facebook apps name to post onto the users feed as part of the post.
Hope this helps.
My question may be naive, I guess, since object description is usually used for debug and output in NSLog. I also have to admit that my approach of attempting use object.description may be wrong. However, I did find in my case, information in description is just what I need. If I can fetch out the part easily from the description.
Okay, here is my code and what I need is user first name (not username):
self.facebookAccountStore = [[ACAccountStore alloc] init];
ACAccountType* facebookAccountType = [self.facebookAccountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
//[self.facebookAccountStore requestAccessToAccountsWithType:facebookAccountType withCompletionHandler:^(BOOL granted, NSError* e) {
[self.facebookAccountStore requestAccessToAccountsWithType:facebookAccountType options:facebookOptions completion:^(BOOL granted, NSError* e) {
if (granted) {
NSArray* accounts = [self.facebookAccountStore accountsWithAccountType:facebookAccountType];
self.facebookAccount = [accounts lastObject];
NSLog(#"acct description: %#", self.facebookAccount.description);
NSLog(#"acct type: %#", self.facebookAccount.accountType);
NSLog(#"acct credential: %#", self.facebookAccount.credential);
NSLog(#"acct identifier: %#", self.facebookAccount.identifier);
NSLog(#"acct username: %#", self.facebookAccount.username);
} else { //.....
}
account description gives out:
acct description:
objectID: x-coredata://F8123001-FB33-48D4-B1A7-EXXXX1243XXXX/Account/p10
enabledDataclasses: {(
"com.apple.Dataclass.Contacts",
"com.apple.Dataclass.Calendars"
)}
enableAndSyncableDataclasses: {(
)}
properties: {
fullname = "LOOKAT HERE";
uid = 100004223213342323;
}
parentAccount: (null)
owningBundleID:(null)
type:com.apple.facebook
identifier: EF34399A-8577-459B-BE5E-FD12132SEDSFE
accountDescription: Facebook
username: pspped.ok#mailserver.com
check out this part:
properties: {
fullname = "LOOKAT HERE";
uid = 100004223213342323;
}
This is exactly what I need. If I use this, I don't have to do SLRequest and SLRequestMethodGET etc to get user name (which I didn't figure out yet, another motivation why I am attempted to use object description).
My question is whether it's wrong to parse description and get out fullname property? If wrong, why?
Following question is: Wrong or not, how can I get fullname property of description gracefully (such as convert description to something that uses dot and dot to get property, not to chop the string and get that fullname part), because account.description.fullname or account.fullname so doesn't work although account.username works.
Thanks for your time/input.
It is wrong to parse the description. It's wrong because the description has no documented format. It may change arbitrarily from one instance of an object to the next and from one version of the OS to the next. So your code is likely to break. By relying on undocumented behaviour you're also in breach of your iOS Developer Programme agreement with Apple, giving them the right to pull your apps at any time.
Furthermore if for some reason you're absolute desperate to use undocumented API then you might as well use [self.facebookAccount.description valueForKey:#"fullName"]; it'll be just as robust to OS changes without you trying to second guess how Core Data object descriptions are output.
This is not the most efficient way but it works well for me:
ACAccount *acc = theAccount;
NSArray *parse = [acc.description componentsSeparatedByString:#"uid = "];
parse = [[parse objectAtIndex:1] componentsSeparatedByString:#";"];
NSString *UID = [parse objectAtIndex:0];
parse = [acc.description componentsSeparatedByString:#"fullname = \""];
parse = [[parse objectAtIndex:1] componentsSeparatedByString:#"\";"];
NSString *name = [parse objectAtIndex:0];
there any way to get my personal email accounts created in the iphone settings ??
I am making an application to send mail and would like to select one of the email accounts I have on my iPhone to send and then select the destianatorios of my agenda.
Thanks
I'm not exactly sure what you're trying to do, but iOS offers several ways to display an email composition view controller, as well as methods to access the contacts a user has saved on his /her iDevice.
To display a mail composition view, make a weak link to the MessageUI.framework in your project (a weak link is preferred since the MessageUI.framework is not available on very old iOS versions), then do something like this:
Class mailClass = (NSClassFromString(#"MFMailComposeViewController"));
if (mailClass != nil) {
// MessageUI Library is available. Presenting modal mail composer view.
MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.mailComposeDelegate = self;
[mailViewController setSubject:#"This is the subject of the email"];
[mailViewController setMessageBody:#"This is the body of the email." isHTML:NO];
[self presentModalViewController:mailViewController animated:YES];
[mailViewController release];
} else {
// MessageUI Library not available. Opening mail.app using a URL scheme.
// Note that this URL scheme only works on iOS3 and below, and seems to only accept a
// limited number of characters. For this reason, we only attach the URL.
NSString *mailBody = #"This is the body of the email."
NSString *mailSchemeURL = [NSString stringWithFormat:#"mailto:?body=%#", mailBody];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[mailSchemeURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
}
If you want to access contacts on the iDevice, link AddressBook.framework into your project. You can access the values on the device by following the instructions in Apple's programming guide. For example, you can get an array of all contacts like so:
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *contacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
I expect you can instantiate a mail composition view with a specific contact by using a combination of the above. Hope this helps!