Skip to content

Commit b800caf

Browse files
committed
feat: add ios implementation
1 parent 72b291b commit b800caf

File tree

12 files changed

+467
-36
lines changed

12 files changed

+467
-36
lines changed

packages/capacitor-plugin/.gitignore

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@ DerivedData/
1616
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
1717
.netrc
1818

19-
2019
# macOS files
2120
.DS_Store
2221

23-
24-
2522
# Based on Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
2623

2724
# Built application files
@@ -67,4 +64,4 @@ captures
6764
#*.jks
6865

6966
# External native build folder generated in Android Studio 2.2 and later
70-
.externalNativeBuild
67+
.externalNativeBuild

packages/capacitor-plugin/CapacitorFileTransfer.podspec

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ Pod::Spec.new do |s|
1212
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
1313
s.source_files = 'ios/Sources/FileTransferPlugin/*.{swift,h,m,c,cc,mm,cpp}'
1414
s.ios.deployment_target = '14.0'
15-
#s.dependency 'FileTransferLib', spec='~> 1.0'
16-
# temporary xcframeowrk dependency - TODO update to official pod (commented line above) once published
17-
s.vendored_frameworks = 'ios/Sources/*/IONFileTransferLib.xcframework'
1815
s.dependency 'Capacitor'
16+
s.dependency 'IONFileTransferLib', spec='~> 1.0'
1917
s.swift_version = '5.1'
2018
end

packages/capacitor-plugin/Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ let package = Package(
1010
targets: ["FileTransferPlugin"])
1111
],
1212
dependencies: [
13-
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
13+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "7.1.0")
1414
],
1515
targets: [
1616
.binaryTarget(
1717
name: "IONFileTransferLib",
1818
// url: "https://github.com/ionic-team/ion-ios-filetransfer/releases/download/1.0.0/IONFileTransferLib.zip",
1919
// checksum: "<compute_checksum>" // sha-256
20-
path: "./ios/Sources/FileTransferPlugin/IONFileTransferLib.xcframework"
20+
path: "./ios/Sources/FileTransferPlugin/IONFileTransferLib.zip"
2121
),
2222
.target(
2323
name: "FileTransferPlugin",

packages/capacitor-plugin/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Perform an HTTP request to upload a file to a server
6565
### addListener('progress', ...)
6666

6767
```typescript
68-
addListener(eventName: 'progress', listenerFunc: (progress: ProgressStatus) => void) => Promise<PluginListenerHandle>
68+
addListener(eventName: "progress", listenerFunc: (progress: ProgressStatus) => void) => Promise<PluginListenerHandle>
6969
```
7070

7171
Add a listener to file transfer (download or upload) progress events.

packages/capacitor-plugin/ios/Sources/FileTransferPlugin/FileTransfer.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import Foundation
2+
import Capacitor
3+
import IONFileTransferLib
4+
5+
/// A structured error type used in file transfer operations.
6+
///
7+
/// `FileTransferError` represents various error states that can occur during file uploads and downloads,
8+
/// including validation issues, connection problems, HTTP response errors, and file system errors.
9+
struct FileTransferError: Error {
10+
11+
/// A error code in the format `OS-PLUG-FLTR-XXXX`.
12+
let code: String
13+
14+
/// A human-readable error message.
15+
let message: String
16+
17+
/// The source URL or path related to the error, if available.
18+
var source: String?
19+
20+
/// The target URL or path related to the error, if available.
21+
var target: String?
22+
23+
/// The HTTP status code, if the error is related to a network response.
24+
let httpStatus: Int?
25+
26+
/// The response body returned by the server, if any.
27+
let body: String?
28+
29+
/// The response headers returned by the server, if any.
30+
let headers: [String: String]?
31+
32+
/// The underlying error that caused this error, if any.
33+
let cause: Error?
34+
35+
/// Creates a new `FileTransferError` with the given values.
36+
///
37+
/// - Parameters:
38+
/// - code: A numeric code that will be formatted internally.
39+
/// - message: A human-readable message describing the error.
40+
/// - source: The original input source, such as a URL or path.
41+
/// - target: The intended destination, such as a URL or path.
42+
/// - httpStatus: Optional HTTP status code if error was a network response.
43+
/// - body: Optional response body.
44+
/// - headers: Optional response headers.
45+
/// - cause: Optional underlying error.
46+
init(
47+
code: Int,
48+
message: String,
49+
source: String? = nil,
50+
target: String? = nil,
51+
httpStatus: Int? = nil,
52+
body: String? = nil,
53+
headers: [String: String]? = nil,
54+
cause: Error? = nil
55+
) {
56+
self.code = String(format: "OS-PLUG-FLTR-%04d", code)
57+
self.message = message
58+
self.source = source
59+
self.target = target
60+
self.httpStatus = httpStatus
61+
self.body = body
62+
self.headers = headers
63+
self.cause = cause
64+
}
65+
66+
/// A dictionary representation of the error for use in JavaScript or other serialization contexts.
67+
///
68+
/// This includes the code, message, and optional metadata such as HTTP status,
69+
/// headers, body, and exception description.
70+
var errorInfo: JSObject {
71+
var info: JSObject = [
72+
"code": code,
73+
"message": message
74+
]
75+
if let httpStatus = httpStatus { info["httpStatus"] = httpStatus }
76+
if let body = body { info["body"] = body }
77+
if let headers = headers {
78+
let headersObj: JSObject = headers.reduce(into: [:]) { result, pair in
79+
result[pair.key] = pair.value
80+
}
81+
info["headers"] = headersObj
82+
}
83+
if let cause = cause { info["exception"] = cause.localizedDescription }
84+
85+
return info
86+
}
87+
}
88+
89+
// MARK: - Static Constructors
90+
91+
extension FileTransferError {
92+
93+
static func invalidParameters(_ message: String? = nil) -> FileTransferError {
94+
.init(code: 5, message: message ?? "The method's input parameters aren't valid.")
95+
}
96+
97+
static func invalidServerUrl(_ url: String?) -> FileTransferError {
98+
.init(
99+
code: 6,
100+
message: (url?.isEmpty ?? true)
101+
? "URL to connect to is either null or empty."
102+
: "Invalid server URL was provided - \(url!)",
103+
source: url
104+
)
105+
}
106+
107+
static func fileDoesNotExist() -> FileTransferError {
108+
.init(code: 8, message: "Operation failed because file does not exist.")
109+
}
110+
111+
static func connectionError() -> FileTransferError {
112+
.init(code: 9, message: "Failed to connect to server.")
113+
}
114+
115+
static func notModified() -> FileTransferError {
116+
.init(
117+
code: 10,
118+
message: "The server responded with HTTP 304 – Not Modified. If you want to avoid this, check your headers related to HTTP caching.",
119+
httpStatus: 304
120+
)
121+
}
122+
123+
static func genericError(
124+
cause: Error? = nil,
125+
message: String? = nil,
126+
responseCode: Int? = nil,
127+
responseBody: String? = nil,
128+
headers: [String: String]? = nil
129+
) -> FileTransferError {
130+
.init(
131+
code: 11,
132+
message: message ?? "The operation failed with an error.",
133+
httpStatus: responseCode,
134+
body: responseBody,
135+
headers: headers,
136+
cause: cause
137+
)
138+
}
139+
}
140+
141+
// MARK: - IONFLTRException Mapping
142+
143+
extension IONFLTRException {
144+
145+
/// Converts an `IONFLTRException` to a corresponding `FileTransferError`.
146+
///
147+
/// This method maps specific cases of `IONFLTRException` to their
148+
/// equivalent `FileTransferError` cases, providing a unified error
149+
/// representation for file transfer operations.
150+
///
151+
/// - Returns: A `FileTransferError` instance representing the exception.
152+
func toFileTransferError() -> FileTransferError {
153+
switch self {
154+
case .invalidPath:
155+
return FileTransferError.invalidParameters()
156+
case .emptyURL:
157+
return FileTransferError.invalidServerUrl(nil)
158+
case .invalidURL(let url):
159+
return FileTransferError.invalidServerUrl(url)
160+
case .fileDoesNotExist:
161+
return FileTransferError.fileDoesNotExist()
162+
case .cannotCreateDirectory:
163+
return FileTransferError.genericError(cause: self)
164+
case .httpError(let responseCode, let responseBody, let headers):
165+
return responseCode == 304
166+
? FileTransferError.notModified()
167+
: FileTransferError.genericError(
168+
cause: self,
169+
message: "HTTP error: \(responseCode) - \(self.description)",
170+
responseCode: responseCode,
171+
responseBody: responseBody,
172+
headers: headers
173+
)
174+
case .connectionError:
175+
return FileTransferError.connectionError()
176+
case .transferError:
177+
return FileTransferError.genericError(cause: self)
178+
case .unknownError:
179+
return FileTransferError.genericError(cause: self)
180+
}
181+
}
182+
}

0 commit comments

Comments
 (0)