UIActivityViewController Gmail Share subject and body going Same - ios

I am sharing Some content via UIActivityController.
It is working fine for other Options.
I am able to get subject and body in Default Mail App.
But when I use to share the content with gmail then my Subject of the mail is gone and I am getting Body content in Gmail Subject's section:
Here is my code:
NSString *body = #"I am Body";
NSString *tagLine = #"I am Subject";
NSArray *objectToShare = [NSArray arrayWithObjects:body, nil];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectToShare applicationActivities:nil];
[activityVC setValue:tagLine forKey:#"subject"];
NSArray *excludeActivities = #[UIActivityTypeAirDrop,
UIActivityTypePrint,
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToVimeo];
activityVC.excludedActivityTypes = excludeActivities;
[self presentViewController:activityVC animated:YES completion:nil];
For better Picture Here is the screenshot:
With Default App:
With Gmail:
I also tried different answers on SO. But none of them works.

At the time of writing this, Google doesn't allow setting the subject of email. People have reported it as a bug multiple times, and it seems this feature is still not supported.
Looking at other Google-owned products, and trying to share some contents via Gmail, you will see that the Gmail shared activity doesn't have the subject (e.g Google Chrome), or it's the same as the email's body (Google Translator), while if you share them to the normal app it appears that some of them have a subject. So even Google products have the same behaviour.
If you use a breakpoint inside the subjectForActivityType function you will realise that the Gmail activity won't hit the breakpoint while default mail and other activities will attempt to read the subject.
#implementation EmailItemProvider
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController {
return _body;
}
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType {
return _body;
}
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType {
return _subject;
}

Related

UIActivityViewController unable to set subject when sharing to Gmail app

I see via sharing content from other apps that it is possible to set a different subject and body when using share sheet to share into the Gmail Mail app. I have implemented it and it works fine on the native mail app but not Gmail.
Going into Yelp and sharing a business then choosing gmail from the share sheet, I see that the subject and body are different. The subject contains the address of the business while the body contains the address + a link to the business on Yelp.
I have tried to replicate this logic with success on the native Mail app but not in the Gmail app.
I have tried the following:
Implementing UIActivityItemSource methods
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[self] applicationActivities:nil];
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController {
return #"";
}
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType {
return #"body";
}
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType {
return #"subject";
}
Result
Apple Mail Subject set to "subject", Body set to "body"
Gmail Subject set to "body", Body set to "body"
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType
Is never called when sharing into the Gmail app.
I then try the more hack way of doing it
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[#"body"] applicationActivities:nil];
[activityViewController setValue:#"subject" forKey:#"subject"];
Result
Apple Mail Subject set to "subject", Body set to "body"
Gmail Subject set to "body", Body set to "body"
Any way to make Gmail Behave like Apple Mail?
Again, I have seen that other applications like Yelp and Safari have gotten the proper behavior out of the Gmail app through share sheet. Any advice would be appreciated, thanks.
[_activityViewController setValue:subject forKey:#"subject"];-Not supported way.
Correct way to set body and subject (iOS 7.0 and later)
- implement UIActivityItemSource protocol on item to share.
// EmailDataProvider.h
#interface EmailItemProvider : NSObject <UIActivityItemSource>
#property (nonatomic, strong) NSString *subject;
#property (nonatomic, strong) NSString *body;
#end
// EmailDataProvider.m
#implementation EmailDataProvider
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController {
return _body;
}
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType {
return _body;
}
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType {
return _subject;
}
#end
And than present it:
EmailDataProvider *emailItem = [[EmailDataProvider alloc]init];
emailItem.subject = #"This is Subject text.";
emailItem.body = #"This is Body,set by programatically";
UIActivityViewController *activityViewController =
[[UIActivityViewController alloc] initWithActivityItems:#[emailItem]
applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:nil];

Facebook sharing on iOS works on some devices, but not others

So I am doing just a basic facebook share inside my app, and it works fine on my devices (iPhone 6 OS 9.1 and iPad air 9.02) but doesn't work on my coworkers iPad Air 2 8.4.1 or iPhone 6 Plus 9.1. Anyone have any clue as to why this would be?
They are signed into facebook in the device settings. They also have the facebook app installed (I don't have the app, just signed in through settings)
Here's the screenshot of my device showing the message to share, the other devices just show the image and no text.
Here's the code I am using to share
- (void)shareTapped {
UIImage *image = self.pictureView.image;
NSString *postText = [NSString stringWithFormat:#"%#\n*%#\n%#\n%#, %# %#", self.event.shortDescription, self.event.eventCode, self.event.address, self.event.city, self.event.state, self.event.zip];
[[UtilitiesObject sharedInstance] shareMessage:postText image:image parentVC:self];
}
- (void)shareMessage:(NSString *)msg image:(UIImage *)image parentVC:(UIViewController *)parentVC {
NSArray *activityItems = #[msg];
if (image) {
activityItems = #[msg, image];
}
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
// Tailor the list of services displayed
activityController.excludedActivityTypes = #[UIActivityTypeAssignToContact,
//UIActivityTypePostToFacebook,
//UIActivityTypePostToTwitter,
//UIActivityTypeMail,
UIActivityTypeMessage,
UIActivityTypeSaveToCameraRoll,
UIActivityTypePrint,
UIActivityTypePostToWeibo,
UIActivityTypeCopyToPasteboard];
activityController.popoverPresentationController.sourceView = parentVC.view;
[activityController setCompletionWithItemsHandler:
^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if ([activityType isEqualToString: UIActivityTypeMail]) {
NSLog(#"Mail");
}
if ([activityType isEqualToString:UIActivityTypePostToFacebook]) {
NSLog(#"Facebook");
}
if ([activityType isEqualToString:UIActivityTypePostToTwitter]) {
NSLog(#"Twitter");
}
}];
[parentVC presentViewController:activityController animated:YES completion:nil];
}
Facebook's platform policy does not allow apps to prefill the message field. In this case, because you don't have the Facebook app, it's using Apple's share sheet, which allows prefill but is against FB's platform policy. In your friends case, they're likely seeing the Facebook app's share extension, which correctly enforces the policy, and does not allow prefill.

How to set mail subject with UIActivityItemProvider

I am using UIActivityViewController for sharing information through email. We are able to send email with body, attachments with no problem. But how do we set the subject title for the email.
I notice this question: How to set a mail Subject in UIActivityViewController?
The accepted solution is using UIActivityItemSource with this following API activityViewController:subjectForActivityType:. However, our code doesn't conform to UIActivityItemSource because we are using UIActivityItemProvider.
UIActivityItemSource
You can use this protocol in situations where you want to provide the data from one of your app’s existing objects instead of creating a separate UIActivityItemProvider object.
So the complete question is:
How do I set the email subject if I am using UIActivityItemProvider instead of UIActivityItemSource?
Define your custom item provider:
#interface CustomProvider : UIActivityItemProvider
#end
Add to your implementation:
#implementation CustomProvider
// Some other code ... -(id)item and etc.
- (NSString *) activityViewController:(UIActivityViewController *)activityViewController
subjectForActivityType:(NSString *)activityType
{
return #"A dummy Title";
}
#end
Notice that UIActivityItemProvider will automatically conform to UIactivityItemSource protocol. The difference is, you don't have to implement those #required API for UIactivityItemSource protocol.
Just add this line after you instantiate your UIActivityViewController:
[activityController setValue:#"Your email Subject" forKey:#"subject"];
I am using it like this:
- (void)share {
NSArray *activityItems;
NSString *texttoshare = [NSString stringWithFormat:#"Hey bro! check this info.\n%#\n%#", self.infoBean.title, self.infoBean.desc];
UIImage *imagetoshare = imageView.image;//this is your image to share
if (imagetoshare != nil) {
activityItems = #[imagetoshare, texttoshare];
} else {
activityItems = #[texttoshare];
}
NSArray *exTypes = #[UIActivityTypeAssignToContact, UIActivityTypePrint, UIActivityTypeCopyToPasteboard, UIActivityTypeSaveToCameraRoll];
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
activityController.excludedActivityTypes = exTypes;
[activityController setValue:#"Your email Subject" forKey:#"subject"];
[self presentViewController:activityController animated:YES completion:nil];
}
UIActivityItemProvider implements the UIActivityItemSource protocol. It's right there in the header.
#interface UIActivityItemProvider : NSOperation <UIActivityItemSource>
so you can simply use the method - (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType to return the subject in your UIActivityItemProvider subclass.

How to make a social sharing exception for Twitter / action sheet?

I am using the following code to call action sheet sharing in my app:
- (IBAction)sendPost:(id)sender
{
NSArray *activityItems = nil;
UIImage *appIcon = [UIImage imageNamed:#"appIcon.png"];
NSString *postText = [[NSString alloc] initWithFormat:#"LETS ASSUME THIS STRING IS LONGER THAN 140 CHARACTERS THAT TWITTER PROHIBITS BUT CAN STILL BE SHARED VIA FACEBOOK, EMAIL, TEXT"];
activityItems = #[postText,appIcon];
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
[self presentViewController:activityController animated:YES completion:nil];
}
The problem is this: postText is longer than 140 characters, so sharing via twitter will not be possible, the character count will be -x (red number of characters you are over in order to share via twitter), my question is this: How can I make an exception so that a different message say shortPostText will be the one used when twitter is selected for sharing?
And once the sendPost action is sent I don't see a way to explicitly set a string for twitter, once you are here:
Edit: I dont understand why someone would down-vote this question, I am not asking how to make an if/else statement or how to program. This is a genuine question, that needs a genuine answer.
UPDATE: I need a work around this because this is what I get when a user tries to share via twitter in my app:
A red/negative character indicator and a non-active post button, so unless that character count goes down to 0 or less it will not allow the post to go to twitter.
TL;DR Use UIActivityItemSource to special case payload depending on what the user selection was.
Try this instead:
- (IBAction)sendPost:(id)sender
{
UIImage *appIcon = [UIImage imageNamed:#"appIcon.png"];
NSString *postText = [[NSString alloc] initWithFormat:#"LETS ASSUME THIS STRING IS LONGER THAN 140 CHARACTERS THAT TWITTER PROHIBITS BUT CAN STILL BE SHARED VIA FACEBOOK, EMAIL, TEXT"];
TextItemSource *itemSource = [[TextItemSource alloc] initWithString:postText previewImage:appIcon];
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:#[itemSource] applicationActivities:nil];
[self presentViewController:activityController animated:YES completion:nil];
}
// ------- TextItemSource.h
#interface TextItemSource : NSObject <UIActivityItemSource>
- (id)initWithString:(NSString *)string previewImage:(UIImage *)previewImage;
#end
// ------- TextItemSource.m
#implementation TextItemSource
{
NSString *_string;
UIImage *_previewImage;
}
- (id)initWithString:(NSString *)string previewImage:(UIImage *)previewImage
{
self = [super init];
if (self) {
_string = [string copy];
_previewImage = previewImage;
}
return self;
}
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
return _string;
}
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
NSString *string = _string;
if ([activityType isEqual:UIActivityTypePostToTwitter]) {
#pragma mark TODO: do smarter thing :)
string = [_subject substringToIndex:140];
}
return string;
}
- (UIImage *)activityViewController:(UIActivityViewController *)activityViewController thumbnailImageForActivityType:(NSString *)activityType suggestedSize:(CGSize)size
{
// might want to scale image to fit suggestedSize
return _previewImage;
}
#end

Override UIActivityViewController default behaviour

In the Photos app on the iPhone, when you select the Mail sharing option, the photo animates into the modal view controller that slides up. How is it possible to modify the behaviour of the built-in UIActivities? For example, I'd like to be able to set the subject field of the mail composer.
Unfortunately, customizing the subject field of the UIActivityViewController mail composer is not working yet.
There is a documented and reported bug regarding trying to customize this discussed here:
iphone - How do I set recipients for UIActivityViewController in iOS 6?
If this were working, according to the documentation, you would be able to customize these mail composer fields:
UIActivityTypeMail:
The object posts the provided content to a new email message. When
using this service, you can provide NSString and UIImage objects and
NSURL objects pointing to local files as data for the activity items.
You may also specify NSURL objects whose contents use the mailto
scheme.
So using the mailto scheme, when it is working, you should be able to customize those fields like this:
NSString *text = #"My mail text";
NSURL *recipients = [NSURL URLWithString:#"mailto:foo#bar.com?subject=Here-is-a-Subject"];
NSArray *activityItems = #[text, recipients];
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
[self presentViewController:activityController animated:YES completion:nil];
If your looking for other ways to customize the UIActivityViewControllerthere is an excellent example project here:
https://github.com/russj/ios6ShareDemo
This is how I did it and it's working for me in iOS 7.
Create a class that conforms to the UIActivityItemSource protocol:
#interface CustomActivityItem : NSObject <UIActivityItemSource>
#end
In the implementation override the relevant methods:
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
return #"";
}
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType
{
if ([activityType isEqualToString:UIActivityTypeMail])
{
return #"Subject"
}
return nil;
}
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
if ([activityType isEqualToString:UIActivityTypeMail])
{
return #"body";
}
return nil;
}
Then present the activity view controller:
CustomActivityItem* activityItem = [[CustomActivityItem alloc] init];
UIActivityViewController* activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[activityItem]
applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:nil];

Resources