@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.
- package/CapgoCapacitorDownloader.podspec +17 -0
- package/Package.swift +30 -0
- package/README.md +206 -0
- package/android/build.gradle +57 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/ee/forgr/capacitor/plugin/downloader/CapacitorDownloaderPlugin.java +262 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +293 -0
- package/dist/esm/definitions.d.ts +39 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +13 -0
- package/dist/esm/web.js +28 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +42 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +45 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/CapacitorDownloaderPlugin/CapacitorDownloaderPlugin.swift +176 -0
- package/ios/Tests/CapacitorDownloaderPluginTests/CapacitorDownloaderPluginTests.swift +15 -0
- package/package.json +80 -0
|
@@ -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
|
+
}
|