├── ICloudManager
├── ICloudDocumentModel.swift
├── ICloudDocumentPickerViewController.swift
├── ICloudFileHelper.swift
└── ICloudManager.swift
├── ICloudPicker.podspec
├── LICENSE
└── README.md
/ICloudManager/ICloudDocumentModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ICloudDocumentModel.swift
3 | // cloud
4 | //
5 | // Created by Teng Wang 王腾 on 2018/10/10.
6 | // Copyright © 2018 Teng Wang 王腾. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | open class ICloudDocumentModel: NSObject {
12 |
13 | open var fileURL: URL?
14 |
15 | /// 文件的名称
16 | /// eg. “/tmp/scratch.tiff” -> “/tmp/scratch”
17 | /// eg. “/tmp/” -> “/tmp”
18 | /// eg. “scratch..tiff” -> “scratch.”
19 | open var fileName: String?
20 |
21 | open var fileIsExist = false
22 |
23 | /// 文件的相关属性. Use: fileAttributes.fileSize()
24 | open var fileAttributes: NSDictionary?
25 |
26 | /// 创建 ICloudDocumentModel 实例, 会进行参数的初始化操作
27 | ///
28 | /// - Parameter path: 文档j路径
29 | /// - Returns: ICloudDocumentModel 实例
30 | open class func model(path: String) -> ICloudDocumentModel {
31 |
32 | let documentModel = ICloudDocumentModel()
33 |
34 | guard !path.isEmpty else {
35 | return documentModel
36 | }
37 |
38 | documentModel.fileURL = URL.init(fileURLWithPath: path)
39 |
40 | // 读取文件名
41 | if let fileUrl = documentModel.fileURL {
42 | let pathString = NSString.init(string: fileUrl.lastPathComponent)
43 | documentModel.fileName = pathString.deletingPathExtension
44 | }
45 |
46 | let fileManager = FileManager.default
47 | documentModel.fileIsExist = fileManager.fileExists(atPath: path)
48 |
49 | // 获取文件相关属性
50 | guard let fileAttributes = ICloudFileHelper.fileAttr(atPath: path) else {
51 | return documentModel
52 | }
53 | documentModel.fileAttributes = fileAttributes
54 |
55 | return documentModel
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/ICloudManager/ICloudDocumentPickerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ICloudDocumentPickerViewController.swift
3 | // cloud
4 | //
5 | // Created by Teng Wang 王腾 on 2018/10/9.
6 | // Copyright © 2018 Teng Wang 王腾. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class ICloudDocumentPickerViewController: UIDocumentPickerViewController {
12 |
13 | /// 主题颜色
14 | public var themeColor: UIColor?
15 |
16 | public override func viewDidLoad() {
17 | super.viewDidLoad()
18 | modalPresentationStyle = .fullScreen
19 | modalTransitionStyle = .coverVertical
20 | }
21 |
22 | /// 设置主题颜色
23 | ///
24 | /// - Parameter animated:
25 | public override func viewWillAppear(_ animated: Bool) {
26 | super.viewWillAppear(animated)
27 | if let themeColor = themeColor {
28 | configureThemeColor(themeColor)
29 | }
30 | }
31 |
32 | /// 恢复系统主题颜色
33 | ///
34 | /// - Parameter animated:
35 | public override func viewWillDisappear(_ animated: Bool) {
36 | super.viewWillDisappear(animated)
37 | if let _ = themeColor {
38 | configureThemeColor(.blue)
39 | }
40 | }
41 |
42 | /// 设置主题颜色
43 | ///
44 | /// - Parameter themeColor:
45 | func configureThemeColor(_ themeColor: UIColor) {
46 | UIImageView.appearance().tintColor = themeColor
47 | UITabBar.appearance().tintColor = themeColor
48 | UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = themeColor
49 | UIBarButtonItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor:themeColor], for: .normal)
50 | UILabel.appearance().tintColor = themeColor
51 | UIButton.appearance().tintColor = themeColor
52 | view.tintColor = themeColor
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ICloudManager/ICloudFileHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ICloudFileHelper.swift
3 | // cloud
4 | //
5 | // Created by Teng Wang 王腾 on 2018/10/10.
6 | // Copyright © 2018 Teng Wang 王腾. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class ICloudFileHelper: NSObject {
12 |
13 | /// 创建文件目录、如果不存在目录会创建目录
14 | ///
15 | /// - Parameter atPath: 文件目录
16 | /// - Returns: 是否创建成功
17 | @discardableResult
18 | public class func createDirectory(atPath: String) -> Bool {
19 | let fileManager = FileManager.default
20 | let result = fileManager.fileExists(atPath: atPath)
21 | if result == false {
22 | do {
23 | try fileManager.createDirectory(atPath: atPath,
24 | withIntermediateDirectories: true,
25 | attributes: nil)
26 | } catch {
27 | return false
28 | }
29 | return true
30 | } else {
31 | return true
32 | }
33 | }
34 |
35 | /// 获取单个文件大小
36 | ///
37 | /// - Parameter atPath: 文件路径
38 | /// - Returns: 文件大小
39 | public class func fileSize(atPath: String) -> Float {
40 | let fileManager = FileManager.default
41 | guard fileManager.fileExists(atPath: atPath) else {
42 | return 0.0
43 | }
44 | do {
45 | let attr = try fileManager.attributesOfItem(atPath: atPath) as NSDictionary
46 | return Float(attr.fileSize())
47 | } catch {
48 | return 0.0
49 | }
50 | }
51 |
52 | /// 获取文件属性
53 | ///
54 | /// - Parameter atPath: 文件路径
55 | /// - Returns: 文件大小
56 | public class func fileAttr(atPath: String) -> NSDictionary? {
57 | let fileManager = FileManager.default
58 | guard fileManager.fileExists(atPath: atPath) else {
59 | return nil
60 | }
61 | do {
62 | let attr = try fileManager.attributesOfItem(atPath: atPath) as NSDictionary
63 | return attr
64 | } catch {
65 | return nil
66 | }
67 | }
68 |
69 |
70 | /// 获取文件夹的大小
71 | ///
72 | /// - Parameter atPath: 文件夹路径
73 | /// - Returns: 文件夹大小
74 | public class func forderSize(atPath: String) -> Float {
75 |
76 | let fileManager = FileManager.default
77 | guard fileManager.fileExists(atPath: atPath) else {
78 | return 0.0
79 | }
80 | guard let childFilePaths = fileManager.subpaths(atPath: atPath) else {
81 | return 0.0
82 | }
83 |
84 | var fileSize: Float = 0
85 | for path in childFilePaths {
86 | let fileAbsoluePath = atPath + "/" + path
87 | if isDirectory(atPath: fileAbsoluePath) {
88 | fileSize += 0
89 | } else {
90 | fileSize += ICloudFileHelper.fileSize(atPath: fileAbsoluePath)
91 | }
92 | }
93 | return fileSize
94 | }
95 |
96 | /// 是否是文件夹
97 | ///
98 | /// - Parameter atPath: 目录路径
99 | /// - Returns: true or false
100 | public class func isDirectory(atPath: String) -> Bool {
101 | var isDirectory: ObjCBool = ObjCBool(false)
102 | let fromExist = FileManager.default.fileExists(atPath: atPath,
103 | isDirectory: &isDirectory)
104 | return fromExist && isDirectory.boolValue
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/ICloudManager/ICloudManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // iCloudManager.swift
3 | // cloud
4 | //
5 | // Created by Teng Wang 王腾 on 2018/10/8.
6 | // Copyright © 2018 Teng Wang 王腾. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class ICloudManager: NSObject {
12 |
13 | /// 存放的默认路径
14 | public static let iCloudBoxPath = NSHomeDirectory() + "/Documents/iCloudBox/Doc/"
15 |
16 | public static let iCloudBoxDownLoadPath = NSHomeDirectory() + "/Documents/iCloudBox/Download/"
17 |
18 | /// 判断iCloud是否可用
19 | ///
20 | /// - Returns: ture false
21 | public class func iCloudEnable() -> Bool {
22 | let manager = FileManager.default
23 | if let _ = manager.url(forUbiquityContainerIdentifier: nil) {
24 | return true
25 | } else {
26 | return false
27 | }
28 | }
29 |
30 | /// 通过iCloudDocument 打开和关闭文件
31 | ///
32 | /// - Parameters:
33 | /// - documentURL: documentURL description
34 | /// - callBack: 文件数据、文件大小 kb
35 | public class func download(with documentURL: URL, callBack: @escaping (NSData?, Float) -> Void) {
36 | let iCloudDoc = iCloudDocument.init(fileURL: documentURL)
37 | iCloudDoc.open { (result) in
38 | if result {
39 | let size = ICloudFileHelper.fileSize(atPath: documentURL.path)
40 | iCloudDoc.close(completionHandler: { (_) in })
41 | callBack(iCloudDoc.data, size)
42 | }
43 | }
44 | }
45 |
46 | /// 保存文件到本地 /Documents/iCloudBox 下
47 | ///
48 | /// - Parameters:
49 | /// - documentURL: documentURL description
50 | /// - maxSize: 保存的最大尺寸 为 nil 忽略
51 | /// - callBack: 保存h的路径 url、是否保存成功、保存失败的描述
52 | public class func save(with documentURL: URL, maxSize: Float?, callBack: @escaping (ICloudDocumentModel?, Bool, String) -> Void) {
53 |
54 | guard ICloudManager.iCloudEnable() else {
55 | callBack(nil, false, "请在设置->AppleID、iCloud->iCloud中打开访问权限")
56 | return
57 | }
58 |
59 | var forderPath = documentURL.absoluteString.replacingOccurrences(of: "file:///private/var/mobile/Library/Mobile%20Documents/", with: "")
60 |
61 | forderPath = forderPath.replacingOccurrences(of: documentURL.lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "", with: "")
62 | guard let forderName = forderPath.removingPercentEncoding else {
63 | callBack(nil, false, "forderName 不存在")
64 | return
65 | }
66 |
67 | ICloudManager.download(with: documentURL) { (obj, fileSize) in
68 |
69 | if let maxSize = maxSize {
70 | guard fileSize < maxSize else {
71 | callBack(nil, false, "文件不能大于\(maxSize)m")
72 | return
73 | }
74 | }
75 | if let data = obj {
76 | let writeUrl = URL.init(fileURLWithPath: ICloudManager.iCloudBoxPath + forderName + documentURL.lastPathComponent)
77 | ICloudFileHelper.createDirectory(atPath: ICloudManager.iCloudBoxPath + forderName)
78 | do {
79 | try data.write(to: writeUrl, options: .atomic)
80 | callBack(ICloudDocumentModel.model(path: writeUrl.path), true, "文件写入成功")
81 | } catch {
82 | callBack(nil, false, "文件写入失败")
83 | }
84 | }
85 | }
86 |
87 | }
88 |
89 | /// 文件是否在 iCloudBox 存在
90 | ///
91 | /// - Parameter fileName: 文件名(fileUrl.lastPathComponent) eg. doc.text
92 | /// - Returns:
93 | open class func documentIsExists(fileName: String) -> URL? {
94 |
95 | let fileManager = FileManager.default
96 |
97 | guard let childFilePaths = fileManager.subpaths(atPath: ICloudManager.iCloudBoxDownLoadPath) else {
98 | return nil
99 | }
100 |
101 | for path in childFilePaths {
102 | // 读取文件名
103 | let fileUrl = URL.init(fileURLWithPath: ICloudManager.iCloudBoxDownLoadPath + path)
104 | if fileName == fileUrl.lastPathComponent {
105 | return fileUrl
106 | }
107 | }
108 | return nil
109 | }
110 | }
111 |
112 | extension ICloudManager {
113 |
114 | /// 清除iCloudBox本地缓存, filePath 为空 清除所有缓存
115 | ///
116 | /// - Parameter filePath: 为空 清除所有缓存
117 | public class func cleariCloudBoxCache(filePath: URL = URL(fileURLWithPath: ICloudManager.iCloudBoxPath)) {
118 | do {
119 | try FileManager.default.removeItem(at: filePath)
120 | } catch {
121 |
122 | }
123 | }
124 |
125 | /// 异步获取iCloudBox 缓存大小
126 | ///
127 | /// - Parameter callBack: 大小 kb
128 | public class func asynciCloudBoxSize(callBack: @escaping(Float) -> Void) {
129 | DispatchQueue.global().async {
130 | let size = ICloudFileHelper.forderSize(atPath: ICloudManager.iCloudBoxPath)
131 | callBack(size)
132 | }
133 | }
134 | }
135 |
136 | class iCloudDocument: UIDocument {
137 |
138 | var data: NSData?
139 |
140 | // 处理文件下载
141 | override func load(fromContents contents: Any, ofType typeName: String?) throws {
142 | if let userContent = contents as? NSData {
143 | data = userContent
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/ICloudPicker.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint ICloudPicker.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |s|
10 |
11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
12 | #
13 | # These will help people to find your library, and whilst it
14 | # can feel like a chore to fill in it's definitely to your advantage. The
15 | # summary should be tweet-length, and the description more in depth.
16 | #
17 |
18 | s.name = "ICloudPicker"
19 | s.version = "0.0.10"
20 | s.summary = "icloud driver picker"
21 | s.swift_version = '4.0'
22 |
23 | # This description is used to generate tags and improve search results.
24 | # * Think: What does it do? Why did you write it? What is the focus?
25 | # * Try to keep it short, snappy and to the point.
26 | # * Write the description between the DESC delimiters below.
27 | # * Finally, don't worry about the indent, CocoaPods strips it!
28 | s.description = <<-DESC
29 | icloud driver picker
30 | DESC
31 |
32 | s.homepage = "https://github.com/xiaohuochai/iCloudPicker.git"
33 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
34 |
35 |
36 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
37 | #
38 | # Licensing your code is important. See http://choosealicense.com for more info.
39 | # CocoaPods will detect a license file if there is a named LICENSE*
40 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
41 | #
42 |
43 | # s.license = "MIT"
44 | s.license = { :type => "MIT", :file => "LICENSE" }
45 |
46 |
47 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
48 | #
49 | # Specify the authors of the library, with email addresses. Email addresses
50 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
51 | # accepts just a name if you'd rather not provide an email address.
52 | #
53 | # Specify a social_media_url where others can refer to, for example a twitter
54 | # profile URL.
55 | #
56 |
57 | s.author = { "Teng Wang 王腾" => "teng.wang.o@nio.com" }
58 | # Or just: s.author = "Teng Wang 王腾"
59 | # s.authors = { "Teng Wang 王腾" => "teng.wang.o@nio.com" }
60 | # s.social_media_url = "http://twitter.com/Teng Wang 王腾"
61 |
62 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
63 | #
64 | # If this Pod runs only on iOS or OS X, then specify the platform and
65 | # the deployment target. You can optionally include the target after the platform.
66 | #
67 |
68 | # s.platform = :ios
69 | s.platform = :ios, "10.0"
70 |
71 | # When using multiple platforms
72 | s.ios.deployment_target = "10.0"
73 | # s.osx.deployment_target = "10.7"
74 | # s.watchos.deployment_target = "2.0"
75 | # s.tvos.deployment_target = "9.0"
76 |
77 |
78 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
79 | #
80 | # Specify the location from where the source should be retrieved.
81 | # Supports git, hg, bzr, svn and HTTP.
82 | #
83 |
84 | s.source = { :git => "https://github.com/xiaohuochai/iCloudPicker.git", :tag => "#{s.version}" }
85 |
86 |
87 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
88 | #
89 | # CocoaPods is smart about how it includes source code. For source files
90 | # giving a folder will include any swift, h, m, mm, c & cpp files.
91 | # For header files it will include any header in the folder.
92 | # Not including the public_header_files will make all headers public.
93 | #
94 |
95 | s.source_files = "ICloudManager/*.swift"
96 | # s.exclude_files = ""
97 |
98 | # s.public_header_files = "ICloudManager/*.swift"
99 |
100 |
101 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
102 | #
103 | # A list of resources included with the Pod. These are copied into the
104 | # target bundle with a build phase script. Anything else will be cleaned.
105 | # You can preserve files from being cleaned, please don't preserve
106 | # non-essential files like tests, examples and documentation.
107 | #
108 |
109 | # s.resource = "icon.png"
110 | # s.resources = "Resources/*.png"
111 |
112 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
113 |
114 |
115 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
116 | #
117 | # Link your library with frameworks, or libraries. Libraries do not include
118 | # the lib prefix of their name.
119 | #
120 |
121 | # s.framework = "SomeFramework"
122 | # s.frameworks = "SomeFramework", "AnotherFramework"
123 |
124 | # s.library = "iconv"
125 | # s.libraries = "iconv", "xml2"
126 |
127 |
128 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
129 | #
130 | # If your library depends on compiler flags you can set them in the xcconfig hash
131 | # where they will only apply to your library. If you depend on other Podspecs
132 | # you can include multiple dependencies to ensure it works.
133 |
134 | # s.requires_arc = true
135 |
136 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
137 | # s.dependency "JSONKit", "~> 1.4"
138 |
139 | end
140 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 wangteng
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ICloudPicker
2 |
3 | swift 版本
4 |
5 | 特点:
6 |
7 | 1、直接显示到 iCloud 云盘位置
8 |
9 | 2、可以自定义主题颜色、(微信自定义了主题颜色)
10 |
11 | 3、使用 UIDocument 来读写文件保证文件的安全访问
12 |
13 | [https://github.com/xiaohuochai/iCloudPicker.git](https://github.com/xiaohuochai/iCloudPicker.git)
14 |
15 |
16 | # Installation
17 |
18 | ## Using [CocoaPods](https://cocoapods.org):
19 | Simply add the following line to your Podfile:
20 | ```
21 | pod 'ICloudPicker'
22 | ```
23 |
24 | # Xcode config
25 |
26 |
27 |
28 | # Use
29 | ```
30 | func openICloudDocumentPickerViewController() {
31 | guard ICloudManager.iCloudEnable() else {
32 | debugPrint("请在设置->AppleID、iCloud->iCloud中打开访问权限")
33 | return
34 | }
35 |
36 | let iCloudDocument = ICloudDocumentPickerViewController.init(documentTypes: ["public.data"], in: .open)
37 | iCloudDocument.themeColor = .red
38 | iCloudDocument.delegate = self
39 | self.present(iCloudDocument, animated: true) {}
40 | }
41 | ```
42 |
43 | ```
44 | extension ViewController: UIDocumentPickerDelegate {
45 |
46 | public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
47 | saveiCloudDocument(urls)
48 | }
49 |
50 | public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
51 | saveiCloudDocument([url])
52 | }
53 |
54 | /// 保存文件、限制文件大小为10m
55 | ///
56 | /// - Parameter url: UIDocumentPicker url
57 | func saveiCloudDocument(_ urls: [URL]) {
58 | guard let url = urls.first else {
59 | return
60 | }
61 | ICloudManager.save(with: url, maxSize: 10*1024*1024) { (documentModel, result, errorMsg) in
62 |
63 | }
64 | }
65 | }
66 | ```
67 |
68 | # Cache
69 | ```
70 | func iCloudBoxCache() {
71 |
72 | // 异步获取 ICloudDocument 文件大小
73 | ICloudManager.asynciCloudBoxSize { (size) in
74 | debugPrint(size)
75 |
76 | // 清除所有 本地存储的 ICloudDocument 文件
77 | ICloudManager.cleariCloudBoxCache()
78 |
79 | // 清除单个文件
80 | // ICloudManager.cleariCloudBoxCache(filePath: URL.init(fileURLWithPath: ""))
81 | }
82 | }
83 | ```
84 | # view
85 |
86 |
--------------------------------------------------------------------------------