通过Gmail Intent打开共享图像

时间:2014-08-27 19:38:40

标签: android android-intent

我有以下代码正确地将图像附加到电子邮件并发送:

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定义为" image / png"

destFile是从应用的外部缓存目录中抓取的图片,(((ActivityMain) getActivity()).getExternalCacheDir()

但是,当我尝试在Gmail中打开文件时,会出现一个对话框,显示:信息 - 没有应用可以打开此附件进行查看。我已经通过我的电脑下载了文件,扩展程序显示为.File。我可以用油漆和其他图像浏览器打开它。

以前有人经历过这个吗?

2 个答案:

答案 0 :(得分:1)

考虑到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>

答案 1 :(得分:0)

这有效,但需要外部存储和相关权限。下载应用程序时,会出现一个对话框,显示应用程序正在请求能够读取/写入可能会导致用户离开的数据。如果这是一个问题,请使用我在初始帖子中建议的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
以及另一个主题:
How to use support FileProvider for sharing content to other apps?

此时我意识到没有为正在使用的图像设置文件类型。我只是将.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"));
    }
}