This is the official Swift iOS for Filestack — API and content management system that makes it easy to add powerful file uploading and transformation capabilities to any web or mobile application.
- Xcode 8.3 or later
- Swift 3.2 / Objective-C
- iOS 9 or later
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
To integrate Filestack into your Xcode project using CocoaPods, specify it in your Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!
target '<Your Target Name>' do
pod 'Filestack', '~> 1.5'
end
Then, run the following command:
$ pod install
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with Homebrew using the following command:
$ brew update
$ brew install carthage
To integrate Filestack into your Xcode project using Carthage, specify it in your Cartfile
:
github "filestack/filestack-ios" ~> 1.5
Run carthage update
to build the framework and drag the built Filestack.framework
into your Xcode project. Additionally, add Filestack.framework
, FilestackSDK.framework
, Alamofire.framework
, CryptoSwift.framework
, and ZipArchive.framework
to the embedded frameworks build phase of your app's target.
Open up Terminal, cd into your top-level project directory, and run the following command "if" your project is not initialized as a git repository:
$ git init
Add Filestack and its dependencies as git submodules by running the following commands:
$ git submodule add https://github.com/filestack/filestack-ios.git
$ git submodule add https://github.com/filestack/filestack-swift.git
$ git submodule add https://github.com/Alamofire/Alamofire.git
$ git submodule add https://github.com/krzyzanowskim/CryptoSwift.git
$ git submodule add https://github.com/ZipArchive/ZipArchive.git
Open the new filestack-ios
folder, and drag the Filestack.xcodeproj
into the Project Navigator of your application's Xcode project.
It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter.
Select the Filestack.xcodeproj
in the Project Navigator and verify the deployment target matches that of your application target.
Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar.
In the tab bar at the top of that window, open the "General" panel.
Click on the + button under the "Embedded Binaries" section and choose the Filestack.framework
for iOS.
Repeat the same process for adding Alamofire
, CryptoSwift
, FilestackSDK
, and ZipArchive
dependent frameworks.
Any source files that need to use the Filestack iOS SDK should import the Filestack
and FilestackSDK
frameworks:
import Filestack
import FilestackSDK
// Initialize a `Policy` with the expiry time and permissions you need.
let oneDayInSeconds: TimeInterval = 60 * 60 * 24 // expires tomorrow
let policy = Policy(// Set your expiry time (24 hours in our case)
expiry: Date(timeIntervalSinceNow: oneDayInSeconds),
// Set the permissions you want your policy to have
call: [.pick, .read, .store])
// Initialize a `Security` object by providing a `Policy` object and your app secret.
// You can find and/or enable your app secret in the Developer Portal.
guard let security = try? Security(policy: policy, appSecret: "YOUR-APP-SECRET") else {
return
}
// Create `Config` object.
let config = Filestack.Config()
// Make sure to assign an app scheme URL that matches the one configured in your info.plist.
config.appURLScheme = "filestackdemo"
let client = Filestack.Client(apiKey: "YOUR-API-KEY", security: security, config: config)
let localURL = URL(string: "file:///an-app-sandbox-friendly-local-url")!
let uploadRequest = client.upload(from: localURL, uploadProgress: { (progress) in
// Here you may update the UI to reflect the upload progress.
print("progress = \(String(describing: progress))")
}) { (response) in
// Try to obtain Filestack handle
if let json = response?.json, let handle = json["handle"] as? String {
// Use Filestack handle
} else if let error = response?.error {
// Handle error
}
}
// The view controller that will be presenting the image picker.
let presentingViewController = self
// The source type (e.g. `.camera`, `.photoLibrary`)
let sourceType: UIImagePickerControllerSourceType = .camera
let uploadRequest = client.uploadFromImagePicker(viewController: presentingViewController, sourceType: sourceType, uploadProgress: { (progress) in
// Here you may update the UI to reflect the upload progress.
print("progress = \(String(describing: progress))")
}) { (response) in
// Try to obtain Filestack handle
if let json = response?.json, let handle = json["handle"] as? String {
// Use Filestack handle
} else if let error = response?.error {
// Handle error
}
}
// The view controller that will be presenting the image picker.
let presentingViewController = self
let uploadRequest = client.uploadFromDocumentPicker(viewController: presentingViewController, uploadProgress: { (progress) in
// Here you may update the UI to reflect the upload progress.
print("progress = \(String(describing: progress))")
}) { (response) in
// Try to obtain Filestack handle
if let json = response?.json, let handle = json["handle"] as? String {
// Use Filestack handle
} else if let error = response?.error {
// Handle error
}
}
In all the previous uploading examples, an upload may be cancelled at anytime by calling cancel()
on the CancellableRequest
conforming object returned by any of the functions above:
uploadRequest.cancel()
// The cloud provider to use (it may require authentication)
let provider: CloudProvider = .googleDrive
// The cloud provider's path (e.g. "/" for the root's folder)
let path = "/"
// An URL scheme that your app can handle.
let appURLScheme = "FilestackDemo"
client.folderList(provider: provider, path: path, pageToken: nil) { response in
if let error = response.error {
// Handle error
return
}
if let contents = response.contents {
// Contents received — do something with them.
print("Received \(contents.count) entries.")
}
if let nextToken = response.nextToken {
// More contents are available — to retrieve next page, pass this `nextToken` as a parameter in the `folderList` function.
} else {
// No more contents available — we are done.
}
}
Remember also to add this piece of code to your AppDelegate
so the auth flow can complete:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if url.scheme == "YOUR-APP-URL-SCHEME" && url.host == "Filestack" {
if #available(iOS 11.0, *) {
// NO-OP
} else {
NotificationCenter.default.post(name: Filestack.Client.resumeCloudRequestNotification,
object: url)
}
return true
}
// Here we just state that any other URLs should not be handled by this app.
return false
}
// The cloud provider to use
let provider: CloudProvider = .googleDrive
// A path to a file in the cloud
let path = "/some-large-image.jpg"
// Store options for your uploaded files.
// Here we are saying our storage location is S3 and access for uploaded files should be public.
let storeOptions = StorageOptions(location: .s3, access: .public)
client.store(provider: provider, path: path, storeOptions: storeOptions) { (response) in
if let error = response.error {
// Handle error
return
}
if let contents = response.contents {
// Contents received describing the request's result.
}
}
Please make sure to authenticate against the cloud provider first by using the folderList
function before calling store
.
This is a code fragment broken into pieces taken from the Demo app describing the process of launching the picker UI using some of the most relevant config options:
// In case your Filestack account has security enabled, you will need to instantiate a `Security` object.
// We can do this by either configuring a `Policy` and instantiating a `Security` object by passing
// the `Policy` and an `appSecret`, or by instantiating a `Security` object directly by passing an already
// encoded policy together with its corresponding signature — in this example, we will use the 1st method.
// Create `Policy` object with an expiry time and call permissions.
let policy = Policy(expiry: .distantFuture,
call: [.pick, .read, .stat, .write, .writeURL, .store, .convert, .remove, .exif])
// Create `Security` object based on our previously created `Policy` object and app secret obtained from
// [Filestack Developer Portal](https://dev.filestack.com/).
guard let security = try? Security(policy: policy, appSecret: "YOUR-APP-SECRET-HERE") else {
fatalError("Unable to instantiate Security object.")
}
// Create `Config` object.
// IMPORTANT: - Make sure to assign an app scheme URL that matches the one(s) configured in your info.plist
let config = Filestack.Config.builder
.with(appUrlScheme: "YOUR-APP-URL-SCHEME")
.with(videoQuality: .typeHigh)
.with(imageUrlExportPreset: .current)
.with(maximumSelectionLimit: 10)
.withEditorEnabled()
.with(availableCloudSources: [.dropbox, .googledrive, .googlephotos, .customSource])
.with(availableLocalSources: [.camera])
.build()
// Instantiate the Filestack `Client` by passing an API key obtained from [Filestack Developer Portal](https://dev.filestack.com/),
// together with a `Security` and `Config` object.
// If your account does not have security enabled, then you can omit this parameter or set it to `nil`.
let client = Filestack.Client(apiKey: "YOUR-API-KEY-HERE", security: security, config: config)
// Store options for your uploaded files.
// Here we are saying our storage location is S3 and access for uploaded files should be public.
let storeOptions = StorageOptions(location: .s3, access: .public)
// Instantiate picker by passing the `StorageOptions` object we just set up.
let picker = client.picker(storeOptions: storeOptions)
// Optional. Set the picker's delegate.
picker.pickerDelegate = self
And implement the PickerNavigationControllerDelegate
protocol in your view controller, i.e.:
extension ViewController: PickerNavigationControllerDelegate {
func pickerStoredFile(picker: PickerNavigationController, response: StoreResponse) {
if let contents = response.contents {
// Our cloud file was stored into the destination location.
print("Stored file response: \(contents)")
} else if let error = response.error {
// The store operation failed.
print("Error storing file: \(error)")
}
}
func pickerUploadedFile(picker: PickerNavigationController, response: NetworkJSONResponse?) {
if let contents = response?.json {
// Our local file was stored into the destination location.
print("Uploaded file response: \(contents)")
} else if let error = response?.error {
// The upload operation failed.
print("Error uploading file: \(error)")
}
}
}
yourViewController.present(picker, animated: true)
Finally, remember that you'll need this piece of code in your AppDelegate
for the auth flow to complete:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if url.scheme == "YOUR-APP-URL-SCHEME" && url.host == "Filestack" {
if #available(iOS 11.0, *) {
// NO-OP
} else {
NotificationCenter.default.post(name: Filestack.Client.resumeCloudRequestNotification,
object: url)
}
return true
}
// Here we just state that any other URLs should not be handled by this app.
return false
}
- Some of the functions and objects used above support additional parameters and properties, consult the API Reference for more details.
Check the Demo app for an example on how to launch the picker UI with all the settings and options discussed above.
Filestack iOS SDK follows the Semantic Versioning.
If you have problems, please create a Github Issue.
Please see CONTRIBUTING.md for details.
Thank you to all the contributors.