2 |
AliyunpanSDK
3 |
4 |
5 |
6 |
7 |
8 |
9 | This is the open-source SDK for Aliyunpan OpenAPI.
10 |
11 |
12 | 示例
13 | ·
14 | 反馈 Bug
15 | ·
16 | 提交需求
17 |
18 |
19 |
20 | ## 准备工作
21 |
22 | 在开始前,请查看阿里云盘开放平台接入指南:
23 |
24 | [👉 如何注册三方开发者](https://www.yuque.com/aliyundrive/zpfszx/tyzl591kxmft4e81)
25 |
26 | ## 快速开始
27 |
28 | ### 1. 创建 Client
29 | ```swift
30 | let client: AliyunpanClient = AliyunpanClient(
31 | .init(
32 | appId: "YOUR_APP_ID",
33 | scope: "YOUR_SCOPE", // e.g. user:base,file:all:read
34 | )
35 | )
36 | ```
37 |
38 | ### 2. 授权
39 | 你可以使用 SDK 提供的多种授权方式授权
40 | #### [Credentials](https://alibaba.github.io/aliyunpan-ios-sdk/Enums/AliyunpanCredentials.html)
41 |
42 | | 授权方式 | 描述 | **不需要** Server | **不需要**阿里云盘客户端 |
43 | | :----: | :----: | :----: | :----: |
44 | | pkce | pkce 授权 | ✅ | ✅ |
45 | | sso | sso pkce 授权 | ✅ | ✅ |
46 | | server | 业务后端授权 | ❌ | ✅ |
47 | | qrCode | 二维码授权 | ✅ | ✅ |
48 | | token | 注入 token 授权 | ✅ | ✅ |
49 |
50 | ```swift
51 | client.authorize(credentials: credentials)
52 | ```
53 |
54 | ### 3. 发送命令
55 |
56 | 使用 SDK,你可以轻松使用所有已提供的 OpenAPI 和它们的请求体、返回体模型
57 |
58 | ```swift
59 | // Concurrency
60 | try await client.send(
61 | AliyunpanScope.User.GetUsersInfo()) // -> GetUsersInfo.Response
62 |
63 | try await client.send(
64 | AliyunpanScope.File.GetFileList(
65 | .init(drive_id: driveId, parent_file_id: "root")))) // -> GetFileList.Response
66 |
67 | // Closure
68 | client.send(
69 | AliyunpanScope.User.GetUsersInfo()) { result in
70 | /// do something
71 | }
72 | ```
73 |
74 | ## 高级功能
75 |
76 | ### 上传
77 | ```swift
78 | let uploader = client.uploader
79 |
80 | // 上传
81 | let task = Task {
82 | let file = try? await uploader.upload(
83 | fileURL: url,
84 | fileName: fileName,
85 | driveId: driveId,
86 | folderId: folderId,
87 | useProof: true // 是否开启快传
88 | )
89 | }
90 |
91 | // 取消
92 | task.cancel()
93 | ```
94 |
95 | ### 下载
96 | ```swift
97 | let downloader = client.downloader
98 |
99 | // 下载
100 | let task = downloader.download(file: file, to: destination)
101 | // let task = downloader.tasks.first
102 |
103 | // 修改并发数,默认为10
104 | downloader.maxConcurrentOperationCount = 10
105 |
106 | // 暂停
107 | downloader.pause(task)
108 | // 恢复
109 | downloader.resume(task)
110 | // 取消
111 | downloader.cancel(task)
112 |
113 | // AliyunpanDownloadDelegate
114 | // 下载速度变化
115 | // func downloader(_ downloader: AliyunpanDownloader, didUpdatedNetworkSpeed networkSpeed: Int64)
116 | // 下载任务状态变化
117 | // func downloader(_ downloader: AliyunpanDownloader, didUpdateTaskState state: AliyunpanDownloadTask.State, for task: AliyunpanDownloadTask)
118 | downloadr.addDelegate(DELEGATE)
119 | ```
120 |
121 | #### 示例
122 | [FileListViewController](Demo/Demo/Demo-iOS/FileListViewController.swift)
123 |
124 | ## 安装方式
125 |
126 | #### Swift Package Manager
127 |
128 | - File > Swift Packages > Add Package Dependency
129 | - 添加 `https://github.com/alibaba/aliyunpan-ios-sdk.git`
130 |
131 | #### CocoaPods
132 |
133 | ```ruby
134 | target 'MyApp' do
135 | pod 'AliyunpanSDK', '~> 0.2'
136 | end
137 | ```
138 |
139 | ## 要求
140 |
141 | - iOS 13.0+ (CocoaPods)
142 | - Swift 5.0+
143 |
144 | ## 文档
145 |
146 | [👉 文档](https://alibaba.github.io/aliyunpan-ios-sdk/)
147 |
148 | ## TODO
149 | - Alamofire、URLSession 拓展
150 |
151 | ## License
152 |
153 | This project is licensed under the [MIT License](LICENSE).
154 |
--------------------------------------------------------------------------------
/Sources/AliyunpanSDK/AliyunpanClient.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AliyunpanClient.swift
3 | // AliyunpanSDK
4 | //
5 | // Created by zhaixian on 2023/11/22.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct AliyunpanClientConfig {
11 | /// 应用 ID
12 | public let appId: String
13 | /// 申请权限
14 | public let scope: String
15 | /// 业务方自定义 id,可实现账号互绑
16 | public var identifier: String?
17 |
18 | /// - Parameters:
19 | /// - appId: 应用 ID
20 | /// - scope: 申请权限
21 | /// - identifier: 业务方自定义 id
22 | public init(appId: String, scope: String, identifier: String? = nil) {
23 | self.appId = appId
24 | self.scope = scope
25 | self.identifier = identifier
26 | }
27 | }
28 |
29 | public class AliyunpanClient {
30 | private let config: AliyunpanClientConfig
31 |
32 | private var tokenStorageKey: String {
33 | "com.aliyunpanSDK.accessToken_\(config.appId)_\(config.identifier ?? "-")"
34 | }
35 |
36 | @MainActor var token: AliyunpanToken? {
37 | willSet {
38 | if token != newValue,
39 | let data = try? JSONParameterEncoder().encode(newValue) {
40 | UserDefaults.standard.set(data, forKey: tokenStorageKey)
41 | }
42 | }
43 | }
44 |
45 | /// 获取当前持久化的 accessToken
46 | @MainActor public var accessToken: String? {
47 | token?.access_token
48 | }
49 |
50 | /// 下载器
51 | public lazy var downloader: AliyunpanDownloader = {
52 | let downloader = AliyunpanDownloader()
53 | downloader.client = self
54 | return downloader
55 | }()
56 |
57 | /// 上传器
58 | public lazy var uploader: AliyunpanUploader = {
59 | let uploader = AliyunpanUploader()
60 | uploader.client = self
61 | return uploader
62 | }()
63 |
64 | public init(_ config: AliyunpanClientConfig) {
65 | self.config = config
66 |
67 | if let tokenData = UserDefaults.standard.data(forKey: tokenStorageKey) {
68 | token = try? JSONParameterDecoder().decode(AliyunpanToken.self, from: tokenData)
69 | }
70 | }
71 |
72 | public convenience init(appId: String, scope: String, identifier: String? = nil) {
73 | self.init(.init(appId: appId, scope: scope, identifier: identifier))
74 | }
75 |
76 | /// 强制清除 token 持久化
77 | @MainActor public func cleanToken() {
78 | token = nil
79 | }
80 |
81 | /// 授权
82 | /// 如本地持久化未过期会取持久化,否则会开始授权
83 | /// - Parameter credentials: 授权方式
84 | /// - Returns: token
85 | @discardableResult
86 | public func authorize(
87 | credentials: AliyunpanCredentials = .pkce
88 | ) async throws -> AliyunpanToken {
89 | if let token = await token, !token.isExpired {
90 | return token
91 | }
92 | let token = try await credentials.implement.authorize(
93 | appId: config.appId,
94 | scope: config.scope
95 | )
96 | await MainActor.run {
97 | self.token = token
98 | }
99 | return token
100 | }
101 |
102 | /// 发送请求
103 | ///
104 | /// - throws:
105 | /// `DecodingError`: JSON 解析错误
106 | /// `AliyunpanAuthorizeError`: 授权错误
107 | /// `AliyunpanServerError`: 服务端错误
108 | /// `AliyunpanNetworkSystemError`: 网络系统错误
109 | public func send