Skip to content
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

Can't share file in Application Document Directory - found work around #27

Open
skionthursday opened this issue Aug 13, 2020 · 4 comments

Comments

@skionthursday
Copy link

skionthursday commented Aug 13, 2020

I was having success when the file to share was located on the android external storage. I elected to move my files from an external storage location to the Application Document Directory, located using getApplicationDocumentsDirectory(). I did this so I can deploy to iOS which does not allow access to external storage. I can write the file to:

/data/user/0/com.PlantListGPSv1.Android.PlantListGPSv1/app_flutter/Backup/Backup 2020-08-12@20_18.pgps

placing the above full path into a string variable _fullPathName, and running the code below,

///
print('Full path name: $_fullPathName');
FlutterShare.shareFile(
title: _fileName,
text: 'Plant List GPS File:' + _fileName,
filePath: _fullPathName,
);
///

I get a debug console message and this error message

Full path name: /data/user/0/com.PlantListGPSv1.Android.PlantListGPSv1/app_flutter/Backup/Backup 2020-08-12@20_18.pgps
Exception has occurred.
PlatformException (PlatformException(Failed to find configured root that contains /data/data/com.PlantListGPSv1.Android.PlantListGPSv1/app_flutter/Backup/Backup 2020-08-12@20_18.pgps, null, null))

====

In trying to troubleshoot what FutterShare stopped working I find that my code runs without problem on iOS which has me thinking something changed with Android. I currently have an app working on Google play, build at the end of July with Android 28. After this post, I moved to Android 29 and I can remember when exactly things started breaking, but was soon after I started working in Android 29. I found that my permission-handler plugin went from permission_handler: '^4.2.0+hotfix.2' to permission_handler: ^5.0.1+1 which was a major change. I suspect internal storage, external storage, shared storage(new?) has changed too and could be the root cause of why the flutter_share stopped working with the path provide by getApplicationDocumentsDirectory. I offer this insight to help other to thing in this direction if a cause has not yet been found.

I have developed a work-around as sharing files is important to my app. In a high level, my app reads from the ApplicationDocumentDirectory and writes the file to ExternalStorageDirectory when flutter_share works. Below is an extract of my code that is working for me. I have logged a provider error message that I do not understand, but since flutter_share works, I'm not sure how relevant the exception is, and would appreciate any help in resolving it.

//permission_handler: ^5.0.1+1
Future<String> askStoragePermission() async {
	var permission = await Permission.storage.request().isGranted;
	if (permission) {
	  return 'Ok';
	} else {
	  print('Storage permission denied');
	  return 'Not OK';
	}
  }

Future<void> shareFile(_subDir, _fileName) async {
final String _fullPathName = await getShareFileFullPath(_subDir, _fileName);
print('Find file at: \n$_fullPathName');
await FlutterShare.shareFile(
  title: _fileName,
  text: 'PLGPS File:' + _fileName,
  filePath: _fullPathName,
);
}

Future getShareFileFullPath(String _subDir, String _fileName) async {
String _fullPathName, _rootDir, _storagePermission;
Io.Directory _storDir;
if (Platform.isAndroid) {
// work around FlutterShare not able to read App Doc Dir
// get file to re-write to external Storage
_storDir = await getApplicationDocumentsDirectory();
_rootDir = _storDir.toString();
_fullPathName =
_rootDir.substring(12, _rootDir.length - 1) + _subDir + _fileName;
print('$_fullPathName');
final _myFile = new Io.File(_fullPathName);
final String _fileData = await _myFile.readAsString(); // have file read
//
// write file to external storage so it can be shared
_storagePermission = await _iOX.askStoragePermission();
print('Storage permission: $_storagePermission');
var _path = await ExtStorage.getExternalStorageDirectory();
_subDir = 'Test';
final String _plgpsDirPath = _path + '/$_subDir/';
Io.Directory(_plgpsDirPath)
.create(recursive: true)
.then((Io.Directory directory) {});
final String _fullPathFileName = _plgpsDirPath + _fileName;
new File(_fullPathFileName).writeAsString(_fileData);
print('File written to:\n$_fullPathFileName');
return _fullPathFileName;
}
// iOS and other OS routine
else {
Io.Directory _storDir = await getApplicationDocumentsDirectory();
_rootDir = _storDir.toString();
_fullPathName = _rootDir.substring(0, _rootDir.length - 1) +
_subDir +
"/" +
_fileName;
print('$_fullPathName');
return _fullPathName;
}
}

AndroidManifest.xml highlights

I'm not sure about the following error message. The share process powers through the Permission denied exception. I suspect sharing between routines is not happening, but not familiar enough with the topic to know the issue. Maybe someone who knows can chime in to help with the reported issue. Thanks.

Debug Console:

I/flutter (23897): /data/user/0/com.PlantListGPSv1.Android.PlantListGPSv1/app_flutter/Backup/Backup 2020-08-14@21_14.pgps
I/flutter (23897): Storage permission: Ok
I/flutter (23897): File written to:
I/flutter (23897): /storage/emulated/0/Test/Backup 2020-08-14@21_14.pgps
I/flutter (23897): Find file at:
I/flutter (23897): /storage/emulated/0/Test/Backup 2020-08-14@21_14.pgps
I/.PlantListGPSv(23897): NativeAlloc concurrent copying GC freed 7847(424KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 1589KB/3179KB, paused 44.346ms total 466.370ms
E/DatabaseUtils(23897): Writing exception to parcel
E/DatabaseUtils(23897): java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri content://com.PlantListGPSv1.Android.PlantListGPSv1.provider/external_files/Test/Backup%202020-08-14%4021_14.pgps from pid=21487, uid=1000 requires the provider be exported, or grantUriPermission()
E/DatabaseUtils(23897): at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:729)
E/DatabaseUtils(23897): at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:602)
E/DatabaseUtils(23897): at android.content.ContentProvider$Transport.query(ContentProvider.java:231)
E/DatabaseUtils(23897): at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:104)
E/DatabaseUtils(23897): at android.os.Binder.execTransactInternal(Binder.java:1021)
E/DatabaseUtils(23897): at android.os.Binder.execTransact(Binder.java:994)

@skionthursday skionthursday changed the title Not finding file is Application Document Directory Not finding file in Application Document Directory Aug 13, 2020
@skionthursday skionthursday changed the title Not finding file in Application Document Directory Can't share file in Application Document Directory - found work around Aug 16, 2020
@MrCsabaToth
Copy link

There are several changes with Android API 29 and API 30 related to file handling. In fact even API 28 had some changes.
https://developer.android.com/training/data-storage/shared/media
https://developer.android.com/about/versions/10/behavior-changes-10

@mw66
Copy link

mw66 commented May 28, 2021

@MrCsabaToth so what's the recommended API number that works with , e.g. flutter_share 1.0.3?

@mw66
Copy link

mw66 commented May 28, 2021

Saw this one:

https://stackoverflow.com/questions/63688285/flutter-platformexceptionerror-failed-to-find-configured-root-that-contains

"""
My understanding is as follow, you can read and write in ApplicationDocumentsDirectory but the data can't be accessed outside of the app. Since when you call FlutterEmailSender the data is then sent through an other application, you'll have to save your .csv to a "public" location.
"""

Maybe this is the reason.

@mw66
Copy link

mw66 commented May 28, 2021

I copied the app image file to the public download dir:

import 'package:downloads_path_provider/downloads_path_provider.dart';
...

                      File file = File(path);
                      Directory downloadsDirectory = await DownloadsPathProvider.downloadsDirectory;
                      // copy file to downloadsDirectory
                      String fileBasename = basename(file.path);
                      String pubPath = '${downloadsDirectory.path}/$fileBasename';
                      await file.copy(pubPath);
                      FlutterShare.shareFile(
                        title: 'share image',
                        text: "share image",
                        filePath: pubPath,
                      );

The operation seems successful, no error report by the app. But in the other to-be-shared app, the sharing is not happening.

And I checked the "/Downloads/....jpeg", the file is copied there.

Do you know why the sharing is not actually happening, while no error reported? What I should check further?

P.S.: I just found some app e.g. Email/Gmail sharing is working; while other app is not, e.g. WeChat (only simple text share is working on WeChat).

Has anyone been able to share image on WeChat?

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants