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.

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 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.See using Forms for more on creating a form.

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.

- (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];
}

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 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.

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.

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"];
}
}