Sharing:
Creating Services:
- Getting Started
- Understanding the share flow
- Creating Forms
- Using SHKItem
- Getting stored logins
- Using SHKRequest
Managing Services
How to Share
This documentation already assumes you've installed ShareKit. If you have not done that, I would recommend following the install instructions to familarize yourself with ShareKit.
As described by the install documentation, to launch ShareKit, you create an SHKItem to share, a SHKActionSheet with the item, and then display the SHKActionSheet to the user:
- (void)myButtonHandlerAction{
// Create the item to share (in this example, a url)
NSURL *url = [NSURL URLWithString:@"http://getsharekit.com"];
SHKItem *item = [SHKItem URL:url title:@"ShareKit is Awesome!"];
// Get the ShareKit action sheet
SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item];
// Display the action sheet
[actionSheet showFromToolbar:navigationController.toolbar];
}
SHKItem has four methods, one for each type of file that you want to share.
Sharing URLs
+ (SHKItem *)URL:(NSURL *)url title:(NSString *)title;
url - The URL you want to share
title - (optional nil) - The title of the URL
// Create the item to share (in this example, a url)
NSURL *url = [NSURL URLWithString:@"http://getsharekit.com"];
SHKItem *item = [SHKItem URL:url title:@"ShareKit is Awesome!"];
If you are sharing a page a user is viewing in a UIWebView, a category is provided to extract the page title from the page. Import "SHK.h" to the top of your class and call:
NSString *title = [myWebView pageTitle];
// which can be used like:
SHKItem *item = [SHKItem URL:myWebView.request.URL title:title];
Sharing Images
+ (SHKItem *)image:(UIImage *)image title:(NSString *)title;
image - The image you want to share
title - (optional nil) - The title of the image
// Example: Use an image in our resource bundle
UIImage *image = [UIImage imageNamed:@"sanFran.jpg"];
SHKItem *item = [SHKItem image:image title:@"Look at this picture!"];
Sharing Text
+ (SHKItem *)text:(NSString *)text;
text - The text you want to share
NSString *someText = @"This is a blurb of text I highlighted from a document.";
SHKItem *item = [SHKItem text:someText];
Sharing Files
+ (SHKItem *)file:(NSData *)data filename:(NSString *)filename mimeType:(NSString *)mimeType title:(NSString *)title;
data - the contents of the file you want to share
filename - the suggested filename (ex: myFile.doc)
mimeType - the mime-type of the file
title - the name of the file
NSData *myPDF = [NSData dataWithContentsOfFile:@"path/to/my/file.pdf"];
SHKItem *item = [SHKItem file:myPDF
filename:@"file.pdf"
mimeType:@"application/pdf"
title:@"A PDF file for you"];
Sharing with a Specific Service
If you create your own interface for ShareKit or have a reason to share directly with a specific service, it's just as easy as calling the actionsheet.
You simply create a SHKItem and then push the item to the service's class. Here is an example of sharing a URL with Read It Later:
#import "SHKReadItLater.h" //include the service's header at the top of your class
...
// Create the item to share (in this example, a url)
NSURL *url = [NSURL URLWithString:@"http://getsharekit.com"];
SHKItem *item = [SHKItem URL:url title:@"ShareKit is Awesome!"];
// Share the item
[SHKReadItLater shareItem:item];
Sharing Offline
If your app can be used without an internet connection, you should support offline sharing. Luckily, this means only adding one additional line of code.
Most ShareKit services support offline sharing. This means when a user shares something while they are disconnected, ShareKit will store it and wait to send until they are connected again.
You just need to tell ShareKit when to retry these offline items. A good time to do this is when the app is opened. Simply add this line when you want ShareKit to try resending the items:
[SHK flushOfflineQueue];
Creating New Services
Understanding the Share Flow
There are 3 phases a service class will respond to. Here is a quick overview of what happens when a user clicks a share button that is hooked up to ShareKit.
Step 1 : CanShare...?
The first thing ShareKit will do is gather a list of services that can respond to the item being shared. If for example, the user wants to share a URL, it will call +(BOOL)canShareURL on your service class to see if you accept URLs. If your service can share URLs, you should return YES.
// Other types to respond to:
+ (BOOL)canShareURL
+ (BOOL)canShareImage
+ (BOOL)canShareText
+ (BOOL)canShareFile
Step 2 : Authentication
After a user has selected which service to use, ShareKit looks to see if it has stored credentials for the service. If it does not, it attempts to authenticate the user before sharing. This step is different depending on the type of service you are creating (action, web, web w/ OAuth).
Authenticating Actions
Generally actions should not require authenticating. If they connect to a web service, you should use the web service template instead.
Authenticating Web Services
ShareKit will call -(NSArray *)authorizationFormFields on your class to get a login form to display to the user. You should return the fields required to log a user in to your service.
See using Forms for more on creating a form.
The form is then displayed to the user. Once they complete their information, they will hit 'Login'. This calls -(void)authorizationFormValidate:(SHKFormController *)form on your class.
In authorizationFormValidate, you will validate the form data and then send a request to your server to verify the provided credentials are correct. You are responsible for sending the request and handling and displaying errors (i.e. incorrect username and password).
Once the user's credentials have been verified, you'll save the form and ShareKit will continue on to the next step.
Authenticating Web Services with OAuth
If your service uses OAuth, most of the work is already done for you. ShareKit will use the provided token request, authorize, and access URLs along with the app's consumer and secret keys to do the complete OAuth roundtrip on its own.
Step 3 : Presenting an Edit Form
ShareKit will first check to see if the user has enabled auto-sharing for your service. Auto sharing allows the user to skip the share Edit Form dialog. For example, when a user shares with Delicious, they can edit the title, add tags, and set the privacy setting of the shared item. If a user wants to skip this step, they can toggle on auto-share and ShareKit will just immediately share the item the next time they use Delicious.
If your service has additional information that is required, you can disable this by responding NO to - (BOOL)canAutoShare
Next ShareKit calls -(NSArray *)shareFormFieldsForType:(SHKShareType)type to request a form to let the user edit the item they are sharing or provide additional details. If you do not require any other information, do not provide this method and the form will be skipped.
Step 4 : Sending the item
Finally, ShareKit will attempt to send the item by calling -(BOOL)send.
Here you should do whatever is necessary to send the item to your service or perform the required action.
At this point you'll likely need information about the shared item and access to the stored credentials for the user. See the following sections for retrieving both:
If the action is asynchronous and will not be completed by the time send returns (which is likely to be the case for all web services), you need to update ShareKit and tell it what is happening. There are five methods you can call on your own service class:
[self sendDidStart];
This notifies ShareKit that you have started sending the item. ShareKit will present an activity indicator to the user.
[self sendDidFinish];
This notifies ShareKit that the item was sent successfully. ShareKit will display a 'Saved!' message and close any open ShareKit views.
[self sendDidFailShouldRelogin];
If the send request fails because the user's credentials are no longer accurate, use this and ShareKit will attempt to reauthenticate the user (Step 2 above).
[self sendDidFailWithError:(NSError *)];
This notifies ShareKit that sending the item has failed. It will display an error to user.
[self sendDidCancel];
This tells ShareKit that the user cancelled the share. Most implementations will not call this.
Using Forms
There are two places where ShareKit will present a form to the user: when logging in and when allowing them to edit an item before it is shared.
ShareKit takes care of displaying and storing the data collected from the form. You simply need to tell it what questions to ask.
The two instances where ShareKit will request form fields from your service are:
(NSArray *)shareFormFieldsForType:(SHKShareType)type
(NSArray *)authorizationFormFields
Each method should return a NSArray of SHKFormFieldSetting objects.
A SHKFormFieldSetting is made up of:
- a label : The question being asked
- a key : The key by which you'll retrieve the data later (like a variable name)
- a type : The type of field, either SHKFormFieldTypeText, SHKFormFieldTypePassword, or SHKFormFieldTypeSwitch
- a starting value : If the field should be prefilled, provide a starting value. For SHKFormFieldTypeSwitch fields, this can be either SHKFormFieldSwitchOn or SHKFormFieldSwitchOff.
You create a SHKFormFieldSetting object with one line:
SHKFormFieldSettings *field =
[SHKFormFieldSettings label:@"My Label"
key:@"myKey"
type:SHKFormFieldTypeText
start:nil];
Some examples
Generally an authorization form will just ask for a username and password. That looks like:
- (NSArray *)authorizationFormFields{
return [NSArray arrayWithObjects:
[SHKFormFieldSettings label:@"Username"
key:@"username"
type:SHKFormFieldTypeText
start:nil],
[SHKFormFieldSettings label:@"Password"
key:@"password"
type:SHKFormFieldTypePassword
start:nil],
nil];
}
An edit share item form may ask for more details. Here is an example:
- (NSArray *)shareFormFieldsForType:(SHKShareType)type
{
return [NSArray arrayWithObjects:
// Let the user edit the item's title before sending.
// Use item.title as the starting value to prefill the existing title
// Use "title" as the key so when the form is saved, it overwrites the
// item's title property
[SHKFormFieldSettings label:@"Title"
key:@"title"
type:SHKFormFieldTypeText
start:item.title],
// If your service let's users make their items public, you may want
// to add an option to make the share public or private.
// Here we add a UISwitch to the form and save it to the item
// with the 'public' key. We also set the switch to start as OFF
// so by default the share is private
[SHKFormFieldSettings label:@"Public"
key:@"public"
type:SHKFormFieldTypeSwitch
start:SHKFormFieldSwitchOff],
nil];
}
Validating the data
You'll likely need to validate the data in the form before saving.
Instances where you'll need to do this are:
- (void)shareFormValidate:(SHKCustomFormController *)form
- (void)authorizationFormValidate:(SHKFormController *)form
When the form is being displayed and you have access to the SHKFormController object, you can access the form data with [theForm formValues]. This will return a NSDictionary of each field's 'key' value mapped to a key in the dictionary.
If the data looks good and can be saved, call [form saveForm]. On the authentication form, this will save the values to the keychain and for the share form, the values will be saved to the SHKItem. See the next section on retrieving this data.
Retrieving the data
To retrieve the data collected from a login form, see Getting stored logins.
To retrieve the data collected from a share/edit form, see Using SHKItem.
Accessing SHKItem
Everything in ShareKit revolves around SHKItem. It stores everything there is to know about something that is being shared. You should be familar with accessing the information stored in SHKItem so your service can use it correctly.
There are several built-in properties that you can find/store values in:
// This indicates what type of content is stored in the item.
SHKShareType shareType;
// Possible values:
// SHKShareTypeURL, SHKShareTypeImage, SHKShareTypeText, SHKShareTypeFile
// This is generally used for url sharing (SHKShareTypeURL)
NSURL *URL;
// This is generally used for image sharing (SHKShareTypeImage)
UIImage *image;
// These text related properties are used for all 4 types
NSString *title; // use for any title or subject type field
NSString *text; // use for any long text like a note, SHKShareTypeText uses this
NSString *tags; // use for tagging
// These are used for file sharing (SHKShareTypeFile)
NSData *data;
NSString *mimeType;
NSString *filename;
Setting and Storing Custom Values
Your service may have additional values that it needs to collect when sharing. You can set and retrieve custom variables from SHKItem. Custom values can only be NSStrings. This is so that they can be stored for offline use if your service supports offline sharing.
// Saving a custom value
[item setCustomValue:@"This is my value" forKey:@"myCustomKey"];
// Retrieving the value
NSString *value = [item customValueForKey:@myCustomKey"];
// value = @"This is my value"
Using with Forms
When using forms, setting any form key name to an item's property name will cause the item's property to be overwritten with that value when the form is saved.
If the form's key does not match a property, it will be saved as a custom value.
// A SHKFormFieldSetting mapped to the item's tags property:
[SHKFormFieldSettings label:@"Tags"
key:@"tags" // use of 'tags' here maps it to the item's tag property
type:SHKFormFieldTypeText
start:item.tags]; // display the current item.tags value in the form
// After the form is saved, the result can be retrieved by
item.tags
..
// A SHKFormFieldSetting mapped to an item's custom value:
[SHKFormFieldSettings label:@"Custom Question"
key:@"myCustomKey"
type:SHKFormFieldTypeText
start:nil];
// After the form is saved, the result can be retrieved by
NSString *value = [item customValueForKey:@"myCustomKey"];
..
// An example using a switch and the BOOL convenience method
[SHKFormFieldSettings label:@"Public"
key:@"myCustomKey"
type:SHKFormFieldTypeSwitch
start:nil];
// Can be retrieved by
BOOL isPublic = [item customBoolForSwitchKey:@"myCustomKey"];
Accessing Stored Logins
If your web service uses basic auth, you'll likely need to send the username and password along with the shared item. After a user has been authenticated, the credentials are stored and easily accessible.
// To retrieve a stored value:
// self = your service class
// In this example, let's retrieve the username and password:
NSString *username = [self getAuthValueForKey:@"username"];
NSString *password = [self getAuthValueForKey:@"password"];
// The keys used to retrieve the data are the same keys you used
// when defining your login form:
- (NSArray *)authorizationFormFields
{
return [NSArray arrayWithObjects:
[SHKFormFieldSettings label:@"Username"
key:@"username" <---
type:SHKFormFieldTypeText
start:nil],
[SHKFormFieldSettings label:@"Password"
key:@"password" <---
type:SHKFormFieldTypePassword
start:nil],
nil];
}
Logging Out / Removing Stored Logins
There are three methods to remove stored credentials:
// Remove credentials for all services
[SHK logoutOfAll];
// Remove credentials for a specific service
// Use the service's class name: ex SHKTwitter, SHKDelicious
[SHK logoutOfService:@"SHKReadItLater"];
// Remove credentials for a specific service (alternative method)
// call +logout on any sharer class
[SHKTwitter logout];
Using SHKRequest
You can use whatever methods you'd like to connect to your web service. If all you need is a way to send a few parameters to a specific URL and get the response, the SHKRequest object will help you get started quickly.
- (BOOL)send
{
// Set the parameters for the request
// Create a parameter string like you would for a GET request
NSString *params = [NSMutableString stringWithFormat:@"username=%@&password=%@",
SHKEncode([self authValueForKey:@"username"]),
SHKEncode([self authValueForKey:@"password"]) ];
// Other helpers:
// SHKEncode() takes a string and properly urlencodes it.
// SHKEncodeURL() takes a NSURL and properly urlencodes it into a string.
// Send request
NSURL *url = [NSURL URLWithString:@"http://api.example.com/share/"];
self.request = [[[SHKRequest alloc] initWithURL:url
params:params
delegate:self
isFinishedSelector:@selector(sendFinished:) // set your callback function
method:@"POST" // POST or GET
autostart:YES] autorelease];
}
// a callback (as set by isFinishedSelector above) - (void)sendFinished:(SHKRequest *)aRequest{
// If the request status code was 200, 'success' will be set to YES
if (aRequest.success)
{
// Do something with the result
NSString *bodyOfResponse = [aRequest getResult];
}
// If there is an error, handle it
else{
// SHKRequest has a few properties that can help find out what happened
// aRequest.response is the NSHTTPURLResponse of the request
// aRequest.response.statusCode is the HTTTP status code of the response
// [aRequest getResult] returns a NSString of the body of the response
// What was the status code?
int HTTPstatusCode = aRequest.response.statusCode; // 404? 401? 500?
// What was the value of some header value?
NSString *contentType = [aRequest.headers objectForKey:@"Content-Type"];
}
}