UIActivityViewController completion handler still calls action even if user presses cancel - ios

This is really annoying! Completed is always returned yes even if the user cancels the share option. e.g. I tap on the facebook share and dont share, just tap cancel. Is there a way to track this?
[activityVC setCompletionWithItemsHandler:
^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if (completed)
{
[GoogleAnalytics trackShareEvents:activityType];
}else
{
[GoogleAnalytics trackEventWithCategory:#"Share" action:#"Failed/Canceled" eventLabel:activityType];
}
}];

Related

Detect which App was launched using UIActivityViewController

When an external app is launched using UIActivityViewController, can we detect which app was used in the completionHandler?
In Apple's documentation, there is mention of a property UIActivity.ActivityType, but it seems this is used only to detect "built-in activities". How can I detect if, eg. WhatsApp Messenger was launched?
When setting up your UIActivityViewController, use the completionWithItemsHandler to setup a completion closure that is called when the user makes a selection.
This completion block takes four parameters: the (optional) selected activity, a completion indicator, an optional array of returned items, and an error.
The selected activity is of type UIActivity.ActivityType. Its rawValue is a String representing the activity. If the activity type isn't one of the provided constants, compare its rawValue against a string you determine by running some tests to see its value for a given activity such as WhatsApp.
In Objective-C
You can use this code to know which activity was used
shareSheetVC.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *error){
if (completed) {
NSLog(#"Shared by activity %#", activityType);
} else {
NSLog(#"ShareSheet was closed");
}
if (error) {
NSLog(#"An Error occured: %#, %#", error.localizedDescription, error.localizedFailureReason);
}
};
Output when I shared using WhatsApp

Unlock a feature when the user shares the app via Facebook/Tweeter in iOS, Swift?

Is there such feature that can be un-locked when the user shares my app via Facebook or Tweeter?
Like this:
1) The user clicks on "Share" button within my app
2) My app is then posted(shared or advertised) on the wall of the user's facebook
3) Some feature gets unlocked within my app
You can use the Facebook sharing delegate method to know whether the user has successfully shared OR not.
Below is FB developer link which show various sharing methods,according to your requirements.
https://developers.facebook.com/docs/sharing/ios
Below are the methods in which you can know the sharing status
- (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results{
//UNLOCK THE APP FEATURE IN THIS METHOD
}
- (void)sharerDidCancel:(id<FBSDKSharing>)sharer{
}
- (void)sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error{
NSLog(#"%#",error);
}
See iOS Facebook Tutorial for an example of how its done on the facebook end.
On the app side you can setup a flag on NSUserDefaults or write to the app filesystem to check if the feature is unlocked.
This can be done relatively painlessly using UIActivityViewController and its completion handler.
NSString *message = #"my app is awesome.";
NSURL *link = [NSURL URLWithString:#"awesomeapp.com"];
UIActivityViewController *shareController = [[UIActivityViewController alloc] initWithActivityItems:#[message, link]
applicationActivities:nil];
//add whatever you don't want
shareController.excludedActivityTypes = #[UIActivityTypeMessage];
shareController.completionWithItemsHandler =
^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
//Share wasn't completed, don't unlock
if (!completed || activityError) {
return;
}
//Facebook or Twitter
if ([activityType isEqualToString:UIActivityTypePostToFacebook] ||
[activityType isEqualToString:UIActivityTypePostToTwitter]) {
//Unlock item logic
}
};
[self presentViewController:shareController animated:YES completion:^{
//Whatever
}];

How to detect when Facebook share has been cancelled from UIActivityViewController setCompletionWithItemsHandler

The completion handler seems to work correctly for all the other share types (Twitter, Mail) but for Facebook, the complete BOOL is YES even when you cancel the share (having first tapped the Facebook icon).
UIActivityViewController *shareActivity = [[UIActivityViewController alloc] initWithActivityItems:#[title, url] applicationActivities:nil];
[shareActivity setCompletionWithItemsHandler:^(NSString *activityType, BOOL complete, NSArray *returnedItems, NSError *activityError) {
if (complete) { //Facebook share is always YES }];
Any suggestions?
iOS 8.3, Facebook App installed.

App runs fine in iOS 8, but not in iOS 7

So, in my app, I want to share something using the UIActivityViewController.
To make sure that the sharing activity was successful, I have this code:
UIActivityViewController *controller = [[UIActivityViewController alloc]
initWithActivityItems:#[text, shortURL, image]
applicationActivities:nil];
[controller setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if (! completed){
// Here I do some stuff irrelevant to the question
}
}];
Since I have copied (and modified) this code, I don't want to claim that I completely understand what is happening here.
What I do know, and this is my question, is that the code above runs fine on iOS 8 but not on iOS 7, hardware or simulator.
I dearly hope that somebody can explain to me what is going on here.
The completionWithItemsHandler property is not available in iOS 7, as it was introduced in iOS 8.
What you're looking for is the now-deprecated completionHandler property; if your deployment target is below iOS 8, you can just use this, but if you want to be future-proof, you can check whether the new handler is supported and, if not, use the old handler:
if([[UIApplication sharedApplication] respondsToSelector:(#selector(setCompletionWithItemsHandler:))]){
[controller setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if(!completed){
// Out of scope of question
}
}];
}else{
[controller setCompletionHandler:^(NSString *activityType, BOOL completed) {
if(!completed){
// Out of scope of question
}
}];
}
}
Also, you may have omitted this for brevity, but it's important that you actually present the view controller after initializing it:
[self presentViewController:controller animated:YES completion:nil];
OK, so this is what I did. Most likely, Kremelur answered it in general terms, but I am too much of a novice to understand that. So, I copied and pasted some stuff, after some cross-googling. I hope this is of any use to someone.
[controller setCompletionHandler:^(NSString *activityType, BOOL completed) {
NSLog(#"completed dialog - activity: %# - finished flag: %d", activityType, completed);
if (! completed){
// Out of scope of question
}
}];
This code seems to run fine in both iOS7 and iOS8.

openActiveSessionWithReadPermissions is not calling back when allowLoginUI is "NO"

im updating to lastest sdk facebook (3.10) and i having a problem in the login.
When i pass allowLoginUI = YES it logins nicely and the callback block is called. but when i pass allowLoginUI = NO the callback isnt called... i dont know why.
I want to pass allowLoginUI = NO when the user already has a session.
Here is the code.
- (void)openFBSession:(NSNumber*)active{
BOOL boolValue = [active boolValue];
NSArray *permissions = [[NSArray alloc] initWithObjects:#"basic_info, email", nil];
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:boolValue
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
if (error) {
// Handle errors
[self handleAuthError:error];
} else {
// No error
[self sessionStateChanged:session state:state error:error];
}
}];
}
Here when i call the function. (The enableScreen is a function that shows the facebookLogin button)
if (FBSession.activeSession.state == FBSessionStateCreated) {
// Yes, so just open the session (this won't display any UX).
[self.window.rootViewController performSelector:#selector(enableScreen)];
} else {
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded){
[self openFBSession:[NSNumber numberWithBool:NO]];
}else{
[self.window.rootViewController performSelector:#selector(enableScreen)];
}
}
Thanks!
You need to check the return value of openActiveSessionWithReadPermissions method.
It will return YES if the session was opened synchronously without presenting the UI to the user.
When passing allowLoginUI:NO the callback is not called since this method executed synchronously.
The real thing after searching and digging its that if you call openActiveSessionWithReadPermissions with allowLoginUI = NO only will work if you have a token loaded. If not you should call with allowLoginUI = YES
Try to set nil instead of permissions array. It works for me.

Resources