@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,17 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'CapgoCapacitorDownloader'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.homepage = package['repository']['url']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
+
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.ios.deployment_target = '13.0'
|
|
15
|
+
s.dependency 'Capacitor'
|
|
16
|
+
s.swift_version = '5.1'
|
|
17
|
+
end
|
package/Package.swift
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "CapgoCapacitorDownloader",
|
|
6
|
+
platforms: [.iOS(.v13)],
|
|
7
|
+
products: [
|
|
8
|
+
.library(
|
|
9
|
+
name: "CapgoCapacitorDownloader",
|
|
10
|
+
targets: ["CapacitorDownloaderPlugin"])
|
|
11
|
+
],
|
|
12
|
+
dependencies: [
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", branch: "main"),
|
|
14
|
+
.package(url: "https://github.com/mzeeshanid/MZDownloadManager.git", from: "3.3.0")
|
|
15
|
+
],
|
|
16
|
+
targets: [
|
|
17
|
+
.target(
|
|
18
|
+
name: "CapacitorDownloaderPlugin",
|
|
19
|
+
dependencies: [
|
|
20
|
+
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
21
|
+
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
|
22
|
+
"MZDownloadManager"
|
|
23
|
+
],
|
|
24
|
+
path: "ios/Sources/CapacitorDownloaderPlugin"),
|
|
25
|
+
.testTarget(
|
|
26
|
+
name: "CapacitorDownloaderPluginTests",
|
|
27
|
+
dependencies: ["CapacitorDownloaderPlugin"],
|
|
28
|
+
path: "ios/Tests/CapacitorDownloaderPluginTests")
|
|
29
|
+
]
|
|
30
|
+
)
|
package/README.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# @capgo/capacitor-downloader
|
|
2
|
+
|
|
3
|
+
Download file in background or foreground
|
|
4
|
+
|
|
5
|
+
WIP: the plugin is not yet ready for production
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @capgo/capacitor-downloader
|
|
11
|
+
npx cap sync
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## API
|
|
15
|
+
|
|
16
|
+
<docgen-index>
|
|
17
|
+
|
|
18
|
+
* [`download(...)`](#download)
|
|
19
|
+
* [`pause(...)`](#pause)
|
|
20
|
+
* [`resume(...)`](#resume)
|
|
21
|
+
* [`stop(...)`](#stop)
|
|
22
|
+
* [`checkStatus(...)`](#checkstatus)
|
|
23
|
+
* [`getFileInfo(...)`](#getfileinfo)
|
|
24
|
+
* [`addListener('downloadProgress', ...)`](#addlistenerdownloadprogress-)
|
|
25
|
+
* [`addListener('downloadCompleted', ...)`](#addlistenerdownloadcompleted-)
|
|
26
|
+
* [`addListener('downloadFailed', ...)`](#addlistenerdownloadfailed-)
|
|
27
|
+
* [`removeAllListeners()`](#removealllisteners)
|
|
28
|
+
* [Interfaces](#interfaces)
|
|
29
|
+
|
|
30
|
+
</docgen-index>
|
|
31
|
+
|
|
32
|
+
<docgen-api>
|
|
33
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
34
|
+
|
|
35
|
+
### download(...)
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
download(options: DownloadOptions) => Promise<DownloadTask>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| Param | Type |
|
|
42
|
+
| ------------- | ----------------------------------------------------------- |
|
|
43
|
+
| **`options`** | <code><a href="#downloadoptions">DownloadOptions</a></code> |
|
|
44
|
+
|
|
45
|
+
**Returns:** <code>Promise<<a href="#downloadtask">DownloadTask</a>></code>
|
|
46
|
+
|
|
47
|
+
--------------------
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### pause(...)
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
pause(id: string) => Promise<void>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
| Param | Type |
|
|
57
|
+
| -------- | ------------------- |
|
|
58
|
+
| **`id`** | <code>string</code> |
|
|
59
|
+
|
|
60
|
+
--------------------
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
### resume(...)
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
resume(id: string) => Promise<void>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
| Param | Type |
|
|
70
|
+
| -------- | ------------------- |
|
|
71
|
+
| **`id`** | <code>string</code> |
|
|
72
|
+
|
|
73
|
+
--------------------
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
### stop(...)
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
stop(id: string) => Promise<void>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
| Param | Type |
|
|
83
|
+
| -------- | ------------------- |
|
|
84
|
+
| **`id`** | <code>string</code> |
|
|
85
|
+
|
|
86
|
+
--------------------
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
### checkStatus(...)
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
checkStatus(id: string) => Promise<DownloadTask>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Param | Type |
|
|
96
|
+
| -------- | ------------------- |
|
|
97
|
+
| **`id`** | <code>string</code> |
|
|
98
|
+
|
|
99
|
+
**Returns:** <code>Promise<<a href="#downloadtask">DownloadTask</a>></code>
|
|
100
|
+
|
|
101
|
+
--------------------
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
### getFileInfo(...)
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
getFileInfo(path: string) => Promise<{ size: number; type: string; }>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
| Param | Type |
|
|
111
|
+
| ---------- | ------------------- |
|
|
112
|
+
| **`path`** | <code>string</code> |
|
|
113
|
+
|
|
114
|
+
**Returns:** <code>Promise<{ size: number; type: string; }></code>
|
|
115
|
+
|
|
116
|
+
--------------------
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
### addListener('downloadProgress', ...)
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
addListener(eventName: 'downloadProgress', listenerFunc: (progress: { id: string; progress: number; }) => void) => Promise<PluginListenerHandle>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
| Param | Type |
|
|
126
|
+
| ------------------ | --------------------------------------------------------------------- |
|
|
127
|
+
| **`eventName`** | <code>'downloadProgress'</code> |
|
|
128
|
+
| **`listenerFunc`** | <code>(progress: { id: string; progress: number; }) => void</code> |
|
|
129
|
+
|
|
130
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
131
|
+
|
|
132
|
+
--------------------
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
### addListener('downloadCompleted', ...)
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
addListener(eventName: 'downloadCompleted', listenerFunc: (result: { id: string; }) => void) => Promise<PluginListenerHandle>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
| Param | Type |
|
|
142
|
+
| ------------------ | ------------------------------------------------- |
|
|
143
|
+
| **`eventName`** | <code>'downloadCompleted'</code> |
|
|
144
|
+
| **`listenerFunc`** | <code>(result: { id: string; }) => void</code> |
|
|
145
|
+
|
|
146
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
147
|
+
|
|
148
|
+
--------------------
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
### addListener('downloadFailed', ...)
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
addListener(eventName: 'downloadFailed', listenerFunc: (error: { id: string; error: string; }) => void) => Promise<PluginListenerHandle>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| Param | Type |
|
|
158
|
+
| ------------------ | --------------------------------------------------------------- |
|
|
159
|
+
| **`eventName`** | <code>'downloadFailed'</code> |
|
|
160
|
+
| **`listenerFunc`** | <code>(error: { id: string; error: string; }) => void</code> |
|
|
161
|
+
|
|
162
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
163
|
+
|
|
164
|
+
--------------------
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
### removeAllListeners()
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
removeAllListeners() => Promise<void>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
--------------------
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
### Interfaces
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
#### DownloadTask
|
|
180
|
+
|
|
181
|
+
| Prop | Type |
|
|
182
|
+
| -------------- | -------------------------------------------------------------------- |
|
|
183
|
+
| **`id`** | <code>string</code> |
|
|
184
|
+
| **`progress`** | <code>number</code> |
|
|
185
|
+
| **`state`** | <code>'PENDING' \| 'RUNNING' \| 'PAUSED' \| 'DONE' \| 'ERROR'</code> |
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
#### DownloadOptions
|
|
189
|
+
|
|
190
|
+
| Prop | Type |
|
|
191
|
+
| ----------------- | ---------------------------------------- |
|
|
192
|
+
| **`id`** | <code>string</code> |
|
|
193
|
+
| **`url`** | <code>string</code> |
|
|
194
|
+
| **`destination`** | <code>string</code> |
|
|
195
|
+
| **`headers`** | <code>{ [key: string]: string; }</code> |
|
|
196
|
+
| **`network`** | <code>'cellular' \| 'wifi-only'</code> |
|
|
197
|
+
| **`priority`** | <code>'high' \| 'normal' \| 'low'</code> |
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
#### PluginListenerHandle
|
|
201
|
+
|
|
202
|
+
| Prop | Type |
|
|
203
|
+
| ------------ | ----------------------------------------- |
|
|
204
|
+
| **`remove`** | <code>() => Promise<void></code> |
|
|
205
|
+
|
|
206
|
+
</docgen-api>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
ext {
|
|
2
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
3
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
|
|
4
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5'
|
|
5
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
buildscript {
|
|
9
|
+
repositories {
|
|
10
|
+
google()
|
|
11
|
+
mavenCentral()
|
|
12
|
+
}
|
|
13
|
+
dependencies {
|
|
14
|
+
classpath 'com.android.tools.build:gradle:8.2.1'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
apply plugin: 'com.android.library'
|
|
19
|
+
|
|
20
|
+
android {
|
|
21
|
+
namespace "ee.forgr.capacitor.plugin.downloader"
|
|
22
|
+
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
|
|
23
|
+
defaultConfig {
|
|
24
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
|
|
25
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34
|
|
26
|
+
versionCode 1
|
|
27
|
+
versionName "1.0"
|
|
28
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
29
|
+
}
|
|
30
|
+
buildTypes {
|
|
31
|
+
release {
|
|
32
|
+
minifyEnabled false
|
|
33
|
+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
lintOptions {
|
|
37
|
+
abortOnError false
|
|
38
|
+
}
|
|
39
|
+
compileOptions {
|
|
40
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
41
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
repositories {
|
|
46
|
+
google()
|
|
47
|
+
mavenCentral()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
dependencies {
|
|
51
|
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
52
|
+
implementation project(':capacitor-android')
|
|
53
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
54
|
+
testImplementation "junit:junit:$junitVersion"
|
|
55
|
+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
56
|
+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
57
|
+
}
|
package/android/src/main/java/ee/forgr/capacitor/plugin/downloader/CapacitorDownloaderPlugin.java
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
package ee.forgr.capacitor.plugin.downloader;
|
|
2
|
+
|
|
3
|
+
import android.app.DownloadManager;
|
|
4
|
+
import android.content.BroadcastReceiver;
|
|
5
|
+
import android.content.Context;
|
|
6
|
+
import android.content.Intent;
|
|
7
|
+
import android.content.IntentFilter;
|
|
8
|
+
import android.database.Cursor;
|
|
9
|
+
import android.net.Uri;
|
|
10
|
+
import android.os.Handler;
|
|
11
|
+
import android.os.Looper;
|
|
12
|
+
|
|
13
|
+
import com.getcapacitor.JSObject;
|
|
14
|
+
import com.getcapacitor.Plugin;
|
|
15
|
+
import com.getcapacitor.PluginCall;
|
|
16
|
+
import com.getcapacitor.PluginMethod;
|
|
17
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
18
|
+
|
|
19
|
+
import java.io.File;
|
|
20
|
+
import java.util.HashMap;
|
|
21
|
+
import java.util.Iterator;
|
|
22
|
+
import java.util.Map;
|
|
23
|
+
|
|
24
|
+
@CapacitorPlugin(name = "CapacitorDownloader")
|
|
25
|
+
public class CapacitorDownloaderPlugin extends Plugin {
|
|
26
|
+
|
|
27
|
+
private DownloadManager downloadManager;
|
|
28
|
+
private final Map<String, Long> downloads = new HashMap<>();
|
|
29
|
+
private final Handler handler = new Handler(Looper.getMainLooper());
|
|
30
|
+
private BroadcastReceiver downloadReceiver;
|
|
31
|
+
|
|
32
|
+
@Override
|
|
33
|
+
public void load() {
|
|
34
|
+
downloadManager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE);
|
|
35
|
+
registerDownloadReceiver();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private void registerDownloadReceiver() {
|
|
39
|
+
downloadReceiver = new BroadcastReceiver() {
|
|
40
|
+
@Override
|
|
41
|
+
public void onReceive(Context context, Intent intent) {
|
|
42
|
+
long receivedDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
|
|
43
|
+
String downloadId = getDownloadIdByValue(receivedDownloadId);
|
|
44
|
+
if (downloadId != null) {
|
|
45
|
+
checkDownloadStatus(downloadId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
getContext().registerReceiver(downloadReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private String getDownloadIdByValue(long value) {
|
|
53
|
+
for (Map.Entry<String, Long> entry : downloads.entrySet()) {
|
|
54
|
+
if (entry.getValue() == value) {
|
|
55
|
+
return entry.getKey();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@PluginMethod
|
|
62
|
+
public void download(PluginCall call) {
|
|
63
|
+
String id = call.getString("id");
|
|
64
|
+
String url = call.getString("url");
|
|
65
|
+
String destination = call.getString("destination");
|
|
66
|
+
|
|
67
|
+
if (id == null || url == null || destination == null) {
|
|
68
|
+
call.reject("Missing required parameters");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url))
|
|
73
|
+
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
|
74
|
+
.setAllowedOverMetered(true)
|
|
75
|
+
.setAllowedOverRoaming(true);
|
|
76
|
+
|
|
77
|
+
// Handle custom destination
|
|
78
|
+
File destinationFile = new File(getContext().getExternalFilesDir(null), destination);
|
|
79
|
+
Uri destinationUri = Uri.fromFile(destinationFile);
|
|
80
|
+
request.setDestinationUri(destinationUri);
|
|
81
|
+
|
|
82
|
+
JSObject headers = call.getObject("headers");
|
|
83
|
+
if (headers != null) {
|
|
84
|
+
for (Iterator<String> it = headers.keys(); it.hasNext(); ) {
|
|
85
|
+
String key = it.next();
|
|
86
|
+
request.addRequestHeader(key, headers.getString(key));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
String network = call.getString("network");
|
|
91
|
+
if ("wifi-only".equals(network)) {
|
|
92
|
+
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
|
|
93
|
+
} else {
|
|
94
|
+
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
long downloadId = downloadManager.enqueue(request);
|
|
98
|
+
downloads.put(id, downloadId);
|
|
99
|
+
|
|
100
|
+
JSObject result = new JSObject();
|
|
101
|
+
result.put("id", id);
|
|
102
|
+
result.put("status", DownloadManager.STATUS_PENDING);
|
|
103
|
+
call.resolve(result);
|
|
104
|
+
|
|
105
|
+
// Start a periodic progress check
|
|
106
|
+
startProgressCheck(id, downloadId);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private void startProgressCheck(final String id, final long downloadId) {
|
|
110
|
+
handler.post(new Runnable() {
|
|
111
|
+
@Override
|
|
112
|
+
public void run() {
|
|
113
|
+
if (checkDownloadStatus(id)) {
|
|
114
|
+
handler.postDelayed(this, 1000); // Check every second
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private boolean checkDownloadStatus(String id) {
|
|
121
|
+
DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloads.get(id));
|
|
122
|
+
try (Cursor cursor = downloadManager.query(query)) {
|
|
123
|
+
if (cursor.moveToFirst()) {
|
|
124
|
+
int status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));
|
|
125
|
+
long bytesDownloaded = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
|
|
126
|
+
long bytesTotal = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
|
|
127
|
+
|
|
128
|
+
float progress = bytesTotal > 0 ? (float) bytesDownloaded / bytesTotal : 0f;
|
|
129
|
+
|
|
130
|
+
JSObject progressData = new JSObject();
|
|
131
|
+
progressData.put("id", id);
|
|
132
|
+
progressData.put("progress", progress);
|
|
133
|
+
notifyListeners("downloadProgress", progressData);
|
|
134
|
+
|
|
135
|
+
if (status == DownloadManager.STATUS_SUCCESSFUL) {
|
|
136
|
+
JSObject completedData = new JSObject();
|
|
137
|
+
completedData.put("id", id);
|
|
138
|
+
notifyListeners("downloadCompleted", completedData);
|
|
139
|
+
return false; // Stop checking progress
|
|
140
|
+
} else if (status == DownloadManager.STATUS_FAILED) {
|
|
141
|
+
JSObject failedData = new JSObject();
|
|
142
|
+
failedData.put("id", id);
|
|
143
|
+
failedData.put("error", "Download failed");
|
|
144
|
+
notifyListeners("downloadFailed", failedData);
|
|
145
|
+
return false; // Stop checking progress
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return true; // Continue checking progress
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@PluginMethod
|
|
153
|
+
public void pause(PluginCall call) {
|
|
154
|
+
// DownloadManager doesn't support pausing individual downloads
|
|
155
|
+
call.reject("Pausing individual downloads is not supported on Android");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@PluginMethod
|
|
159
|
+
public void resume(PluginCall call) {
|
|
160
|
+
// DownloadManager doesn't support resuming individual downloads
|
|
161
|
+
call.reject("Resuming individual downloads is not supported on Android");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@PluginMethod
|
|
165
|
+
public void stop(PluginCall call) {
|
|
166
|
+
String id = call.getString("id");
|
|
167
|
+
if (id == null || !downloads.containsKey(id)) {
|
|
168
|
+
call.reject("Download not found");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
int removedDownloads = downloadManager.remove(downloads.get(id));
|
|
172
|
+
downloads.remove(id);
|
|
173
|
+
call.resolve(new JSObject().put("removed", removedDownloads > 0));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@PluginMethod
|
|
177
|
+
public void checkStatus(PluginCall call) {
|
|
178
|
+
String id = call.getString("id");
|
|
179
|
+
if (id == null || !downloads.containsKey(id)) {
|
|
180
|
+
call.reject("Download not found");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloads.get(id));
|
|
185
|
+
try (Cursor cursor = downloadManager.query(query)) {
|
|
186
|
+
if (cursor.moveToFirst()) {
|
|
187
|
+
JSObject result = getDownloadStatus(cursor);
|
|
188
|
+
call.resolve(result);
|
|
189
|
+
} else {
|
|
190
|
+
call.reject("Download not found");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private JSObject getDownloadStatus(Cursor cursor) {
|
|
196
|
+
int status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));
|
|
197
|
+
long bytesDownloaded = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
|
|
198
|
+
long bytesTotal = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
|
|
199
|
+
|
|
200
|
+
JSObject result = new JSObject();
|
|
201
|
+
result.put("status", status);
|
|
202
|
+
result.put("bytesDownloaded", bytesDownloaded);
|
|
203
|
+
result.put("bytesTotal", bytesTotal);
|
|
204
|
+
|
|
205
|
+
if (status == DownloadManager.STATUS_FAILED) {
|
|
206
|
+
int reason = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON));
|
|
207
|
+
result.put("reason", reason);
|
|
208
|
+
result.put("reasonText", getReasonText(status, reason));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private String getReasonText(int status, int reason) {
|
|
215
|
+
if (status == DownloadManager.STATUS_FAILED) {
|
|
216
|
+
switch (reason) {
|
|
217
|
+
case DownloadManager.ERROR_CANNOT_RESUME:
|
|
218
|
+
return "ERROR_CANNOT_RESUME";
|
|
219
|
+
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
|
|
220
|
+
return "ERROR_DEVICE_NOT_FOUND";
|
|
221
|
+
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
|
|
222
|
+
return "ERROR_FILE_ALREADY_EXISTS";
|
|
223
|
+
case DownloadManager.ERROR_FILE_ERROR:
|
|
224
|
+
return "ERROR_FILE_ERROR";
|
|
225
|
+
case DownloadManager.ERROR_HTTP_DATA_ERROR:
|
|
226
|
+
return "ERROR_HTTP_DATA_ERROR";
|
|
227
|
+
case DownloadManager.ERROR_INSUFFICIENT_SPACE:
|
|
228
|
+
return "ERROR_INSUFFICIENT_SPACE";
|
|
229
|
+
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
|
|
230
|
+
return "ERROR_TOO_MANY_REDIRECTS";
|
|
231
|
+
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
|
|
232
|
+
return "ERROR_UNHANDLED_HTTP_CODE";
|
|
233
|
+
default:
|
|
234
|
+
return "ERROR_UNKNOWN";
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return "UNKNOWN";
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@PluginMethod
|
|
241
|
+
public void getFileInfo(PluginCall call) {
|
|
242
|
+
String path = call.getString("path");
|
|
243
|
+
if (path == null) {
|
|
244
|
+
call.reject("Missing path");
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
Uri fileUri = Uri.parse(path);
|
|
249
|
+
JSObject result = new JSObject();
|
|
250
|
+
result.put("size", fileUri.getPath() != null ? new java.io.File(fileUri.getPath()).length() : 0);
|
|
251
|
+
result.put("type", getContext().getContentResolver().getType(fileUri));
|
|
252
|
+
call.resolve(result);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@Override
|
|
256
|
+
protected void handleOnDestroy() {
|
|
257
|
+
super.handleOnDestroy();
|
|
258
|
+
if (downloadReceiver != null) {
|
|
259
|
+
getContext().unregisterReceiver(downloadReceiver);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
File without changes
|