2014-07-16 108 views
4

我已閱讀關於此參數的所有答案,但我總是收到收到我的照片的應用程序的錯誤。
的唯一方法是工作對我來說,所有應用,是這樣的(它的工作原理,因爲SD卡上的文件都是公開的所有應用):與FileProvider共享Android圖片

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))); 



現在,我被困在如何共享位於私人文件夾中的文件。 我使用的谷歌文檔提供的代碼:

<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

回答

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. FileProvider
  3. 使用實施delete()方法startActivityForResult
  4. onActivityResult
  5. 現在,你可以刪除所有臨時圖像

對於電子郵件附件您在刪除文件之前必須等待發送電子郵件,否則您將發送一個空的附件

+0

所以你沒有使用XML路徑?我遇到了多個路徑的問題。一條路徑工作,當我把它兩個不 – dangalg

+0

有人找出爲什麼多個路徑不工作? – JaredBanyard

+0

我更新了多個路徑的答案 –