通过Gmail 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定义为"图像/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"));
    }
}

最新更新