[Bug]: File name converted to UUID with "octet-stream" as extension when using a temporary file
Platform
Android 13
Plugin
share_plus
Version
6.3.1
Flutter SDK
3.9.0-0.2.pre
Steps to reproduce
- Create a temporary file
- Share it using
shareXFiles
The example project works fine, but temporary files do not work. @Coronon this is related to #914
https://user-images.githubusercontent.com/50424412/227925332-afcd3320-f40e-4b34-bcfa-8bd686c84017.mp4
Code Sample
await Share.shareXFiles(
[
XFile.fromData(
const Utf8Encoder().convert("test"),
name: "viewkey.json",
);
],
text: "View key",
subject: "Here's my View Key to see my location",
);
Here's the full Flutter code (ready to be copy-pasted):
```dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:share_plus/share_plus.dart';
void main() {
runApp(const DemoApp());
}
class DemoApp extends StatefulWidget {
const DemoApp({Key? key}) : super(key: key);
@override
DemoAppState createState() => DemoAppState();
}
class DemoAppState extends State<DemoApp> {
String text = '';
String subject = '';
List<String> imageNames = [];
List<String> imagePaths = [];
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Share Plus Plugin Demo',
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: const Color(0x9f4376f8),
),
home: Scaffold(
appBar: AppBar(
title: const Text('Share Plus Plugin Demo'),
elevation: 4,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ElevatedButton(
onPressed: () async {
await Share.shareXFiles([
XFile.fromData(
const Utf8Encoder().convert("test"),
name: "viewkey.json",
)],
text: "View key",
subject: "Here's my View Key to see my location",
);
},
child: const Text('Share'),
),
],
),
),
),
);
}
}
### Logs
```shell
The only log generated when calling this function is this:
[+5894 ms] D/DecorView[](24650): onWindowFocusChanged hasWindowFocus false
### Flutter Doctor
```shell
[✓] Flutter (Channel beta, 3.9.0-0.2.pre, on Fedora Linux 37 (Workstation Edition) 6.2.7-200.fc37.x86_64, locale en_US.UTF-8)
• Flutter version 3.9.0-0.2.pre on channel beta at /home/myzel394/snap/flutter/common/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 0df8557c56 (3 days ago), 2023-03-23 22:02:01 -0500
• Engine revision 1cc4b2d280
• Dart version 3.0.0 (build 3.0.0-290.3.beta)
• DevTools version 2.22.2
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
• Android SDK at /home/myzel394/Android/Sdk
• Platform android-33, build-tools 33.0.2
• Java binary at: /var/lib/snapd/snap/android-studio/125/android-studio/jre/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
• All Android licenses accepted.
[✓] Chrome - develop for the web
• Chrome at google-chrome
[✓] Linux toolchain - develop for Linux desktop
• clang version 10.0.0-4ubuntu1
• cmake version 3.16.3
• ninja version 1.10.0
• pkg-config version 0.29.1
[✓] Android Studio (version 2021.3)
• Android Studio at /var/lib/snapd/snap/android-studio/125/android-studio
• Flutter plugin version 72.1.1
• Dart plugin version 213.7433
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
[✓] IntelliJ IDEA Ultimate Edition (version 2022.3)
• IntelliJ at /var/lib/snapd/snap/intellij-idea-ultimate/417
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
[✓] Connected device (3 available)
• S426SXGG (mobile) • cda19d92 • android-arm64 • Android 12 (API 31)
• Linux (desktop) • linux • linux-x64 • Fedora Linux 37 (Workstation Edition) 6.2.7-200.fc37.x86_64
• Chrome (web) • chrome • web-javascript • Google Chrome 111.0.5563.110
[✓] Network resources
• All expected network resources are available.
• No issues found!
### Checklist before submitting a bug
- [X] I Google'd a solution and I couldn't find it
- [X] I searched on StackOverflow for a solution and I couldn't find it
- [X] I read the README.md file of the plugin
- [X] I'm using the latest version of the plugin
- [X] All dependencies are up to date with `flutter pub upgrade`
- [X] I did a `flutter clean`
- [X] I tried running the example project
the same thing is happening to me, any fix?
Hi there, while I was involved in large parts of the current share_plus code, the XFiles frontend was not designed by me. It would therefore probably be a little more time consuming for me to debug this. Sadly, I am currently unable to afford this time and can only leave you with the option to have a look at it after 27.04.2023 :/
@Coronon Today is 31.03.2023 :O Do you know someone else who can look at this?
@Myzel394 pardon me, I meant 27.04.2023! Possibly 'miquelbeltran'? I don't want to ping him though as he is also often quite busy and will look at new issues when he has time on his hands.
A quick fix for the time being should be to actually write the data to disk as a named file in a cache directory, share them and then delete them afterwards/at app startup. Have you tried that yet? :)
Yes temporarily I implemented that as a solution
Using the path_provider package, get the temporary file directory and we can store the file there. Then we can share the file using share_plus.
code for storing the file temporarily
Future<String> storeFileTemporarily(Uint8List image) async {
final tempDir = await getTemporaryDirectory();
const uuid = Uuid();
final path = '${tempDir.path}/${uuid.v4()}.jpg';
final file = await File(path).create();
file.writeAsBytesSync(image);
return path;
}
then using the temporary file path share the file.
final path = await storeFileTemporarily(value);
await Share.shareXFiles(
[XFile(path)],
);
Don't forget to import the packages.
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 15 days
@Coronon could you take a look at this? :D
Actually have time today - will look into it ;)
Ok, I took a look into this now.
We are indeed just discarding the XFile.name value and just create a new filename with {uuidV4}.{extensionForMime}.
Technical:
After changing that to actually prefer the name attribute this still does not work which leads me to the underlying problem: The XFile implementation itself doesn't handle the name argument to the constructor in the io (non web) version - it simply discards it!
XFile.fromData(
Uint8List bytes, {
String? mimeType,
String? path,
String? name,
int? length,
DateTime? lastModified,
}) : _mimeType = mimeType,
_bytes = bytes,
// This is where path will dictate the filename from now on <--------------
_file = File(path ?? ''),
_length = length,
_lastModified = lastModified,
// We simply discard `name` here <--------------
super(path) {
if (length == null) {
_length = bytes.length;
}
}
The name is instead dynamically deduced from the provided path (yes, even when using fromData which also takes a path argument ^^):
// This is the dart:io implementation
// _file was initialized in the constructor from `path`
String get name => _file.path.split(Platform.pathSeparator).last;
Conclusion:
This sadly means that we can not implement this feature as easily as we would like to.
Either you continue with your workaround, and we add a little hint to this behavior in the documentation.
Or we honor, by extension, the path argument in that we check if such a file exists and if not use the name getter to extract a filename the user want's us to use. This is pretty ugly though... The real problem lies with the upstream implementation of cross_file package in my eyes.
Another possible solution would be to provide a custom wrapper for XFile that implements the original interface and handles the name as expected, but that seems like a lot of scope creep.
Possible solution:
I could try to submit a PR to cross_file that defaults to the provided name if no path was provided (e.g. the file does not actually exist on disk). I don't know what the probability of them merging such a change is, though, as this might break other peoples code...
I would like to get the opinion of a maintainer here: /cc @vbuberen
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 15 days
@Coronon Sorry for getting back that late. This issue slipped out of my radar and thanks to Stale Action something reminded me about it.
I have the same feeling that it would be good to open a PR into cross_file as you suggested.
Just hit this as well. The name is completely ignored and my file becomes a UUID.
Any update on this? Me, too, stumbled upon this. It would be at least nice to get this documented properly. At least a note in the XFile.fromData method comment would be nice.
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 15 days