Filestack iOS SDK
这是 Filestack 的官方 Swift iOS,一个 API 和内容管理系统,能够轻松地将强大的文件上传和转换功能添加到任何网络或移动应用程序。
资源
要求
- Xcode 11+ (需要 Xcode 12+ 支持SPM)
- Swift 4.2+ / Objective-C
- iOS 11.0+
安装
CocoaPods
CocoaPods 是 Cocoa 项目的依赖管理器。您可以使用以下命令进行安装
$ gem install cocoapods
要使用 CocoaPods 将 Filestack 集成到您的 Xcode 项目中,请在其 Podfile
中指定它
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.0'
use_frameworks!
target '<Your Target Name>' do
pod 'Filestack', '~> 2.8.5'
end
然后,运行以下命令
$ pod install
Carthage
Carthage 是一个去中心化的依赖管理器,它可以构建您的依赖并提供二进制框架。
您可以使用以下命令使用 Homebrew 安装 Carthage
$ brew update
$ brew install carthage
要使用 Carthage 将 Filestack 集成到您的 Xcode 项目中,请在其 Cartfile
中指定它
github "filestack/filestack-ios" ~= 2.8.5
运行 carthage update
来构建框架,并将构建的 Filestack.framework
拖放到您的 Xcode 项目中。此外,将 Filestack.framework
、FilestackSDK.framework
和 ZIPFoundation.framework
添加到您的应用程序目标的嵌入式框架构建阶段。
Swift Package Manager
将 https://github.com/filestack/filestack-ios.git
添加为 Swift Package Manager 的依赖项到您的 Xcode 项目。
或者,如果您正在将 Filestack
添加到自己的 Swift 包中,请在您的 Package.swift
中声明依赖项
dependencies: [
.package(name: "Filestack", url: "https://github.com/filestack/filestack-ios.git", .upToNextMajor(from: "2.8.5"))
]
手动
嵌入框架
打开终端,切换到您的顶级项目目录,如果您的项目尚未初始化为git仓库,请运行以下命令:
$ git init
通过运行以下命令将Filestack及其依赖项作为git子模块添加:
$ 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/weichsel/ZIPFoundation.git
打开新的filestack-ios
文件夹,并在您的应用Xcode项目的项目导航器中拖放Filestack.xcodeproj
。
它应该嵌套在您的应用蓝色项目图标下。它是在所有其他Xcode分组之上还是在之下无关紧要。在项目导航器中选择Filestack.xcodeproj
,并验证部署目标与您的应用目标相匹配。
接下来,在项目导航器(蓝色项目图标)中选择您的应用项目,然后导航到目标配置窗口并选择侧边栏中的“ Targets”部分下的应用目标。
在该窗口顶部的标签栏中,打开“ General”面板。
在“ Embedded Binaries”部分下点击+按钮,并选择iOS的Filestack.framework
。
为添加FilestackSDK
和ZIPFoundation
依赖框架重复此过程。
用法
导入必需的框架
需要使用Filestack iOS SDK的任何源文件应该导入Filestack
和FilestackSDK
框架
import Filestack
import FilestackSDK
实例化Filestack对象
// 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 a callback URL scheme that is handled by your app.
config.callbackURLScheme = "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 uploader = client.upload(using: 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`, or `.documents`)
let sourceType: LocalSource = .camera
// Upload options for any uploaded files.
let uploadOptions: UploadOptions = .defaults
// Store options for any uploaded files.
uploadOptions.storeOptions = StorageOptions(location: .s3, access: .public)
let behavior = .uploadAndStore(uploadOptions: uploadOptions)
let uploader = client.pickFiles(using: presentingViewController,
source: sourceType,
behavior: behavior,
pickCompletionHandler: { (urls) in
// Copy, move, or access the contents of the returned files at this point while they are still available.
// Once this closure call returns, all the files will be automatically removed.
}) { (responses) in
for response in responses {
// 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
}
}
}
// OPTIONAL: Monitor upload progress.
let uploadObserver = uploader.progress.observe(\.fractionCompleted, options: [.new]) { (progress, change) in
// TODO: Use `progress` or `change` objects.
})
在所有的上传示例中,可以通过在Uploader
上调用cancel()
在任何时候取消上传。
uploader.cancel()
从云服务提供商列出内容
client.folderList(provider: .googleDrive, 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.
}
}
将来自云服务提供商的内容存储到存储位置
// 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: .googleDrive, path: "/some-large-image.jpg", storeOptions: storeOptions) { (response) in
if let error = response.error {
// Handle error
return
}
if let contents = response.contents {
// Contents received describing the request's result.
}
}
确保在调用store
之前,使用folderList
函数首先对云服务提供商进行身份验证。
启动选择器用户界面
这是从示例应用程序(包含在此存储库中)中拆分出来的代码片段,描述了使用一些最相关的配置选项启动选择器用户界面的过程。
1. 设置策略和安全对象
// 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
// https://dev.filestack.com/.
guard let security = try? Security(policy: policy, appSecret: "YOUR-APP-SECRET-HERE") else {
fatalError("Unable to instantiate Security object.")
}
2. 设置配置对象
// 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(callbackURLScheme: "YOUR-APP-URL-SCHEME")
.with(videoQuality: .typeHigh)
.with(imageURLExportPreset: .current)
.with(maximumSelectionLimit: 10)
.withEditorEnabled()
.with(availableCloudSources: [.dropbox, .googledrive, .googlephotos, .customSource])
.with(availableLocalSources: [.camera])
.build()
3. 设置客户端对象
// Instantiate the Filestack `Client` by passing an API key obtained from 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)
4. 使用自定义存储选项实例化选择器
// 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)
5. (可选) 设置选择行为
上传和存储行为
/// After finishing picking, local files are uploaded and cloud files are stored at the store destination.
picker.behavior = .uploadAndStore(uploadOptions: .defaults)
仅存储行为
/// After finishing picking, only cloud files are stored at the store destination.
picker.behavior = .storeOnly
6. 设置选择器的代理
// Optional. Set the picker's delegate.
picker.pickerDelegate = self
并在你的视图中实现 PickerNavigationControllerDelegate
协议,例如:
extension ViewController: PickerNavigationControllerDelegate {
/// Called when the picker finishes picking files originating from the local device.
func pickerPickedFiles(picker: PickerNavigationController, fileURLs: [URL]) {
switch picker.behavior {
case .storeOnly:
// IMPORTANT: Copy, move, or access the contents of the returned files at this point while they are still available.
// Once this delegate function call returns, all the files will be automatically removed.
// Dismiss the picker since we have finished picking files from the local device, and, in `storeOnly` mode,
// there's no upload phase.
DispatchQueue.main.async {
picker.dismiss(animated: true) {
self.presentAlert(titled: "Success", message: "Finished picking files: \(fileURLs)")
}
}
case let .uploadAndStore(uploadOptions):
// TODO: Handle this case.
break
default:
break
}
}
/// Called when the picker finishes storing a file originating from a cloud source into the destination storage location.
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)")
}
}
/// Called when the picker finishes uploading a file originating from the local device into the destination storage location.
func pickerUploadedFile(picker: PickerNavigationController, response: JSONResponse?) {
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)")
}
}
/// Called when the picker reports progress during a file or set of files being uploaded.
func pickerReportedUploadProgress(picker: PickerNavigationController, progress: Float) {
print("Picker \(picker) reported upload progress: \(progress)")
}
}
7. 在屏幕上显示选择器
yourViewController.present(picker, animated: true)
8. (可选) 启用后台上传支持
从 Filestack SDK 2.3
版本开始,支持后台上传。为了在 Filestack 中使用后台上传功能,只需在您的代码中添加以下内容
// Set `UploadService.shared.useBackgroundSession` to true to allow uploads in the background.
FilestackSDK.UploadService.shared.useBackgroundSession = true
9. (可选) 实现自定义选择器源
从 Filestack iOS SDK 2.8.0
版本开始,SDK 用户可以通过以下步骤添加自己的自定义源实现
-
创建一个新的视图控制器,继承自
UIViewController
并实现SourceProvider
class MyCustomSourceProvider: UIViewController, SourceProvider { // 1. Add `sourceProviderDelegate` weak var sourceProviderDelegate: SourceProviderDelegate? // 2. Add initializer. init() { // TODO: Implement initializer. } // 3. Call this function whenever you want to start uploading files. // These should be passed to the source provider delegate as an array of locally stored URLs. @objc func upload() { let urls = Array(urls) dismiss(animated: true) { self.sourceProviderDelegate?.sourceProviderPicked(urls: urls) } } // 4. Call this function whenever you want to dismiss your source provider without uploading. @objc func cancel() { dismiss(animated: true) { self.sourceProviderDelegate?.sourceProviderCancelled() } } // TODO: Continue implementing your view controller. }
-
设置您的自定义源
/// Returns a custom `LocalSource` configured to use an user-provided `SourceProvider`. func customLocalSource() -> LocalSource { // Instantiate your source provider let customProvider = MyCustomSourceProvider() // Optional. Configure your `customProvider` object customProvider.urls = [url1, url2, url3] // Define your custom source let customSource = LocalSource.custom( description: "Custom Source", image: UIImage(named: "icon-custom-source")!, provider: customProvider ) // Return your custom source return customSource }
-
将您的自定义源传递给您的
Config
对象- 使用
Filestack.Config.builder
.with(availableLocalSources: [.camera, .photoLibrary, .documents, customLocalSource()])
- 直接使用
Filestack.Config
config.availableLocalSources = [.camera, .photoLibrary, .documents, customLocalSource()]
- 使用
演示
请查看此存储库中包含的演示应用程序,了解上述所有主题。
版本控制
Filestack iOS SDK 遵循 语义化版本控制。
问题
如果您遇到问题,请创建一个Github 问题。
贡献
请查阅 CONTRIBUTING.md 获取详细信息。
致谢
感谢所有 贡献者。