我有以下代码,可以正确地将图像附加到电子邮件并发送:
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Set tht type to image/* and add the extra text field for the message to send
sharingIntent.setType(Application2.instance().getResString(R.string.share_intent_type_text_image));
sharingIntent.putExtra(Intent.EXTRA_TEXT, String.format(Application2.instance().getResString(R.string.share_intent_body_question), question.question));
if (destFile != null)
{
Uri uri = Uri.fromFile(destFile);
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
((ActivityMain) getActivity()).startActivity(Intent.createChooser(sharingIntent, "Share via"));
}
R.string.share_intent_type_text_image
定义为"图像/png"
destFile
是从应用程序的外部缓存目录(((ActivityMain) getActivity()).getExternalCacheDir()
中获取的图像
然而,当我试图在Gmail中打开文件时,会出现一个对话框,上面写着:信息-没有应用程序可以打开此附件进行查看。我已经通过我的电脑下载了这个文件,扩展名显示为.file。我可以用油漆和其他图像查看器打开它。
以前有人经历过这种情况吗?
考虑到FileProvider
问题,也因为我想为收集的临时文件实现最大缓存大小,所以我选择了ContentProvider
解决方案,它很有效。基本上,你可以毫无问题地使用内部缓存,但仍然可以为第三方应用程序提供URI,它们可以用来引用你想要与他们共享的临时文件。因为您使用内部缓存,所以不会有不必要的WRITE_EXTERNAL_STORAGE
权限要求。
添加的最大缓存大小限制(例如,如果您可以确保在共享后直接删除所有文件,这样它们就不会保留在设备上,则可以通过简单地删除checkSize()
到类末尾的所有内容来从类中删除)通过在每次调用时检查累积的最大大小并在必要时清除一半缓存(删除最旧的文件)来实现。
public class TemporaryFile extends ContentProvider {
private static final long MAX_SIZE = 512 * 1024;
// commented out on purpose so that you don't forget to rewrite it...
// public static final String AUTHORITY = "com.example.tempfile";
private UriMatcher uriMatcher;
@Override
public boolean onCreate() {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "*", 1);
return true;
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
if (uriMatcher.match(uri) == 1) {
final String file = getContext().getCacheDir() + File.separator + uri.getLastPathSegment();
return ParcelFileDescriptor.open(new File(file), ParcelFileDescriptor.MODE_READ_ONLY);
}
else
throw new FileNotFoundException(uri.toString());
}
@Override
public int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int delete (Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
public static File getFile(Context context, String prefix, String extension) throws IOException {
checkSize(context);
File file = File.createTempFile(prefix, extension, context.getCacheDir());
file.setReadable(true);
file.deleteOnExit();
return file;
}
public static Uri getPublicUri(File file) {
return Uri.withAppendedPath(Uri.parse("content://" + AUTHORITY), file.getName());
}
public static void checkSize(Context context) throws IOException {
File dir = context.getCacheDir();
if (getDirSize(dir) > MAX_SIZE)
cleanDir(dir, MAX_SIZE / 2);
}
private static long getDirSize(File dir) {
long size = 0;
for (File file : dir.listFiles())
if (file.isFile())
size += file.length();
return size;
}
private static void cleanDir(File dir, long atLeast) {
long deleted = 0;
File[] files = dir.listFiles();
Arrays.sort(files, new Comparator<File>() {
public int compare(File f1, File f2) {
return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
}
});
for (File file : files) {
deleted += file.length();
file.delete();
if (deleted >= atLeast)
break;
}
}
}
使用它再简单不过了,只需调用
File file = TemporaryFile.getFile(this, "prefix", ".extension");
只要你想创建一个新文件和
TemporaryFile.getPublicUri(file)
只要您想获得文件的公共Uri,例如将其作为数据或Intent.EXTRA_STREAM
传递给意图。
作为提供者,也不要忘记添加必要的清单条目:
<provider
android:name=".TemporaryFile"
android:authorities="com.example.tempfile"
android:exported="true"
tools:ignore="ExportedContentProvider" >
</provider>
这很有效,但需要外部存储和相关权限。下载应用程序时,会出现一个对话框,显示该应用程序正在请求能够读取/写入数据,这可能会让用户望而却步。如果这是一个问题,请使用Simon在我最初的帖子中建议的FileProvider。
有用的链接:
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
我试图像Simon在我最初的帖子中建议的那样使用文件提供程序,但没有成功。我在以下行收到一个NullPointerException:
final ProviderInfo info = context.getPackageManager()
.resolveContentProvider(authority, PackageManager.GET_META_DATA);
在以下位置遵循指南后,我无法跟踪问题:https://developer.android.com/reference/android/support/v4/content/FileProvider.html
以及位于以下位置的其他线程:
如何使用support FileProvider将内容共享到其他应用程序?
在这一点上,我意识到没有为正在使用的图像设置文件类型。我只是简单地将.png添加到文件中,附件在Gmail以及以前已经工作的应用程序中都能正常工作。
如果有人好奇我是如何共享内部文件的,我提供了以下代码。它并不完整,也不能完全处理错误,但它可能对某些人有用。
// Copy image file to external memory and send with the intent
File srcFile = getImage();
File destDir = new File(((ActivityMain) getActivity()).getExternalCacheDir(),
Application2.instance().getResString(R.string.temporary_external_image_path));
if(!destDir.exists())
{
destDir.mkdirs();
}
if(destDir != null && srcFile != null)
{
File destFile = new File(destDir, srcFile.getName());
if (!destFile.exists())
{
try
{
Application2.instance().copy(srcFile, destFile);
}
catch (IOException e)
{
if (BuildConfig.DEBUG) Log.e("Failed to copy file '" + srcFile.getName() + "'");
}
}
if (destFile != null)
{
Uri uri = Uri.fromFile(destFile);
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
((ActivityMain) getActivity()).startActivity(Intent.createChooser(sharingIntent, "Share via"));
}
}