All code is licensed under the MIT-License.
- Before continuing, familiarize yourself with the ShareFile API and it's methodology.
- Please make sure you are running XCode version 7.2+
- If using XCode 11, an unofficial fork that adds support can be found here: https://github.com/FabienLydoire/ShareFile-ObjectiveC/tree/Fix-for-Xcode-11
Example functions demonstrated: authenticate, upload, download, and create share links.
Once you configure credentials in "Misc/ShareFileSDKSampleCred.plist", building the app will:
- Authenticate using the Password Authentication method as described below.
- Create a folder at the root level of your ShareFile account called "Sample Folder".
- Upload "Misc/Sample.png" to that folder.
- Download "Sample.png".
- Display the image in a UIImageView.
- Send a share notification to
shareEmail
as configured in "Misc/ShareFileSDKSampleCred.plist". - Provide a share link directly in the console.
applicationControlPlane
- Describes the domain that the ShareFile account is available on.- For example:
sharefile.com
,securevdr.com
,sharefile.eu
, etc.
- For example:
authorizationUrl
- The initial url that should be visited to being web authentication.client_id
- The identifier that is uniquely identifies an OAuth client consumer.client_secret
- This is a shared secret that is required to exchange anOAuthAuthorizationCode
for anOAuthToken
.completionUri
- Alias forredirectUri
. Used primarily inSFAOAuth2AuthenticationHelper
.OAuthAuthorizationCode
- One-time use code that is returned as part of an oauthcode
grant request. We provide a class with the specific properties for this type of response.OAuthToken
- Used to authenticate with ShareFile, specifically using AccessToken - however, this is taken care of for you by the SDK.redirectUri
- Resource that can be used to track when authentication is complete. Generally, this resource is controlled by the OAuth client consumer.state
- Token created by the OAuth consumer to associate an authorization request with an authorization response.
- Authentication with ShareFile v3 API makes use of OAuth 2.0 protocol.
- Some helper methods and classes are provided to make authentication easier for consumers.
- Once successfully authenticated, an instance of ShareFileClient
sfaClient
will be available to execute queries and tasks.
If you use your own mechanism for tracking when authentication is complete (based on redirectUri
), it is still advisable to use OAuth2AuthenticationHelper
to translate the Url
to id<SFAOAuthResponse>
.
NSURL *redirectUrl = [NSURL URLWithString:@"https://secure.sharefile.com/oauth/oauthcomplete.aspx"];
// Recommended this value is held on to to verify the authentication response.
NSString *state = [[NSUUID UUID] UUIDString];
SFAClient *sfaClient = [[SFAClient alloc] initWithBaseUrl:@"https://secure.sf-api.com/sf/v3/" andConfiguration:nil];
SFAOAuthService *oauthService = [[SFAOAuthService alloc] initWithSFAClient:sfaClient clientId:@"<client_id>" clientSecret:@"<client_secret>"];
[oauthService authorizationUrlForDomain:@"<domain>" responseType:@"code" clientId:@"<client_Id>"
redirectUrl:redirectUrl.absoluteString state:state additionalQueryParams:nil subdomain:nil];
Open up a web view or web browser and use authorizationUrl
to load the page. To assist in tracking when authentication has completed,
create an instance of SFAOAuth2AuthenticationHelper
passing redirectUrl
to initWithUrl:
.
In the case you're using a web browser, you will need to register a custom URL Scheme for your application, so that the browser re-opens your application on redirection. Then, in your AppDelegate’s methods, fetch the URL and follow the process below. Apple's iOS library describes how to register and use custom URL Schemes.
SFAOAuth2AuthenticationHelper *authenticationHelper = [[SFAOAuth2AuthenticationHelper alloc] initWithUrl:redirectUrl];
In UIWebviewDelegate
for navigation event or application launching, check the navigationUrl
that is being loaded as follows:
NSURL *navigationUrl = [NSURL URLWithString:@""];
id<SFAOAuthResponse> oauthResponse = [authenticationHelper isComplete:navigationUrl];
if (oauthResponse)
{
if ([oauthResponse isKindOfClass:[SFAOAuthError class]])
{
// handle error
}
if ([oauthResponse isKindOfClass:[SFAOAuthAuthorizationCode class]])
{
// exchange authorization code for OAuthToken
}
}
To exchange an OAuthAuthorizationCode
for an OAuthToken
:
SFApiQuery *query = [oauthService tokenQueryFromAuthorizationCode:authorizationCode];
[sfaClient executeQueryAsync:query
callbackQueue:nil
completionCallback:^(id returnValue, SFAError *error, NSDictionary *additionalInfo)
{
if (error)
{
// handle error
}
else if ([returnValue isKindOfClass:[SFAOAuthToken class]])
{
SFAOAuthToken *token = (SFAOAuthToken *)returnValue;
[sfaClient addOAuthToken:token];
sfaClient.baseUrl = [token getUrl];
}
}];
In order to complete this authentication you'll need a username
, password
, subdomain
, and applicationControlPlane
.
SFAClient *sfaClient = [[SFAClient alloc] initWithBaseUrl:@"https://secure.sf-api.com/sf/v3/" andConfiguration:nil];
SFAOAuthService *oauthService = [[SFAOAuthService alloc] initWithSFAClient:sfaClient clientId:@"<client_id>" clientSecret:@"<client_secret>"];
SFApiQuery *query = [oauthService passwordGrantRequestQueryForUsername:@"<email>" password:@"<password>"
subdomain:@"<subdomain>" applicationControlPlane:@"<applicationControlPlane>"];
[sfaClient executeQueryAsync:query
callbackQueue:nil
completionCallback:^(id returnValue, SFAError *error, NSDictionary *additionalInfo)
{
if (error)
{
//handle error
}
else if ([returnValue isKindOfClass:[SFAOAuthToken class]])
{
SFAOAuthToken *token = (SFAOAuthToken *)returnValue;
[sfaClient addOAuthToken:token];
sfaClient.baseUrl = [token getUrl];
}
}];
This authentication method assumes you have a mechanism for obtaining a SAML assertion, samlAssertion
from the user's IdP.
SFAClient *sfaClient = [[SFAClient alloc] initWithBaseUrl:@"https://secure.sf-api.com/sf/v3/" andConfiguration:nil];
SFAOAuthService *oauthService = [[SFAOAuthService alloc] initWithSFAClient:sfaClient clientId:@"<client_id>" clientSecret:@"<client_secret>"];
SFApiQuery *query = [oauthService tokenQueryFromSamlAssertion:@"<samlAssertion>"
subdomain:@"<subdomain>" applicationControlPlane:@"<applicationControlPlane>"];
[sfaClient executeQueryAsync:query
callbackQueue:nil
completionCallback:^(id returnValue, SFAError *error, NSDictionary *additionalInfo)
{
if (error)
{
//handle error
}
else if ([returnValue isKindOfClass:[SFAOAuthToken class]])
{
SFAOAuthToken *token = (SFAOAuthToken *)returnValue;
[sfaClient addOAuthToken:token];
sfaClient.baseUrl = [token getUrl];
}
}];
Any OAuthToken that is obtained using a code
grant type can be refreshed. This allows a consumer to silently reauthenticate with the ShareFile API without needing to prompt the user. This is useful if you plan on caching the OAuthToken. The sample below assumes you have already pulled an instance of SFAOAuthToken
as cachedOAuthToken
from some local cache.
SFAClient *sfaClient = [[SFAClient alloc] initWithBaseUrl:@"https://secure.sf-api.com/sf/v3/" andConfiguration:nil];
SFAOAuthService *oauthService = [[SFAOAuthService alloc] initWithSFAClient:sfaClient clientId:@"<client_id>" clientSecret:@"<client_secret>"];
SFApiQuery *query = [oauthService refreshOAuthTokenQuery:cachedOAuthToken];
[sfaClient executeQueryAsync:query
callbackQueue:nil
completionCallback:^(id returnValue, SFAError *error, NSDictionary *additionalInfo)
{
if (error)
{
//handle error
}
else if ([returnValue isKindOfClass:[SFAOAuthToken class]])
{
SFAOAuthToken *token = (SFAOAuthToken *)returnValue;
[sfaClient addOAuthToken:token];
sfaClient.baseUrl = [token getUrl];
}
}];
- Object of type
id<SFAQuery>
(Note:SFApiQuery
is a class which conforms toSFAQuery
protocol) is used to represent and contains information regarding any action that needs to be performed using ShareFile's REST API. - Any query can be executed asyncronously using API provider by
SFAClient
, the most useful of which is- (void)executeQueryAsync:callbackQueue:completionCallback:
.
SFApiQuery *query = [sfaClient.sessions loginWithAuthmethod:nil andAuthcomparison:nil];
SFApiQuery *query = [sfaClient.sessions delete];
[sfaClient clearCredentials];
A User in ShareFile derives from the SFPrincipal
object. Most consumers will be interested in SFUser
and SFAccountUser
. The SFAccountUser
type designates the user to be an Employee and will have some additional properties available.
SFApiQuery *query = [sfaClient.users getWithId:@"<id>" andEmailAddress:@"<email>"];
This call will return the default folder for the currently authenticated User.
SFApiQuery *query = [[sfaClient.items get];
SFApiQuery *query = [sfaClient.items getChildrenWithUrl:<URL> andIncludeDeleted:@NO];
SFFolder *newFolder = [[SFFolder alloc] init];
newFolder.Name = @"Sample Folder";
newFolder.Description = @"Created by SF Client SDK";
SFApiQuery *query = [sfaClient.items createFolderWithParentUrl:parentFolder.url folder:newFolder overwrite:@YES andPassthrough:@NO];
SFApiQuery *query = [sfaClient.items searchWithQuery:@"query"];
Because Aliased folders are not exposed alongside standard folders, you must use SFAItemAlias
instead.
NSURL *itemUrl = [sfaClient.items urlWithItemAlias:SFAItemAliasTop];
ShareFile supports the oData protocol which provides standard ways of handling common tasks such as:
- Selecting specific properties
- Expanding Navigation properties such as
Folder.Children
- Performing paging operations
The following SFApiQuery
will only select the Name property. If you execute this, all other properties will be their default values. This is convenient for reducing payloads on the wire.
SFApiQuery *query = [[sfaClient.items get] selectProperty:@"Name"];
The following SFApiQuery
will expand Children
. Since we know we are querying for a Folder
we can ask ShareFile to go ahead and return the list of Children. This helps reduce the number of round trips required. Note Chlidren
is presented as a NSMutableArray
instead of an SFODataFeed
.
SFApiQuery *query = [[sfaClient.items get] expandProperty:@"Children"];
When working with SFODataFeed
responses, you can limit the size of the response by using Top
and Skip
. The following SFApiQuery
will return up to 10 Children and skip the first 10.
SFApiQuery *query = [[[sfaClient.items getChildrenWithUrl:<url> andIncludeDeleted:@YES] top:10] skip:10];
To support paging SFODataFeed
will also return a nextLink which will compute the Top and Skip values for you.
id<SFATask>
,id<SFATransferTask>
andid<SFADownloadTask>
are objects that perform the action represented by theid<SFAQuery>
type object.- You can also cancel a task, track progress and perform many other action on a task depending on its type. See API Reference for detail. You can also refer to the
iOSSample
andMacOSXSample
included in the project
SFAFileInfo *info = [[SFAFileInfo alloc] initWithFilePath:<filePath>];
NSFileHandle *handle = [info fileHandleForWritingCreateIfNeeded:YES];
SFAAsyncFileDownloader *fileDownloader = [self.client asyncFileDownloaderForItem:downloadItem withDownloaderConfig:nil];
id<SFADownloadTask> task = [fileDownloader downloadAsyncToFileHandle:handle
withTransferMetadata:nil
callbackQueue:nil
completionCallback:nil
cancelCallback:nil
progressCallback:nil
dataReceivedCallback:nil];
NSString *path = [[NSBundle mainBundle] pathForResource:<filename> ofType:<extension>];
SFAUploadSpecificationRequest *request = [SFAUploadSpecificationRequest new];
request.fileName = [NSString stringWithFormat:@"%@.%@", filename, extension];
request.title = request.fileName;
request.details = @"Sample Details";
request.method = SFAUploadMethodStandard;
request.overwrite = YES;
request.parent = destinationFolder.url;
SFAAsyncUploaderBase *uploaderBase = [self.client asyncFileUploaderWithUploadSpecificationRequest:request
filePath:path fileUploaderConfig:nil expirationDays:-1];
// Now use one of `SFAAsyncUploaderBase`'s uploadAsync API. See samples for more detail.
id<SFATransferTask> task = [uploaderBase uploadAsyncWithCallbackQueue:nil completionCallback:nil cancelCallback:nil progressCallback:nil];
For task's that conform to SFATransferTask you can track progress using Progress Callback or Progress Notification - see the sample app for details.