mirror of
https://github.com/flutter/packages.git
synced 2025-06-25 10:04:21 +08:00
[file_selector] Endorse Android (#4329)
Endorses the new Android implementation of `file_selector`, updating the README accordingly. Also adjusts the example to better handle platform diffs, by hiding UI that doesn't work instead of just labelling it on the button. Left a TODO to improve how we determine what to hide once we have the API to do so. Fixes https://github.com/flutter/flutter/issues/110098
This commit is contained in:
11
.github/dependabot.yml
vendored
11
.github/dependabot.yml
vendored
@ -159,6 +159,17 @@ updates:
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-minor", "version-update:semver-patch"]
|
||||
|
||||
- package-ecosystem: "gradle"
|
||||
directory: "/packages/file_selector/file_selector/example/android/app"
|
||||
commit-message:
|
||||
prefix: "[file_selector]"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-minor", "version-update:semver-patch"]
|
||||
|
||||
- package-ecosystem: "gradle"
|
||||
directory: "/packages/file_selector/file_selector_android/android"
|
||||
commit-message:
|
||||
|
@ -53,6 +53,7 @@ packages/**/*_web/** @ditman
|
||||
packages/camera/camera_android/** @camsim99
|
||||
packages/camera/camera_android_camerax/** @camsim99
|
||||
packages/espresso/** @reidbaker
|
||||
packages/file_selector/file_selector_android/** @gmackall
|
||||
packages/flutter_plugin_android_lifecycle/** @reidbaker
|
||||
packages/google_maps_flutter/google_maps_flutter_android/** @reidbaker
|
||||
packages/google_sign_in/google_sign_in_android/** @camsim99
|
||||
|
@ -1,3 +1,7 @@
|
||||
## 0.9.5
|
||||
|
||||
* Adds an endorsed Android implementation.
|
||||
|
||||
## 0.9.4
|
||||
|
||||
* Adds `getSaveLocation` and deprecates `getSavePath`.
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
A Flutter plugin that manages files and interactions with file dialogs.
|
||||
|
||||
| | iOS | Linux | macOS | Web | Windows |
|
||||
|-------------|---------|-------|--------|-----|-------------|
|
||||
| **Support** | iOS 11+ | Any | 10.14+ | Any | Windows 10+ |
|
||||
| | Android | iOS | Linux | macOS | Web | Windows |
|
||||
|-------------|---------|---------|-------|--------|-----|-------------|
|
||||
| **Support** | SDK 19+ | iOS 11+ | Any | 10.14+ | Any | Windows 10+ |
|
||||
|
||||
## Usage
|
||||
|
||||
@ -100,23 +100,25 @@ Different platforms support different type group filter options. To avoid
|
||||
filters that cover all platforms you are targeting, or that you conditionally
|
||||
pass different `XTypeGroup`s based on `Platform`.
|
||||
|
||||
| | iOS | Linux | macOS | Web | Windows |
|
||||
|--------------------------|-----|-------|--------|-----|-------------|
|
||||
| `extensions` | | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| `mimeTypes` | | ✔️ | ✔️† | ✔️ | |
|
||||
| `uniformTypeIdentifiers` | ✔️ | | ✔️ | | |
|
||||
| `webWildCards` | | | | ✔️ | |
|
||||
| | Andoid | iOS | Linux | macOS | Web | Windows |
|
||||
|--------------------------|--------|-----|-------|--------|-----|-------------|
|
||||
| `extensions` | ✔️ | | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| `mimeTypes` | ✔️ | | ✔️ | ✔️† | ✔️ | |
|
||||
| `uniformTypeIdentifiers` | | ✔️ | | ✔️ | | |
|
||||
| `webWildCards` | | | | | ✔️ | |
|
||||
|
||||
† `mimeTypes` are not supported on version of macOS earlier than 11 (Big Sur).
|
||||
|
||||
### Features supported by platform
|
||||
|
||||
| Feature | Description | iOS | Linux | macOS | Windows | Web |
|
||||
| ---------------------- |----------------------------------- |--------- | ---------- | -------- | ------------ | ----------- |
|
||||
| Choose a single file | Pick a file/image | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| Choose multiple files | Pick multiple files/images | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| Choose a save location | Pick a directory to save a file in | ❌ | ✔️ | ✔️ | ✔️ | ❌ |
|
||||
| Choose a directory | Pick a folder and get its path | ❌ | ✔️ | ✔️ | ✔️ | ❌ |
|
||||
| Feature | Description | Android | iOS | Linux | macOS | Windows | Web |
|
||||
| ---------------------- |----------------------------------- |---------|--------- | ---------- | -------- | ------------ | ----------- |
|
||||
| Choose a single file | Pick a file/image | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| Choose multiple files | Pick multiple files/images | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| Choose a save location | Pick a directory to save a file in | ❌ | ❌ | ✔️ | ✔️ | ✔️ | ❌ |
|
||||
| Choose a directory | Pick a directory and get its path | ✔️† | ❌ | ✔️ | ✔️ | ✔️ | ❌ |
|
||||
|
||||
† Choosing a directory is no supported on versions of Android before SDK 21 (Lollipop).
|
||||
|
||||
[example]:./example
|
||||
[entitlement]: https://docs.flutter.dev/desktop#entitlements-and-the-app-sandbox
|
||||
|
13
packages/file_selector/file_selector/example/android/.gitignore
vendored
Normal file
13
packages/file_selector/file_selector/example/android/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
@ -0,0 +1,71 @@
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
if (flutterRoot == null) {
|
||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
namespace "dev.flutter.plugins.file_selector_example"
|
||||
compileSdkVersion flutter.compileSdkVersion
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "dev.flutter.plugins.file_selector_example"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion 19
|
||||
targetSdkVersion flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:label="file_selector_example"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,10 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package dev.flutter.plugins.file_selector_example
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
Binary file not shown.
After Width: | Height: | Size: 544 B |
Binary file not shown.
After Width: | Height: | Size: 442 B |
Binary file not shown.
After Width: | Height: | Size: 721 B |
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
@ -0,0 +1,31 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.buildDir = '../build'
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
tasks.register("clean", Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
|
@ -0,0 +1,11 @@
|
||||
include ':app'
|
||||
|
||||
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||
def properties = new Properties()
|
||||
|
||||
assert localPropertiesFile.exists()
|
||||
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
@ -50,7 +50,7 @@ class GetDirectoryPage extends StatelessWidget {
|
||||
),
|
||||
onPressed: _isIOS ? null : () => _getDirectoryPath(context),
|
||||
child: const Text(
|
||||
'Press to ask user to choose a directory (not supported on iOS).',
|
||||
'Press to ask user to choose a directory.',
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Home Page of the application
|
||||
@ -43,25 +46,33 @@ class HomePage extends StatelessWidget {
|
||||
child: const Text('Open multiple images'),
|
||||
onPressed: () => Navigator.pushNamed(context, '/open/images'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
style: style,
|
||||
child: const Text('Save a file'),
|
||||
onPressed: () => Navigator.pushNamed(context, '/save/text'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
style: style,
|
||||
child: const Text('Open a get directory dialog'),
|
||||
onPressed: () => Navigator.pushNamed(context, '/directory'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
style: style,
|
||||
child: const Text('Open a get multi directories dialog'),
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(context, '/multi-directories'),
|
||||
),
|
||||
// TODO(stuartmorgan): Replace these checks with support queries once
|
||||
// https://github.com/flutter/flutter/issues/127328 is implemented.
|
||||
if (kIsWeb || !(Platform.isAndroid || Platform.isIOS)) ...<Widget>[
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
style: style,
|
||||
child: const Text('Save a file'),
|
||||
onPressed: () => Navigator.pushNamed(context, '/save/text'),
|
||||
),
|
||||
],
|
||||
if (!(kIsWeb || Platform.isIOS)) ...<Widget>[
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
style: style,
|
||||
child: const Text('Open a get directory dialog'),
|
||||
onPressed: () => Navigator.pushNamed(context, '/directory'),
|
||||
),
|
||||
],
|
||||
if (!(kIsWeb || Platform.isAndroid || Platform.isIOS)) ...<Widget>[
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
style: style,
|
||||
child: const Text('Open a get multi directories dialog'),
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(context, '/multi-directories'),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:file_selector/file_selector.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
@ -19,8 +20,8 @@ class OpenTextPage extends StatelessWidget {
|
||||
// This demonstrates using an initial directory for the prompt, which should
|
||||
// only be done in cases where the application can likely predict where the
|
||||
// file would be. In most cases, this parameter should not be provided.
|
||||
final String initialDirectory =
|
||||
(await getApplicationDocumentsDirectory()).path;
|
||||
final String? initialDirectory =
|
||||
kIsWeb ? null : (await getApplicationDocumentsDirectory()).path;
|
||||
final XFile? file = await openFile(
|
||||
acceptedTypeGroups: <XTypeGroup>[typeGroup],
|
||||
initialDirectory: initialDirectory,
|
||||
|
@ -85,7 +85,7 @@ class SaveTextPage extends StatelessWidget {
|
||||
),
|
||||
onPressed: _isIOS ? null : () => _saveFile(),
|
||||
child: const Text(
|
||||
'Press to save a text file (not supported on iOS).',
|
||||
'Press to save a text file.',
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -3,7 +3,7 @@ description: Flutter plugin for opening and saving files, or selecting
|
||||
directories, using native file selection UI.
|
||||
repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector
|
||||
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
|
||||
version: 0.9.4
|
||||
version: 0.9.5
|
||||
|
||||
environment:
|
||||
sdk: ">=2.18.0 <4.0.0"
|
||||
@ -12,6 +12,8 @@ environment:
|
||||
flutter:
|
||||
plugin:
|
||||
platforms:
|
||||
android:
|
||||
default_package: file_selector_android
|
||||
ios:
|
||||
default_package: file_selector_ios
|
||||
linux:
|
||||
@ -24,6 +26,7 @@ flutter:
|
||||
default_package: file_selector_windows
|
||||
|
||||
dependencies:
|
||||
file_selector_android: ^0.5.0
|
||||
file_selector_ios: ^0.5.0
|
||||
file_selector_linux: ^0.9.2
|
||||
file_selector_macos: ^0.9.3
|
||||
|
@ -1 +1,2 @@
|
||||
[]
|
||||
# Can't use Flutter integration tests due to native modal UI.
|
||||
- file_selector
|
||||
|
Reference in New Issue
Block a user