Skip to content
Merged
Show file tree
Hide file tree
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
15 changes: 15 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
on:
push:
branches:
- release

jobs:
publish:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1

- name: Run Pub Publish
run: dart pub publish
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
.history
.svn/

*/**/pubspec.lock

# IntelliJ related
*.iml
*.ipr
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.2.0

Add basic support for `Storage Access Framework` and `targetSdk 31`

- The package now supports basic intents from `Storage Access Framework`
- Your App needs update the `build.gradle` by targeting the current sdk to `31`

## 0.1.1

Minor improvements on `pub.dev` documentation
Expand Down
61 changes: 53 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Plugin to fetch Android shared storage/folders info
- _**Android Only**_
- _**Alpha version**_
- _**Supports Android 4.1+ (API Level 16+)**_
- _**The `targetSdk` should be set to `31`**_

### Features

Expand All @@ -19,8 +20,8 @@ This plugin allow us to get path of top-level shared folder (Downloads, DCIM, Vi
```dart
/// Get Android [downloads] top-level shared folder
/// You can also create a reference to a custom directory as: `EnvironmentDirectory.custom('Custom Folder')`
final sharedDirectory =
await getExternalStoragePublicDirectory(EnvironmentDirectory.downloads);
final sharedDirectory =
await getExternalStoragePublicDirectory(EnvironmentDirectory.downloads);

print(sharedDirectory.path); /// `/storage/emulated/0/Download`
```
Expand All @@ -29,26 +30,70 @@ print(sharedDirectory.path); /// `/storage/emulated/0/Download`

```dart
/// Get Android [downloads] shared folder for Android 9+
final sharedDirectory =
final sharedDirectory =
await getMediaStoreContentDirectory(MediaStoreCollection.downloads);

print(sharedDirectory.path); /// `/external/downloads`
```

- Get root Android path, note that is a read-only folder
- Start `OPEN_DOCUMENT_TREE` activity to prompt user to select an folder to enable write and read access to be used by the `Storage Access Framework` API

```dart
/// Get Android root folder
final sharedDirectory = await getRootDirectory();
/// Get permissions to manage an Android directory
final selectedUriDir = await openDocumentTree();

print(sharedDirectory.path); /// `/system`
print(selectedUriDir);
```

- Create a new file using the `SAF` API

```dart
/// Create a new file using the `SAF` API
final newDocumentFile = await createDocumentFile(
mimeType: ' text/plain',
content: 'My Plain Text Comment Created by shared_storage plugin',
displayName: 'CreatedBySharedStorageFlutterPlugin',
directory: anySelectedUriByTheOpenDocumentTreeAPI,
);

print(newDocumentFile);
```

- Get all persisted [URI]s by the `openDocumentTree` API, from `SAF` API

```dart
/// You have [write] and [read] access to all persisted [URI]s
final listOfPersistedUris = await persistedUriPermissions();

print(listOfPersistedUris);
```

- Revoke a current persisted [URI], from `SAF` API

```dart
/// Can be any [URI] returned by the `persistedUriPermissions`
final uri = ...;

/// After calling this, you no longer has access to the [uri]
await releasePersistableUriPermission(uri);
```

- Convenient method to know if a given [uri] is a persisted `uri` ("persisted uri" means that you have `write` and `read` access to the `uri` even if devices reboot)

```dart
/// Can be any [URI], but the method will only return [true] if the [uri]
/// is also present in the list returned by `persistedUriPermissions`
final uri = ...;

/// Verify if you have [write] and [read] access to a given [uri]
final isPersisted = await isPersistedUri(uri);
```

### Android API's

Most Flutter plugins uses Android API's under the hood. So this plugin do the same, and to retrieve Android shared folder paths the following API's are being used:

[`🔗 android.os.Environment`](https://developer.android.com/reference/android/os/Environment#summary) [`🔗 android.provider.MediaStore`](https://developer.android.com/reference/android/provider/MediaStore#summary)
[`🔗android.os.Environment`](https://developer.android.com/reference/android/os/Environment#summary) [`🔗android.provider.MediaStore`](https://developer.android.com/reference/android/provider/MediaStore#summary) [`🔗android.provider.DocumentsProvider`](https://developer.android.com/guide/topics/providers/document-provider)

<br>

Expand Down
3 changes: 2 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
group 'com.pinciat.external_path'
group 'io.lakscastro.sharedstorage'
version '1.0-SNAPSHOT'

buildscript {
Expand Down Expand Up @@ -37,4 +37,5 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.documentfile:documentfile:1.0.1"
}
2 changes: 1 addition & 1 deletion android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rootProject.name = 'external_path'
rootProject.name = 'sharedstorage'
2 changes: 1 addition & 1 deletion android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pinciat.external_path">
package="io.lakscastro.sharedstorage">
</manifest>
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.lakscastro.sharedstorage

import android.os.Environment
import java.io.File

fun environmentDirectoryOf(directory: String): String {
fun environmentDirectoryOf(directory: String): File {
val mapper = mapOf(
"EnvironmentDirectory.Alarms" to Environment.DIRECTORY_ALARMS,
"EnvironmentDirectory.DCIM" to Environment.DIRECTORY_DCIM,
Expand All @@ -15,5 +16,5 @@ fun environmentDirectoryOf(directory: String): String {
"EnvironmentDirectory.Ringtones" to Environment.DIRECTORY_RINGTONES
)

return mapper[directory] ?: directory
return Environment.getExternalStoragePublicDirectory(mapper[directory] ?: directory)
}
Loading