@capgo/capacitor-downloader 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,176 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ /**
5
+ * Please read the Capacitor iOS Plugin Development Guide
6
+ * here: https://capacitorjs.com/docs/plugins/ios
7
+ */
8
+
9
+ @objc(CapacitorDownloaderPlugin)
10
+ public class CapacitorDownloaderPlugin: CAPPlugin, CAPBridgedPlugin {
11
+ public let identifier = "CapacitorDownloaderPlugin"
12
+ public let jsName = "CapacitorDownloader"
13
+ public let pluginMethods: [CAPPluginMethod] = [
14
+ CAPPluginMethod(name: "download", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "pause", returnType: CAPPluginReturnPromise),
16
+ CAPPluginMethod(name: "resume", returnType: CAPPluginReturnPromise),
17
+ CAPPluginMethod(name: "stop", returnType: CAPPluginReturnPromise),
18
+ CAPPluginMethod(name: "checkStatus", returnType: CAPPluginReturnPromise),
19
+ CAPPluginMethod(name: "getFileInfo", returnType: CAPPluginReturnPromise),
20
+ ]
21
+
22
+ private var tasks: [String: URLSessionDownloadTask] = [:]
23
+ private lazy var session: URLSession = {
24
+ let config = URLSessionConfiguration.background(withIdentifier: "CapacitorDownloader")
25
+ config.sessionSendsLaunchEvents = true
26
+ return URLSession(configuration: config, delegate: self, delegateQueue: nil)
27
+ }()
28
+
29
+ @objc func download(_ call: CAPPluginCall) {
30
+ guard let id = call.getString("id"),
31
+ let urlString = call.getString("url"),
32
+ let destination = call.getString("destination"),
33
+ let url = URL(string: urlString) else {
34
+ call.reject("Invalid parameters")
35
+ return
36
+ }
37
+
38
+ var request = URLRequest(url: url)
39
+ if let headers = call.getObject("headers") as? [String: String] {
40
+ for (key, value) in headers {
41
+ request.setValue(value, forHTTPHeaderField: key)
42
+ }
43
+ }
44
+
45
+ let task = session.downloadTask(with: request)
46
+ tasks[id] = task
47
+ task.resume()
48
+
49
+ call.resolve([
50
+ "id": id,
51
+ "state": "RUNNING",
52
+ "progress": 0
53
+ ])
54
+ }
55
+
56
+ @objc func pause(_ call: CAPPluginCall) {
57
+ guard let id = call.getString("id"),
58
+ let task = tasks[id] else {
59
+ call.reject("Task not found")
60
+ return
61
+ }
62
+
63
+ task.suspend()
64
+ call.resolve()
65
+ }
66
+
67
+ @objc func resume(_ call: CAPPluginCall) {
68
+ guard let id = call.getString("id"),
69
+ let task = tasks[id] else {
70
+ call.reject("Task not found")
71
+ return
72
+ }
73
+
74
+ task.resume()
75
+ call.resolve()
76
+ }
77
+
78
+ @objc func stop(_ call: CAPPluginCall) {
79
+ guard let id = call.getString("id"),
80
+ let task = tasks[id] else {
81
+ call.reject("Task not found")
82
+ return
83
+ }
84
+
85
+ task.cancel()
86
+ tasks.removeValue(forKey: id)
87
+ call.resolve()
88
+ }
89
+
90
+ @objc func checkStatus(_ call: CAPPluginCall) {
91
+ guard let id = call.getString("id"),
92
+ let task = tasks[id] else {
93
+ call.reject("Task not found")
94
+ return
95
+ }
96
+
97
+ let state: String
98
+ switch task.state {
99
+ case .running:
100
+ state = "RUNNING"
101
+ case .suspended:
102
+ state = "PAUSED"
103
+ case .canceling:
104
+ state = "ERROR"
105
+ case .completed:
106
+ state = "DONE"
107
+ @unknown default:
108
+ state = "PENDING"
109
+ }
110
+
111
+ call.resolve([
112
+ "id": id,
113
+ "state": state,
114
+ "progress": task.progress.fractionCompleted
115
+ ])
116
+ }
117
+
118
+ @objc func getFileInfo(_ call: CAPPluginCall) {
119
+ guard let path = call.getString("path") else {
120
+ call.reject("Invalid path")
121
+ return
122
+ }
123
+
124
+ let fileManager = FileManager.default
125
+ guard let attributes = try? fileManager.attributesOfItem(atPath: path) else {
126
+ call.reject("File not found")
127
+ return
128
+ }
129
+
130
+ let size = attributes[.size] as? Int64 ?? 0
131
+ let type = (try? attributes[.type] as? String) ?? "unknown"
132
+
133
+ call.resolve([
134
+ "size": size,
135
+ "type": type
136
+ ])
137
+ }
138
+ }
139
+
140
+ extension CapacitorDownloaderPlugin: URLSessionDownloadDelegate {
141
+ public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
142
+ guard let id = tasks.first(where: { $0.value == downloadTask })?.key,
143
+ let destinationURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent(id) else {
144
+ return
145
+ }
146
+
147
+ do {
148
+ try FileManager.default.moveItem(at: location, to: destinationURL)
149
+ notifyListeners("downloadCompleted", data: ["id": id])
150
+ } catch {
151
+ notifyListeners("downloadFailed", data: ["id": id, "error": error.localizedDescription])
152
+ }
153
+ }
154
+
155
+ public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
156
+ guard let downloadTask = task as? URLSessionDownloadTask,
157
+ let id = tasks.first(where: { $0.value == downloadTask })?.key else {
158
+ return
159
+ }
160
+
161
+ tasks.removeValue(forKey: id)
162
+
163
+ if let error = error {
164
+ notifyListeners("downloadFailed", data: ["id": id, "error": error.localizedDescription])
165
+ }
166
+ }
167
+
168
+ public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
169
+ guard let id = tasks.first(where: { $0.value == downloadTask })?.key else {
170
+ return
171
+ }
172
+
173
+ let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
174
+ notifyListeners("downloadProgress", data: ["id": id, "progress": progress])
175
+ }
176
+ }
@@ -0,0 +1,15 @@
1
+ import XCTest
2
+ @testable import CapacitorDownloaderPlugin
3
+
4
+ class CapacitorDownloaderTests: XCTestCase {
5
+ func testEcho() {
6
+ // This is an example of a functional test case for a plugin.
7
+ // Use XCTAssert and related functions to verify your tests produce the correct results.
8
+
9
+ let implementation = CapacitorDownloader()
10
+ let value = "Hello, World!"
11
+ let result = implementation.echo(value)
12
+
13
+ XCTAssertEqual(value, result)
14
+ }
15
+ }
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@capgo/capacitor-downloader",
3
+ "version": "0.0.2",
4
+ "description": "Download file in background or foreground",
5
+ "main": "dist/plugin.cjs.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
8
+ "unpkg": "dist/plugin.js",
9
+ "files": [
10
+ "android/src/main/",
11
+ "android/build.gradle",
12
+ "dist/",
13
+ "ios/Sources",
14
+ "ios/Tests",
15
+ "Package.swift",
16
+ "CapgoCapacitorDownloader.podspec"
17
+ ],
18
+ "author": "Martin Donadieu",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Cap-go/capacitor-downloader.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Cap-go/capacitor-downloader/issues"
26
+ },
27
+ "keywords": [
28
+ "capacitor",
29
+ "plugin",
30
+ "native"
31
+ ],
32
+ "scripts": {
33
+ "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
34
+ "verify:ios": "xcodebuild -scheme CapgoCapacitorDownloader -destination generic/platform=iOS",
35
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
36
+ "verify:web": "npm run build",
37
+ "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
38
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
39
+ "eslint": "eslint . --ext ts",
40
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
41
+ "swiftlint": "node-swiftlint",
42
+ "docgen": "docgen --api CapacitorDownloaderPlugin --output-readme README.md --output-json dist/docs.json",
43
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
44
+ "clean": "rimraf ./dist",
45
+ "watch": "tsc --watch",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "devDependencies": {
49
+ "@capacitor/android": "^6.0.0",
50
+ "@capacitor/core": "^6.0.0",
51
+ "@capacitor/docgen": "^0.2.2",
52
+ "@capacitor/ios": "^6.0.0",
53
+ "@ionic/eslint-config": "^0.4.0",
54
+ "@ionic/prettier-config": "^4.0.0",
55
+ "@ionic/swiftlint-config": "^2.0.0",
56
+ "eslint": "^8.57.0",
57
+ "prettier": "^3.3.3",
58
+ "prettier-plugin-java": "^2.6.4",
59
+ "rimraf": "^6.0.1",
60
+ "rollup": "^4.24.0",
61
+ "swiftlint": "^2.0.0",
62
+ "typescript": "~4.1.5"
63
+ },
64
+ "peerDependencies": {
65
+ "@capacitor/core": "^6.0.0"
66
+ },
67
+ "prettier": "@ionic/prettier-config",
68
+ "swiftlint": "@ionic/swiftlint-config",
69
+ "eslintConfig": {
70
+ "extends": "@ionic/eslint-config/recommended"
71
+ },
72
+ "capacitor": {
73
+ "ios": {
74
+ "src": "ios"
75
+ },
76
+ "android": {
77
+ "src": "android"
78
+ }
79
+ }
80
+ }