分享没有 WRITE_EXTERNAL_STORAGE 的图片?

Share image without WRITE_EXTERNAL_STORAGE?

有没有办法使用 Intent.ACTION_SEND 共享屏幕截图而不需要 android.permission.WRITE_EXTERNAL_STORAGE

分享部分如下:

    Intent shareIntent = new Intent(Intent.ACTION_SEND);
    shareIntent.setType("image/jpeg");
    shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
    Intent chooserIntent = Intent.createChooser(shareIntent, shareTitle);
    startActivity(chooserIntent);

当 uri 指向 getExternalFilesDir() 中的文件时共享工作正常,但我更喜欢一种不需要 WRITE_EXTERNAL_STORAGE 隐私相关用户权限的解决方案。

我尝试了 3 种不同的方法:

  1. 文件提供者:

    uri = FileProvider.getUriForFile(context, authority, imageFile);
    

这适用于某些共享样式 (Gmail),但不适用于其他共享样式 (Google+)。

  1. 上传到网络服务器:

    uri = Uri.parse("http://my-image-host.com/screenshot.jpg");
    

这到处都失败了,崩溃了一些(Google+)。

(我怀疑这个 可以 如果我自己使用每个社交网络 API 而不是 chooserIntent 实现共享逻辑)

  1. 注入媒体存储:

    uri = MediaStore.Images.Media.insertImage(contentResolver, bitmap, name, description);
    

这会抛出一个 SecurityException,说明它需要 WRITE_EXTERNAL_STORAGE。

我还缺少其他方法吗?

基于 work by Stefan Rusek,我创建了 LegacyCompatCursorWrapper,旨在帮助提高 FileProvider(和其他 ContentProvider 实现)与正在寻找 _DATA 列,但没有找到它们。 _DATA 模式最初由 MediaStore 使用,但应用程序尝试引用该列从来都不是一个好主意。

要与 FileProvider 结合使用,请添加 my CWAC-Provider library 作为依赖项,然后创建您自己的 FileProvider 的子 class,例如:

/***
 Copyright (c) 2015 CommonsWare, LLC
 Licensed under the Apache License, Version 2.0 (the "License"); you may not
 use this file except in compliance with the License. You may obtain a copy
 of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
 by applicable law or agreed to in writing, software distributed under the
 License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.

 From _The Busy Coder's Guide to Android Development_
 http://commonsware.com/Android
 */

package com.commonsware.android.cp.v4file;

import android.database.Cursor;
import android.net.Uri;
import android.support.v4.content.FileProvider;
import com.commonsware.cwac.provider.LegacyCompatCursorWrapper;

public class LegacyCompatFileProvider extends FileProvider {
  @Override
  public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    return(new LegacyCompatCursorWrapper(super.query(uri, projection, selection, selectionArgs, sortOrder)));
  }
}

所有这一切都是将 FileProvider query() 结果包装在 LegacyCompatCursorWrapper 中。您的应用程序配置的其余部分将与直接使用 FileProvider(例如,<meta-data> 元素)相同,除了您的 <activity> 元素的 android:name 属性将指向您自己的 class。您可以在 this sample app.

中看到实际效果