与FileProvider共享Android照片

时间:2014-07-16 13:45:34

标签: java android android-sharing android-fileprovider

我已经阅读了关于这个论点的所有答案,但我总是收到收到我的照片的应用程序的错误。
对我来说工作的唯一方法是适用于所有应用,这是(它的工作因为SD卡文件对所有应用程序都是公开的):< / p>

final File tmpFile = new File(context.getExternalCacheDir(), "exported.jpg");
Uri tmpFileUri = Uri.fromFile(tmpFile);

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setDataAndType(tmpFileUri, "image/jpeg");
shareIntent.putExtra(Intent.EXTRA_STREAM, tmpFileUri);
context.startActivity(Intent.createChooser(shareIntent, context.getString(R.string.share_image)));



现在,我坚持如何共享位于私人文件夹中的文件。 我使用了google文档提供的代码:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.test.myapp.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true" >
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>
...
...
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="internal_files" path="/"/>
    <cache-path name="internal_cache" path="/" />
</paths>


这是使用FileProvider共享文件的代码,但不适用于任何应用程序,除了最新内容:

final File tmpFile = new File(context.getCacheDir(), "exported.jpg");
Uri tmpFileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", tmpFile);
//Remove the uri permission because we overwrite the file
context.revokeUriPermission(tmpFileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

saveBitmapToPath(bitmap, tmpFile);
bitmap.recycle();

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setDataAndType(tmpFileUri, "image/jpeg");
shareIntent.putExtra(Intent.EXTRA_STREAM, tmpFileUri);
//Grant again the permissions
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
context.startActivity(Intent.createChooser(shareIntent, context.getString(R.string.share_image)));

为什么我一直在其他应用程序中遇到错误,如下所示:
java.lang.SecurityException: Permission Denial: content://com.test.myapp.fileprovider/internal_cache/exported.jpg (pid=675, uid=10052) requires null
或者
IllegalArgumentException: Failed to find configuration root that contains content://com.test.myapp.fileprovider/internal_cache/exported.jpg

1 个答案:

答案 0 :(得分:5)

最后查看接收应用的源代码,我得到了解决方案 这是我分享的完整,有效的代码 我希望能帮助别人:

<!-- AndroidManifest.xml -->
<provider
    android:name="com.test.myapp.fileprovider.FileProvider"
    android:authorities="com.test.myapp.fileprovider"
    android:exported="true"
    tools:ignore="ExportedContentProvider" />


//EntryPoint
private void mySharer() {
    ArrayList<Uri> streamUris = new ArrayList<Uri>();
    for (int i = 0; i < 10; i++) {
        File tmpFile = new File(getContext().getCacheDir(), "tmp" + i + ".jpg");
        Uri tmp = FileProvider.getUriForFile("com.test.myapp.fileprovider", tmpFile);
        streamUris.add(tmp);
    }
}

//Share Intent creator
public final void shareUris(ArrayList<Uri> streamUris) {
    if (!streamUris.isEmpty()) {
        Intent shareIntent = new Intent();
        shareIntent.putExtra(ShareCompat.EXTRA_CALLING_PACKAGE, getPackageName());
        shareIntent.putExtra(ShareCompat.EXTRA_CALLING_ACTIVITY, getComponentName());
        shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        shareIntent.setType("image/jpeg");

        if (streamUris.size() == 1) {
            shareIntent.setAction(Intent.ACTION_SEND);
            shareIntent.putExtra(Intent.EXTRA_STREAM, streamUris.get(0));
        } else {
            shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
            shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, streamUris);
        }

        //For multiple images copy all images in the baseDir and use startActivityForResult
        startActivityForResult(Intent.createChooser(shareIntent, getString(R.string.share_image)), 500);
    }
}

//onResult you can delete all temp images/files with specified extensions
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case 500:
            getContentResolver().delete(FileProvider.getUriForFile(getPackageName() + ".fileprovider", null), FileProvider.WHERE_EXTENSION, new String[]{"jpg"});
            break;
        default:
            break;
    }
}

/**
 * This class extends the ContentProvider
 */
abstract class AbstractFileProvider extends ContentProvider {

    private final static String OPENABLE_PROJECTION_DATA = "_data";
    private final static String[] OPENABLE_PROJECTION = { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE, OPENABLE_PROJECTION_DATA };

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        if (projection == null) {
            projection = OPENABLE_PROJECTION;
        }

        final MatrixCursor cursor = new MatrixCursor(projection, 1);
        MatrixCursor.RowBuilder b = cursor.newRow();

        for (String col : projection) {
            if (OpenableColumns.DISPLAY_NAME.equals(col)) {
                b.add(getFileName(uri));
            } else if (OpenableColumns.SIZE.equals(col)) {
                b.add(getDataLength(uri));
            } else if (OPENABLE_PROJECTION_DATA.equals(col)) {
                b.add(getFileName(uri));
            } else {
                b.add(null);
            }
        }

        return cursor;
    }

    @Override
    public String getType(Uri uri) {
        return URLConnection.guessContentTypeFromName(uri.toString());
    }

    protected String getFileName(Uri uri) {
        return uri.getLastPathSegment();
    }

    protected long getDataLength(Uri uri) {
        return AssetFileDescriptor.UNKNOWN_LENGTH;
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        throw new RuntimeException("Operation not supported");
    }

    @Override
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
        throw new RuntimeException("Operation not supported");
    }

    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        throw new RuntimeException("Operation not supported");
    }
}

/**
 * This class extends the AbstractFileProvider
 */
public class FileProvider extends AbstractFileProvider {

    public static final String CONTENT_URI = "content://";
    private File baseDir;

    @Override
    public boolean onCreate() {
        baseDir = getContext().getCacheDir();

        if (baseDir != null && baseDir.exists()) {
            return true;
        }

        Log.e("FileProvider", "Can't access cache directory");
        return false;
    }

    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
        File f = new File(baseDir, uri.getPath());

        if (f.exists()) {
            return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
        }

        throw new FileNotFoundException(uri.getPath());
    }

    @Override
    protected long getDataLength(Uri uri) {
        File f = new File(baseDir, uri.getPath());

        return f.length();
    }

    public static Uri getUriForFile(String authority, File file) {
        return Uri.parse(CONTENT_URI + authority + "/" + file.getName());
    }
}



-------------编辑:05/11/16 --------------
添加了对多个图像的支持:

  1. 复制baseDir文件夹
  2. 中的所有图像
  3. delete()
  4. 中实施FileProvider方法
  5. 使用startActivityForResult
  6. 倾听onActivityResult
  7. 现在您可以删除所有临时图像
  8. 对于电子邮件附件,您必须等待删除文件之前发送电子邮件,否则您将发送空附件