Skip to content

feat: Add mobile support and update example project #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 14, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "tauri-plugin-download"
version = "0.1.0"
authors = [ "You" ]
version = "1.0.0"
authors = [ "Jeremy Thomerson" ]
description = ""
edition = "2021"
rust-version = "1.77.2"
@@ -17,7 +17,7 @@ tauri-plugin-http = "2.3.0"
tauri-plugin-store = "2.2.0"
tauri-plugin-upload = "2.2.0"
thiserror = "2"
tokio = "1.43.0"
tokio = "1.44.2"

[build-dependencies]
serde = { version = "1.0", features = ["derive"] }
133 changes: 129 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# tauri-plugin-download

State-driven, resumable download API.
State-driven, resumable download API for Tauri 2.x apps.

* Parallel, resumable download support
* Persistable, thread-safe store
* State and progress notifications
* Cross-platform support (Linux, Windows, macOS, Android, iOS)

| Platform | Supported |
| -------- | --------- |
@@ -10,10 +15,130 @@ State-driven, resumable download API.
| Android | ✓ |
| iOS | ✓ |

## Contributing
## Installation

Note: These steps are an interim workaround until the plugin is published.

### Rust

Add the `tauri-plugin-download` crate to your `Cargo.toml`:

```toml
[dependencies]
tauri-plugin-download = { git = "https://github.com/silvermine/tauri-plugin-download.git" }
```

### TypeScript

Install the TypeScript bindings via npm:

```bash
npm install github:@silvermine/tauri-plugin-download
```

## Usage

### Prerequisites

Initialize the plugin in your `tauri::Builder`:

```rust
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_download::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```

### API

#### Create a download

```ts
import { create } from 'tauri-plugin-download';

async function createDownload() {
const key = 'file.zip',
url = 'https://example.com/file.zip',
path = await join(await appDataDir(), 'downloads', key);

const download = await create(key, url, path);

console.debug(`Created '${download.key}':${download.url}`);
}
```

#### List downloads

```ts
import { list } from 'tauri-plugin-download';

async function listDownloads() {
const downloads = await list();

for (let download of downloads) {
console.debug(`Found '${download.key}':${download.url} [${download.state}, ${download.progress}%]`)
}
}
```

#### Get a download

```ts
import { get } from 'tauri-plugin-download';

async function getDownload() {
const download = await get('file.zip');

console.debug(`Found '${download.key}':${download.url} [${download.state}, ${download.progress}%]`)
}
```

#### Start, pause, resume or cancel a download

```ts
import { get } from 'tauri-plugin-download';

async function getDownloadAndUpdate() {
const download = await get('file.zip');

download.start();
download.pause();
download.resume();
download.cancel();
}
```

#### Listen for progress notifications

```ts
import { get } from 'tauri-plugin-download';

async function getDownloadAndListen() {
const download = await get('file.zip');

const unlisten = await download.listen((updatedDownload) => {
console.debug(`'${updatedDownload.key}':${updatedDownload.progress}%`);
});

// To stop listening
unlisten();
}
```

### Examples

Check out the [examples/tauri-app](examples/tauri-app) directory for a working example of
how to use this plugin.

## How do I contribute?

PRs accepted. Please read the Contributing Guide before making a pull request.
We genuinely appreciate external contributions. See [our extensive
documentation](https://github.com/silvermine/silvermine-info#contributing) on how to
contribute.

## License

MIT or MIT/Apache 2.0 where applicable.
This software is released under the MIT license. See [the license file](LICENSE) for more
details.
9 changes: 4 additions & 5 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const COMMANDS: &[&str] = &["create", "list", "get", "start", "cancel", "pause", "resume"];
const COMMANDS: &[&str] = &[
"create", "list", "get", "start", "cancel", "pause", "resume",
];

fn main() {
tauri_plugin::Builder::new(COMMANDS)
.android_path("android")
.ios_path("ios")
.build();
tauri_plugin::Builder::new(COMMANDS).build();
}
2 changes: 1 addition & 1 deletion examples/tauri-app/package.json
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
"dependencies": {
"vue": "^3.5.13",
"@tauri-apps/api": "^2",
"tauri-plugin-download-api": "file:../../"
"tauri-plugin-download": "file:../../"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
12 changes: 12 additions & 0 deletions examples/tauri-app/src-tauri/gen/android/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false
19 changes: 19 additions & 0 deletions examples/tauri-app/src-tauri/gen/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
build
/captures
.externalNativeBuild
.cxx
local.properties
key.properties

/.tauri
/tauri.settings.gradle
6 changes: 6 additions & 0 deletions examples/tauri-app/src-tauri/gen/android/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/src/main/java/com/tauri_app/app/generated
/src/main/jniLibs/**/*.so
/src/main/assets/tauri.conf.json
/tauri.build.gradle.kts
/proguard-tauri.pro
/tauri.properties
69 changes: 69 additions & 0 deletions examples/tauri-app/src-tauri/gen/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import java.util.Properties

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("rust")
}

val tauriProperties = Properties().apply {
val propFile = file("tauri.properties")
if (propFile.exists()) {
propFile.inputStream().use { load(it) }
}
}

android {
compileSdk = 34
namespace = "com.tauri_app.app"
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.tauri_app.app"
minSdk = 24
targetSdk = 34
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
}
buildTypes {
getByName("debug") {
manifestPlaceholders["usesCleartextTraffic"] = "true"
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
getByName("release") {
isMinifyEnabled = true
proguardFiles(
*fileTree(".") { include("**/*.pro") }
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
.toList().toTypedArray()
)
}
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
buildConfig = true
}
}

rust {
rootDirRel = "../../../"
}

dependencies {
implementation("androidx.webkit:webkit:1.6.1")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.8.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
}

apply(from = "tauri.build.gradle.kts")
21 changes: 21 additions & 0 deletions examples/tauri-app/src-tauri/gen/android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />

<!-- AndroidTV support -->
<uses-feature android:name="android.software.leanback" android:required="false" />

<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.tauri_app"
android:usesCleartextTraffic="${usesCleartextTraffic}">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:launchMode="singleTask"
android:label="@string/main_activity_title"
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- AndroidTV support -->
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.tauri_app.app

class MainActivity : TauriActivity()
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
Loading