预计阅读本页时间:-
Chapter 7
Integrating Social Media
WHAT YOU LEARN IN THIS CHAPTER:
- Sending e-mails and text messages
- Posting to Twitter, Facebook, and Flicker
- Creating the same sharing experience as Apple apps
WROX.COM CODE DOWNLOADS FOR THIS CHAPTER
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
You can find the wrox.com code downloads for this chapter at www.wrox.com/go/begiosprogramming on the Download Code tab. The code is in the chapter 07 download and individually named according to the names throughout the chapter.
Social networking has become a ubiquitous term you hear everywhere today. It’s also a bit hard to define. For some, it can be as simple as sending an e-mail or a text message. For others, it means having a Twitter or Facebook account to share your thoughts and pictures with friends and family or to market your business. Then there are other services such as Flickr and YouTube or one of the hundreds of other similar services. What all these have in common is the ability to share things with groups of people using software and services.
Integrating with social networking services is a popular feature to add to iOS apps. It gives your app a built-in avenue for viral marketing. When users like a particular app, they’re more likely to tell their friends how great of an app it is. Allowing them to do this easily without needing to leave your app can help make your app a commercial success.
In the not-so-distant past, it was a daunting task to add social networking to an app. First, developers would need to choose which networks to support. Then they needed to learn the APIs and sometimes even register their apps with those services to add them. They would need to learn how to authenticate with the service and store the users’ credentials in their own apps, raising security concerns and giving hackers more places to steal passwords from. Yet developers went through all that trouble.
Sending e-mails was the first form of social networking Apple added in iOS 3. When iOS 5 was introduced, it included built-in support for sending messages to Twitter. iOS 6 added Facebook support, whereas iOS 7 added both Flickr and Vimeo. Instead of developers needing to know the networking details of each of these services, integration with these services was instead built in to iOS.
In this chapter you add the ability to share bands through e-mail and text messages, as well as through Facebook, Twitter, and Flickr.
SENDING E-MAILS AND TEXT MESSAGES
The most basic form of social networking is sending e-mails and text messages. Almost all users of iOS devices have an e-mail address configured on their device. Prior to iPhone OS 3, users could send e-mails only using the built-in Mail app. Apple began including the MessageUI.framework with the release of iPhone OS 3, enabling all third-party apps the capability to compose and send e-mails from within the app as well as setting the subject of the e-mail, the body, and the recipients.
Text messages are also a basic form of social networking. The first iPhone had text messaging through the Messages app; though iPod touches and iPads did not, because text messages were thought of more as part of your cell phone plan. That changed with the release of iMessages in iOS 5. iMessages enables anyone with an Apple account to send text messages to other Apple accounts for free. If you use an iPhone, you can also send text messages to people who do not have an Apple account but have a text-messaging plan. Both use the Messages app or the message composer while inside third-party apps.
Using the E-mail Composer
The capability to show the e-mail composer from within a third-party app was first introduced in iPhone OS 3 with the inclusion of the MessageUI.framework. A framework is best thought of as a DLL in Windows or a Jar file in Java. Some frameworks such as UIKit are automatically added to any new project you create using the project templates. Others need to be added before you can use them. The MessageUI.framework is one that needs to be added. You will learn how to do this in the following Try It Out. After it’s included in your project, you have access to the MFMailComposeViewController and MFMailComposeViewControllerDelegate.
The MFMailComposeViewController, like the UIImagePickerController, is a self-contained view. You don’t need to code your own user interface for writing e-mails nor do you need any special networking code to send them. Instead you create the MFMailComposeViewController, set whatever properties you want, such as the e-mail body and subject, and then present it within your app. To know when the user either sends the e-mail or taps the Cancel button, you need to register as the MFMailComposeViewController delegate and implement the mailComposeController:didFinishWithResult:error method of the MFMailComposeViewControllerDelegate protocol.
The features of the Bands app, as discussed in Chapter 1, “Building a Real World iOS App — Bands,” will eventually include searching for a band on the web, finding local record stores and searching for tracks of a band in iTunes. These are all activity options the users will initiate from the Band Details scene. Options in an iOS app are generally presented to the users with a UIActionSheet. In Chapter 6, “Integrating the Camera and Photo Library in iOS Apps,” you used a UIActionSheet to prompt the user to choose between using the camera or selecting an image from the photo library. The activity options will be presented in the same manner. The recommended way to do this is to add a UIBarButtonItem to the UINavigationItem with its Identifier set to Action. The icon for this type of UIBarButtonItem is a box with an arrow pointing up and out of it. The Bands app will implement this approach to show the activity options to users.
TRY IT OUT: Presenting the MFMailComposeViewController
- Select the Project in the Project Navigator.
- Select the General tab in the editor.
- In the Linked Frameworks and Libraries section, click the Add button.
- Search for and find the MessageUI.framework, and add it to the project.
- Select the WBABand.h file from the Project Navigator, and add the following method declaration to the interface:
- (NSString *)stringForMessaging;
- Select the WBABand.m file from the Project Navigator, and add the following method to the implementation:
- (NSString *)stringForMessaging
{
NSMutableString *messageString = [NSMutableString stringWithFormat:@"%@\n",
self.name];
if(self.notes.length > 0)
[messageString appendString:[NSString stringWithFormat:@"Notes: %@\n",
self.notes]];
else
[messageString appendString:@"Notes: \n"];
[messageString appendString:[NSString stringWithFormat:@"Rating: %d\n",
self.rating]];
if(self.touringStatus == WBATouringStatusOnTour)
[messageString appendString:@"Touring Status: On Tour\n"];
else if (self.touringStatus == WBATouringStatusOffTour)
[messageString appendString:@"Touring Status: Off Tour\n"];
else if (self.touringStatus == WBATouringStatusDisbanded)
[messageString appendString:@"Touring Status: Disbanded\n"];
if(self.haveSeenLive)
[messageString appendString:@"Have Seen Live: Yes"];
else
[messageString appendString:@"Have Seen Live: No"];
return messageString;
} - Select the WBABandDetailsViewController.h file from the Project Navigator.
- Add the following import to the class imports:
#import <MessageUI/MFMailComposeViewController.h>
- Add a new constant to the WBAActionSheetTag using the following code:
typedef enum {
WBAActionSheetTagDeleteBand,
WBAActionSheetTagDeleteBandImage,
WBAActionSheetTagChooseImagePickerSource,
WBAActionSheetTagActivity,
} WBAActionSheetTag; - Add a new enumeration using the following code:
typedef enum {
WBAActivityButtonIndexEmail,
} WBAActivityButtonIndex; - Add the following protocol to the interface:
@interface WBABandDetailsViewController : UIViewController <UITextFieldDelegate,
UITextViewDelegate, UIActionSheetDelegate, UIImagePickerControllerDelegate,
UINavigationControllerDelegate, MFMailComposeViewControllerDelegate> - Add the following IBAction to the interface:
- (IBAction)activityButtonTouched:(id)sender;
- Add the following method declaration to the interface:
- (void)emailBandInfo;
- Select the Main.storyboard from the Project Navigator.
- Add a new Bar Button Item from the Object library to the UINavigationItem of the Band Details scene, and set its identifier to Action, as shown in Figure 7-1.
FIGURE 7-1
- Connect the button to the activityButtonTouched: method.
- Select the WBABandDetailsViewController.m file from the Project Navigator.
- Add the following methods to the implementation:
- (IBAction)activityButtonTouched:(id)sender
{
UIActionSheet *activityActionSheet = [[UIActionSheet alloc]
initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil otherButtonTitles:@"Mail", @"Message", nil];
activityActionSheet.tag = WBAActionSheetTagActivity;
[activityActionSheet showInView:self.view];
}
- (void)emailBandInfo
{
MFMailComposeViewController *mailComposeViewController =
[[MFMailComposeViewController alloc] init];
mailComposeViewController.mailComposeDelegate = self;
[mailComposeViewController setSubject:self.bandObject.name];
[mailComposeViewController setMessageBody:
[self.bandObject stringForMessaging] isHTML:NO];
if(self.bandObject.bandImage)
[mailComposeViewController addAttachmentData:
UIImagePNGRepresentation(self.bandObject.bandImage)
mimeType:@"image/png" fileName:@"bandImage"];
[self presentViewController:mailComposeViewController
animated:YES completion:nil];
}
- (void)mailComposeController:
(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
[controller dismissViewControllerAnimated:YES completion:nil];
if(error)
{
UIAlertView *emailErrorAlertView = [[UIAlertView alloc]
initWithTitle:@"Error" message:error.localizedDescription delegate:nil
cancelButtonTitle:@"OK" otherButtonTitles:nil];
[emailErrorAlertView show];
}
} - Modify the activitySheet:clickedButtonAtIndex: method with the following code:
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(actionSheet.tag == WBAActionSheetTagActivity)
{
if(buttonIndex == WBAActivityButtonIndexEmail)
{
[self emailBandInfo];
}
}
else if(actionSheet.tag == WBAActionSheetTagChooseImagePickerSource)
{
if(buttonIndex == WBAImagePickerSourceCamera)
{
[self presentCameraImagePicker];
}
else if (buttonIndex == WBAImagePickerSourcePhotoLibrary)
{
[self presentPhotoLibraryImagePicker];
}
}
else if(actionSheet.tag == WBAActionSheetTagDeleteBandImage)
{
if(buttonIndex == actionSheet.destructiveButtonIndex)
{
self.bandObject.bandImage = nil;
self.bandImageView.image = nil;
self.tapToSetLabel.hidden = NO;
}
}
else if (actionSheet.tag == WBAActionSheetTagDeleteBand)
{
if(actionSheet.destructiveButtonIndex == buttonIndex)
{
self.bandObject = nil;
self.saveBand = NO;
if(self.navigationController)
[self.navigationController popViewControllerAnimated:YES];
else
[self dismissViewControllerAnimated:YES completion:nil];
}
}
} - Run the code in the iPhone 4-inch simulator. When selecting the Email button, you see the MFMailComposeViewController screen prefilled with the band message string and band image, as shown in Figure 7-2.
FIGURE 7-2
How It Works
You started by adding the MessageUI.framework to the project using the General settings editor and the Linked Frameworks and Libraries section. This tells the compiler to include the framework when building the project. Next, you implemented a helper method in the WBABand class that returns a string representing all the properties of the band.
In the WBABandDetailsViewController header you imported the MFMessageComposeViewController.h file. Next you added a new WBAActionSheetTagActivity value to the WBAActionSheetTag enumeration to be used with the activity options UIActionSheet. You also added a new enumeration named WBAActivityButtonIndex with a WBAActivityButtonIndexEmail constant to keep track of the activity option button indexes in the UIActionSheet. You then declared that the WBABandDetailsViewController implements the MFMessageComposeViewControllerDelegate. You also declared a new IBAction named actionButtonTouched: and an emailBandInfo method.
In the Storyboard, you added a new UIBarButtonItem to the UINavigationItem of the Band Details scene and set its identity to Action. The Action identifier uses the standard action icon, which signals to the user that tapping it performs some sort of action on the data in the scene. You then connected it to the actionButtonTapped: method you previously declared in the WBABandDetailsViewController interface.
Next, you modified code in the WBABandDetailsViewController implementation. The actionButtonTapped: method creates a new UIActionSheet with an e-mail option button and its tag set to the new WBAActionSheetTagActivity constant. In the actionSheet:clickedButtonAtIndex: method, you look for this tag then check to see if the buttonIndex is equal to the new WBAActivityButtonIndexEmail. If it is, the code calls the emailBandInfo method.
The emailBandInfo method first initializes a new MFMailComposeViewController and sets its delegate to the WBABandDetailsViewController using self. Next, it sets the subject of the e-mail to the band’s name using the setSubject: method. You set the e-mail body using the setMessageBody:isHTML: method using the stringForMessaging helper method of the bandObject. Because the string is not HTML, you pass in NO for the isHTML argument. If the bandObject has the bandImage property set, that gets added to the e-mail using the addAttachmentData:mimeType:filename method. The bandImage property is a UIImage, which needs to be serialized to NSData to be attached to an e-mail. You use the UIImagePNGRepresentation function to do this. The mimeType is set to “image/png” and the fileName is set to “bandImage.”
You present the MFMailComposeViewController using the presentViewController:animated:completion: method. When the user sends the e-mail or taps the Cancel button, the mailComposeControllerDidFinish:withResult:error: method of the MFMailComposeViewControllerDelegate protocol gets called. In its implementation you dismiss the MFMailComposeViewController using the dismissViewControllerAnimated:completion: method and then check to see if the error argument is set. If it is, you notify the users that an error occurred using a UIAlertView.
NOTE The MFMailComposeViewController does allow you to send an e-mail with HTML formatting by supplying an HTML string and setting the isHTML flag to true.
Using the Message Composer
Sending text messages and iMessages is similar to sending e-mails. Instead of using the MFMailComposeViewController, you use the MFMessageComposeViewController and MFMessageComposeViewControllerDelegate. Text and iMessages also support attaching the band image to the message, but it’s done a bit differently than with e-mail. Instead of setting the mime type of the image, you need to use its Universal Type Identifier. These identifiers were created by Apple and are included in the MobileCoreServices.framework. This is another framework that is not included in the Project templates, so you need to add it manually, the same as the MessageUI.framework.
NOTE The ability to attach images in text and iMessages in code was introduced in iOS 7. Users could attach images to text messages and iMessages through the Photo app, but there was no way to add them in a third-party app. If your app needs to support iOS 6, you need to check which version of iOS the device is running before attempting to add the image. Failing to do so can cause your app to crash in iOS 6.
TRY IT OUT: Presenting the MFMessageComposeViewController
- Add the MobileCoreServices.framework to the project following the same steps from the previous section.
- Select the WBABandDetailsViewController.h file from the Project Navigator.
- Add the following to the imports:
#import <MessageUI/MFMessageComposeViewController.h>
- Add the following to the protocols of the interface:
@interface WBABandDetailsViewController : UIViewController <UITextFieldDelegate,
UITextViewDelegate, UIActionSheetDelegate, UIImagePickerControllerDelegate,
UINavigationControllerDelegate, MFMailComposeViewControllerDelegate,
MFMessageComposeViewControllerDelegate> - Add the following method declaration to the interface:
- (void)messageBandInfo;
- Add the following value to the WBAActivityButtonIndex enumeration:
typedef enum {
WBAActivityButtonIndexEmail,
WBAActivityButtonIndexShare,
} WBAActivityButtonIndex; - Select the WBABandDetailsViewController.m file from the Project Navigator.
- Add the following methods to the implementation:
- (void)messageBandInfo
{
MFMessageComposeViewController *messageComposeViewController =
[[MFMessageComposeViewController alloc] init];
messageComposeViewController.messageComposeDelegate = self;
[messageComposeViewController setSubject:self.bandObject.name];
[messageComposeViewController setBody:
[self.bandObject stringForMessaging]];
if(self.bandObject.bandImage)
[messageComposeViewController addAttachmentData:
UIImagePNGRepresentation(self.bandObject.bandImage)
typeIdentifier:(NSString *)kUTTypePNG filename:@"bandImage.png"];
[self presentViewController:messageComposeViewController
animated:YES completion:nil];
}
- (void)messageComposeViewController:
(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result
{
[controller dismissViewControllerAnimated:YES completion:nil];
if(result == MessageComposeResultFailed)
{
UIAlertView *emailErrorAlertView = [[UIAlertView alloc]
initWithTitle:@"Error" message:@"The message failed to send" delegate:nil
cancelButtonTitle:@"OK" otherButtonTitles:nil];
[emailErrorAlertView show];
}
} - Modify the activityButtonTouched: method with the following code:
- (IBAction)activityButtonTouched:(id)sender
{
UIActionSheet *activityActionSheet = nil;
if([MFMessageComposeViewController canSendText])
activityActionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil
otherButtonTitles:@"Mail", @"Message", nil];
else
activityActionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil
otherButtonTitles:@"Mail", nil];
activityActionSheet.tag = WBAActionSheetTagActivity;
[activityActionSheet showInView:self.view];
} - Modify the activitySheet:clickedButtonAtIndex: with the following code:
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(actionSheet.tag == WBAActionSheetTagActivity)
{
if(buttonIndex == WBAActivityButtonIndexEmail)
{
[self emailBandInfo];
}
else if (buttonIndex == WBAActivityButtonIndexMessage)
{
[self messageBandInfo];
}
}
else if(actionSheet.tag == WBAActionSheetTagChooseImagePickerSource)
{
if(buttonIndex == WBAImagePickerSourceCamera)
{
[self presentCameraImagePicker];
}
else if (buttonIndex == WBAImagePickerSourcePhotoLibrary)
{
[self presentPhotoLibraryImagePicker];
}
}
else if(actionSheet.tag == WBAActionSheetTagDeleteBandImage)
{
if(buttonIndex == actionSheet.destructiveButtonIndex)
{
self.bandObject.bandImage = nil;
self.bandImageView.image = nil;
self.tapToSetLabel.hidden = NO;
}
}
else if (actionSheet.tag == WBAActionSheetTagDeleteBand)
{
if(actionSheet.destructiveButtonIndex == buttonIndex)
{
self.bandObject = nil;
self.saveBand = NO;
if(self.navigationController)
[self.navigationController popViewControllerAnimated:YES];
else
[self dismissViewControllerAnimated:YES completion:nil];
}
}
} - Run the app on a test device that has text messaging available. When you tap the Messages option, you can see the text message compose screen.
How It Works
Before implementing the MFMailComposeViewController you first added the MobileCoreServices.framework to the Bands project. This framework is required in order to use the Universal Type Identifier constants. You also added the WBAActivityButtonIndexShare constant to the WBAActivityButtonIndex enumeration to use when presenting the e-mail and messaging options to users.
In the implementation you first imported the MobileCoreServices.h file, which allows you to use the Universal Type Identifier constants in the code. Next you modified the activityButtonTouched: method to use the canSendText static method of the MFMessageComposeViewController class to make sure the users device is able to send text messages or iMessages. If it returns true, you then present the UIActivitySheet with both the Mail and Message options. If not you only show the Mail option. If you attempt to use the MFMessageComposeViewController on a device that does not support it your app will crash, so this check is very important.
The method you declared for sending messages, messageBandInfo, is almost identical to the emailBandInfo method you added in the previous section. Instead of using the MFMailComposeViewController, you initialized and presented the MFMessageComposeViewController. You set the subject again using setSubject: and the body using setBody:. The body of a text message or iMessage cannot be HTML, so the isHTML argument is not present. The biggest difference is attaching the bandImage to the message. Instead of using a mime type string, you used the kUTTypePNG Universal Type Identifier constant.
You also implemented the messageComposeViewControllerDidFinishwithResult: method of the MFMessageComposeViewControllerDelegate protocol. In its implementation you dismiss the message MFMessageComposeViewController using the dismissViewControllerAnimated:completion: method and then check the result argument. If it is equal to the MessageComposeResultFailed constant, you show an error to users using a UIAlertView.
NOTE The iOS simulator does not support text messaging or iMessages. You can use it to test your code and make sure you are using the canSendText method before attempting to present the MFMessageComposeViewController. You will need to use a physical device to test sending a text message or iMessage.
SIMPLIFYING SOCIAL NETWORK INTEGRATION
Apple began integrating social networking directly into iOS in iOS 5. They also gave developers access to this integration. Using the built-in integration was a big help to developers, because they no longer needed to learn the various APIs of different social networking services. Actually, you don’t need to add any networking code. The integration is also great for users, because they can sign into those social networks in one place and have access to them in any app that includes the integration. Apple also gave developers a new view controller so that users would have a common experience in not only the Apple apps, but also in any third-party apps that implement it.
Introducing the Activity View Controller
The UIActivityViewController was first introduced in iOS 6. By using it, developers can give their users a common experience not only with social networking integration, but also with other activities, such as e-mailing, messaging, printing, and AirDrop to share between iOS devices. Adding it into your app is similar to the UIImagePickerController, MFMailComposeViewController, and MFMessageComposeViewController, but you don’t need to add new frameworks to your project. The biggest benefit is no longer needing to know what capabilities are available on the device. You also don’t need to know the Universal Type Identifiers for the data in your apps. Instead you simply pass in an array of objects you would like to share, and the system figures out what activities can be performed on them.
In the Bands app you can use the UIActivityController to replace the e-mail and message code you added previously in this chapter. You can also use it to add integration with social networking services.
TRY IT OUT: Presenting the UIActivityViewController
- Select the WBABandDetailsViewController.h file from the Project Navigator, and add the following method declaration to the interface:
- (void)shareBandInfo;
- Modify the WBAActivityButtonIndex enumeration with the following code:
typedef enum {
// WBAActivityButtonIndexEmail,
// WBAActivityButtonIndexMessage,
WBAActivityButtonIndexShare,
} WBAActivityButtonIndex; - Select the WBABandDetailsViewController.m file from the Project Navigator.
- Modify the activityButtonTouched: method with the following code:
- (IBAction)activityButtonTouched:(id)sender
{
UIActionSheet *activityActionSheet = nil;
/*
if([MFMessageComposeViewController canSendText])
activityActionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil
otherButtonTitles:@"Mail", @"Message", nil];
else
activityActionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil
otherButtonTitles:@"Mail", nil];
*/
activityActionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil
otherButtonTitles:@"Share", nil];
activityActionSheet.tag = WBAActionSheetTagActivity;
[activityActionSheet showInView:self.view];
} - Modify the actionSheet:clickedButtonAtIndex: with the following code:
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(actionSheet.tag == WBAActionSheetTagActivity)
{
/*
if(buttonIndex == WBAActivityButtonIndexEmail)
{
[self emailBandInfo];
}
else if (buttonIndex !=actionSheet.cancelButtonIndex &&
buttonIndex == messageActivityButtonIndex)
{
[self messageBandInfo];
}
*/
if(buttonIndex == shareActivityButtonIndex)
{
[self shareBandInfo];
}
}
else if(actionSheet.tag == WBAActionSheetTagChooseImagePickerSource)
{
if(buttonIndex == WBAImagePickerSourceCamera)
{
[self presentCameraImagePicker];
}
else if (buttonIndex == WBAImagePickerSourcePhotoLibrary)
{
[self presentPhotoLibraryImagePicker];
}
}
else if(actionSheet.tag == WBAActionSheetTagDeleteBandImage)
{
if(buttonIndex == actionSheet.destructiveButtonIndex)
{
self.bandObject.bandImage = nil;
self.bandImageView.image = nil;
self.tapToSetLabel.hidden = NO;
}
}
else if (actionSheet.tag == WBAActionSheetTagDeleteBand)
{
if(actionSheet.destructiveButtonIndex == buttonIndex)
{
self.bandObject = nil;
self.saveBand = NO;
if(self.navigationController)
[self.navigationController popViewControllerAnimated:YES];
else
[self dismissViewControllerAnimated:YES completion:nil];
}
}
} - Add the following method to the implementation:
- (void)shareBandInfo
{
NSArray *activityItems = [NSArray arrayWithObjects:
[self.bandObject stringForMessaging], self.bandObject.bandImage, nil];
UIActivityViewController *activityViewController =
[[UIActivityViewController alloc]initWithActivityItems:activityItems
applicationActivities:nil];
[activityViewController setValue:self.bandObject.name forKey:@"subject"];
[self presentViewController:activityViewController
animated:YES completion:nil];
} - Run the app in the iPhone 4-inch simulator. When you tap the Share option, you now see the Activity View Controller, as shown in Figure 7-3.
FIGURE 7-3
- Tap the Mail button. You should see the e-mail compose view with the subject and e-mail body set.
How It Works
The first thing you did was declare a new shareBandInfo method in the WBABandDetailsViewController interface. You then modified the WBAActivityButtonIndex enumeration commenting out the WBAActivityButtonIndexEmail and WBAActivityButtonIndexMessage constants while adding WBAActivityButtonIndexShare. The UIActivityViewController has options for both email and messaging, so you will no longer present those options separately in the UIActionSheet. With those buttons no longer being shown, you need to keep the WBAActivityButtonIndex enumeration order the same as the options you will be displaying.
In the implementation you changed the activityButtonTouched: method to show a UIActionSheet with just a single “Share” button. In the actionSheet:didClickButtonAtIndex: method you commented out the code that checks for the WBAActivityButtonIndexEmail and WBAActivityButtonIndexMessage and replaced it with code to compare the buttonIndex with the WBAActivityButtonIndexShare constant. If true, the code calls the shareBandInfo method.
In the shareBandInfo method you created an NSArray with its first object being the NSString returned from the stringForMessaging method of the bandObject and its second being the bandImage. This is a great example of adding different objects to an NSArray. Because both the NSString class and UIImage class inherit from NSObject, they can both be added to the same NSArray.
In this implementation, you do not need to check whether the image is set, because the UIActivityViewController can figure it out for you. You initialize the UIActivityViewController using the initWithActivityItems:applicationActivities: method. For the activityItems argument you pass in the NSArray you created with the band information. You set the applicationActivities argument to nil. You could create your own supported activities in your app and pass them in using that argument for display in the UIActivityViewController, but the Bands app does not use this feature.
If the users select the Mail or Message options you still want the subject to be set. You do this by calling the setValue:forKey: method, with the value being the name property of the bandObject and the key being subject. Finally you present the UIActivityViewController using the presentViewController:animated:completion: method.
The UIActivityViewController does not have a UIActivityViewControllerDelegate. It will dismiss any other UIViewControllers that may be shown depending on what option the user selects and return to your app when they have either completed the activity or canceled.
Learning About Twitter Integration
The first social networking service Apple integrated was Twitter with the release of iOS 5. Twitter is a microblogging service that enables its users to share text, links, and images to their timelines. They can also follow other users and see posts that they can reply to, favorite, or “retweet” on their own timelines.
Users can sign into their Twitter account or create a new one in the Settings app. The system then downloads the user’s followers list and attempts to match e-mail addresses associated with Twitter users to e-mail addresses in the user’s Contacts. If a match is found, the system adds the Twitter handle to the contact. The Twitter app integration enables apps only to post new messages on the user’s timeline. To use all the features of the services, users need to download the Twitter app. The setup screen has a button to download the app, so users don’t need to search the app store.
TRY IT OUT: Sending Messages to Twitter
- Open the Settings app on the iPhone 4-inch simulator, and select Twitter.
- Enter your Twitter credentials or create a new account.
- Run the Bands app in the simulator. Now when you select the Share option, the UIActivityViewController has Twitter as an option, as shown in Figure 7-4.
FIGURE 7-4
- Selecting Twitter allows you to post the band info and band image to Twitter while staying in the Bands app, as shown in Figure 7-5.
FIGURE 7-5
How It Works
The first thing you did was to go into the Settings app and either entered your Twitter credentials or created a new account. Back in the Bands app, the UIActivityViewController now has a Twitter option, which, if selected, enables you to compose a new message and post it to Twitter without leaving the app.
Learning About Facebook Integration
Facebook is the most popular social networking service in the world. Its users can post messages, pictures, links, and videos to their walls as well as see what other users with whom they are friends with have posted. Users can also create events or RSVP to events posted by their friends or groups of which they are members.
Apple integrated Facebook in iOS 6. Users can sign in or create a new account in the Settings app, the same as with Twitter. When the user’s account is added, the system downloads their friends and adds them to the Contacts app. It also downloads any events and adds them to the Calendar app. The in-app integration is more complex than with Twitter. Apps can request access to the user’s Facebook profile with info such as the user’s birthday, e-mail address, and other information the user has made public on Facebook. Apps can also request the users’ list of Facebook friends. When an app attempts to access this information, the user is prompted and must explicitly grant access. Facebook has had privacy issues in the past, making some users wary of letting third-party apps access their profile and friends lists, so the Bands app will not request this information. Instead users can post band info only to their walls.
TRY IT OUT: Sending Messages to Facebook
- Go to the home screen in the iPhone 4-inch simulator.
- Open the settings app and select Facebook.
- Enter your Facebook account information or create a new account, and sign into Facebook.
- Run the Bands app in the simulator. Now when you select the Share option, the UIActivityViewController has Facebook as an option.
- Selecting Facebook allows you to post the band info and band picture to Facebook while staying in the Bands app, as shown in Figure 7-6.
FIGURE 7-6
How It Works
The integration with Facebook in the Bands app is almost identical to the Twitter integration. If users select the Facebook option in the UIActivityViewController, they can post the band info string and band image to their Facebook walls from within the Bands app. They also have can add their location and designate which friends on Facebook can see the post.
Learning About Flickr Integration
Flickr is a social networking service from Yahoo built around sharing pictures. Users post pictures to their photo streams, which can be public for everyone to see or visible only to their contacts. Contacts or other users can then comment on pictures.
Flickr integration was added with iOS 7. The user can connect to their Flickr account by signing in with their Yahoo account in the Settings app. They can then share Band images by selecting Flickr in the Activity View. As you see in the following Try It Out, the band image must be set for the Flickr option to be shown.
TRY IT OUT: Sending a Picture to Flickr
- Open the Settings app on the iPhone 4-inch simulator, and select Flickr.
- Enter your Flickr credentials or create a new account.
- Run the Bands app in the iPhone 4-inch simulator.
- Select a Band that does not have a band image set. When you select the Share option, Flickr will NOT be an available option.
- Select a Band that does have a band image set. When you select the Share option, Flickr will now be available.
How It Works
Flickr integration works the same as Facebook and Twitter integration. After the user connect the account in the Settings app, the UIActivityViewController will have the Flickr option if the bandImage property of the bandObject is set. They then can post Band images to their Flickr photo stream.
NOTE This chapter covered how to post a new message or status to the social networking services integrated into iOS using the UIActivityViewController. The iOS SDK also includes the SLRequest class, which can be used to send requests directly to social networking services. This approach is for more advanced iOS developers, so it is not covered in this book. You can learn more about SLRequest in the iOS Developer Library at https://developer.apple.com/library/iOs/documentation/Social/Reference/SLRequest_Class/.
Limiting Sharing Options
Using the Activity View Controller does simplify your code, but it also presents users with many options for sharing. Some of those options may not make sense for your app or your audience. The UIActivityViewController has a setExcludedActivityTypes: method you can call with an NSArray of activity type constants you don’t want presented. Table 7-1 lists the built-in activity type constants.
ACTIVITY TYPE DESCRIPTION
UIActivityTypePostToFacebook Enables posting strings, pictures, videos, and URLs to the user’s Facebook wall
UIActivityTypePostToTwitter Enables posting strings, pictures, videos, and URLs to the user’s Twitter timeline
UIActivityTypePostToWeibo Enables posting strings, pictures, videos, and URLs to the Chinese microblogging site Weibo
UIActivityTypeMessage Enables sending strings, pictures, videos, and URLs via text message or iMessage.
UIActivityTypeMail Enables sending strings, pictures, and URLs via e-mail
UIActivityTypePrint Enables printing images
UIActivityTypeCopyToPasteboard Enables copying strings, images, and URLs to the pasteboard
UIActivityTypeAssignToContact Enables assigning an image to a contact
UIActivityTypeSaveToCameraRoll Enables saving an image or a video (using its URL) to the camera roll
UIActivityTypeAddToReadingList Enables adding a URL to the reading list
UIActivityTypePostToFlickr Enables posting an image to Flickr
UIActivityTypePostToVimeo Enables posting a video to Vimeo
UIActivityTypePostToTencentWeibo Enables posting strings, images, videos, and URLs to the Chinese microblogging site Weibo
UIActivityTypeAirDrop Enables sharing strings, images, videos, and URLs via AirDrop
TABLE 7-1: Activity Types
TRY IT OUT: Removing the Assign to Contact Option
- Select the WBABandDetailsViewController.m file from the Project Navigator.
- Modify the shareBandInfo with the following code:
- (void)shareBandInfo
{
NSArray *activityItems = [NSArray arrayWithObjects:
[self.bandObject stringForMessaging], self.bandObject.bandImage, nil];
UIActivityViewController *activityViewController =
[[UIActivityViewController alloc]initWithActivityItems:activityItems
applicationActivities:nil];
[activityViewController setValue:self.bandObject.name forKey:@"subject"];
NSArray *excludedActivityOptions = [NSArray arrayWithObjects:
UIActivityTypeAssignToContact, nil];
[activityViewController setExcludedActivityTypes:excludedActivityOptions];
[self presentViewController:activityViewController
animated:YES completion:nil];
} - Run the app in the iPhone 4-inch simulator. When you select the Share option, you no longer see the Assign to Contact option in the UIActivityViewController.
How It Works
The code to remove an activity from the UIActivityViewController is pretty simple. You first create an NSArray with the UIActivityTypeAssignToContact constant. You can add as many constants from Table 7-1 as you would like in this NSArray. You then use the NSArray with the setExcludedActivityTypes: method of the UIActivityViewController.
SUMMARY
Social networking can be a valuable feature to add to your apps. From simple e-mails to posting to Twitter and Facebook, it gives your users a way to tell their friends, family, and coworkers about your app. Apple has built integration with Facebook, Twitter, Flickr, and Vimeo directly into iOS and gives you a simple way to add them to your app using the UIActivityViewController. The Bands app now has the capability to share bands via e-mail or text message and Twitter, Facebook, and Flickr.
EXERCISES
- How do you add a new framework to an Xcode project?
- What framework needs to be added to a project in order to use the MFMailComposeViewController?
- What additional framework needs to be added to a project to send text messages using the MFMessageComposeViewController and why?
- What method should you call before showing the MFMessageComposeViewController and why?
- What social networks are integrated with iOS?
- Where does a user sign into their social networking accounts in iOS?
- How can you keep users of the Bands app from sharing band images on Flickr using the UIActivityViewController?
WHAT YOU LEARNED IN THIS CHAPTER
TOPIC KEY CONCEPTS
Sending E-mails Within an App The iOS SDK includes the MFMailComposeViewController and MFMailComposeViewControllerDelegate, which you can add to your app to give your users the ability to send e-mails. You can set the subject, set the e-mail body, and add attachments with just a few lines of code.
Sending Text Messages and iMessages with Images Similar to the MFMailComposeViewController is the MFMessageComposeViewController and MFMessageComposeViewControllerDelegate, which you can add to your app to send text messages and iMessages. With the release of iOS 7 you can also add attachments to messages similar to e-mail.
Adding the Same Sharing Experience Found in Apple apps Apps from Apple all have the same user experience to send emails or iMessages as well as using AirDrop, copying to the pasteboard, and printing. By using the UIActivityViewController you can add the same experience to your app.
Integrating with Social Networking Services Apple has been integrating with a handful of social networking services starting with Twitter in iOS 5, then adding Facebook, Flickr, and Vimeo. Users can sign into their accounts in the Settings app giving any third-party app using the UIActivityViewController the ability to send messages and status updates to these services without needing to add any additional code.