2015-12-20 36 views
2

我想創建一個選項,讓用戶通過電子郵件從我的應用程序發送文件。該文件在應用程序內部,可通過FileProvider訪問。Android共享意向選擇器僅限EMail客戶端

這是contentURI看起來像content://packagename.files/files/somefile.ext

在這裏,你可以看到,我給用戶共享文件PicsArt不僅,谷歌驅動器,OneDrive和電子郵件。

ShareDialogFragment

我能夠將內容分享成功的前三個客戶,因爲他們非常特殊的應用。但是當談到電子郵件時,我需要用戶從他的手機中安裝的應用程序中選擇客戶端。

這裏有2組代碼,我已經創建了:

代碼選項1:

Intent EMail = ShareCompat.IntentBuilder.from(this) 
        .setType("message/rfc822") 
        .setSubject("Emailing: File Attached") 
        .setText("Hello") 
        .setStream(contentUri) 
        .setChooserTitle("Send via EMail").getIntent(); 
startActivity(Intent.createChooser(EMail, "Send via EMail")); 

上面的代碼顯示我在哪裏有,它可以處理文件,如圖在許多應用中選擇器下面的圖片。如果我選擇的任何電子郵件客戶端應用程序或任何其他應用程序

Activity Chooser

這一個工作正常。

但這樣做的問題是,有供用戶選擇任何應用程序,這是不是應用的期望行爲的選項。所以,我修改了代碼如下:

final Intent _Intent = new Intent(Intent.ACTION_SENDTO); 
_Intent.setType("text/html"); 
_Intent.setData(Uri.parse("mailto:")); 
_Intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 
_Intent.putExtra(Intent.EXTRA_STREAM, contentUri); 
_Intent.putExtra(android.content.Intent.EXTRA_SUBJECT, 
     "Emailing: File Attached"); 
_Intent.putExtra(android.content.Intent.EXTRA_TEXT, 
     "Hello"); 
startActivity(Intent.createChooser(_Intent, "Send via EMail")); 

這裏是代碼的結果:

only email clients

但是,現在這裏的問題是,我無法從發送的文件內容提供者(FileProvider)。電子郵件客戶端顯示了消息,如下選擇之後:

enter image description here

它根本就沒有文件的電子郵件附連在任何客戶端在上述列表中。

如果有人能幫助我,我會很棒。我認爲,我已經嘗試過所有可能的場景,通過改變MIME類型,以不同方式設置數據設置流等內容,但無法獲得預期結果。

請讓我知道,以防您需要任何其他細節。

再次提前致謝。

+0

您需要編寫ContentProvider,它將向您向其傳遞ContentUri的客戶端提供InputStream。 –

+0

@zeus你能爲我寫一行或兩行代碼嗎?我在這方面有點不成熟。 –

+0

我不確定如果這可以幫助你,但看看這個http://stackoverflow.com/a/31470694/3209739。文件:/ /困擾了我,沒有它的工作,但它是一個文件不是從內容提供商。您可以嘗試沒有內容:/。這是我的盲目猜測;;) – cgr

回答

1

您需要編寫ContentProvider,它將向您向其傳遞ContentUri的客戶端提供InputStream,或者您可以直接提供文件路徑(如果它存在於SdCard或內部存儲中),因爲您需要處理uri並傳遞InputStream。注意:ExtraStream最適用於不在設備中的文件,這些文件將通過互聯網訪問。

public class SampleContentProvider extends ContentProvider implements ContentProvider.PipeDataWriter<InputStream> { 

    static final UriMatcher uriMatcher; 


    static { 
     uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 
     //Uri matcher for different 

    } 

    /** 
    * Database specific constant declarations 
    */ 
    private SQLiteDatabase db; 


    @Override 
    public boolean onCreate() { 
     return true; 
    } 


    @Override 
    public Uri insert(Uri uri, ContentValues values) { 

     throw new SQLException("Insert operation not supported for " + uri); 
    } 

    @Override 
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 

     //condition just for files. You can try something else 
     if (uri.toString().contains("files")) { 

      //you get the file name 
      String lastSegment = uri.getLastPathSegment(); 

      if (projection == null) { 
       projection = new String[]{OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}; 
      } 

      File file = //Code to read the file as u have the directory, just get the file from the file name obtained from the uri 


      if (null == file) { 
       throw new IllegalArgumentException("Unknown File for Uri " + uri); 
      } 
      String[] cols = new String[projection.length]; 
      Object[] values = new Object[projection.length]; 
      int i = 0; 
      for (String col : projection) { 
       if (OpenableColumns.DISPLAY_NAME.equals(col)) { 
        cols[i] = OpenableColumns.DISPLAY_NAME; 
        values[i++] = //file name; 
       } else if (OpenableColumns.SIZE.equals(col)) { 
        cols[i] = OpenableColumns.SIZE; 
        values[i++] = //file size; 
       } 
      } 

      cols = copyOf(cols, i); 
      values = copyOf(values, i); 

      final MatrixCursor cursor = new MatrixCursor(cols, 1); 
      cursor.addRow(values); 
      return cursor; 
     } 

     return super.query(uri, projection, selection, selectionArgs, sortOrder); 

    } 

    @Override 
    public String getType(Uri uri) { 
     return null; 
    } 

    @Override 
    public int delete(Uri uri, String selection, String[] selectionArgs) { 
     return super.delete(uri, selection, selectionArgs); 

    } 


    private static String[] copyOf(String[] original, int newLength) { 
     final String[] result = new String[newLength]; 
     System.arraycopy(original, 0, result, 0, newLength); 
     return result; 
    } 

    private static Object[] copyOf(Object[] original, int newLength) { 
     final Object[] result = new Object[newLength]; 
     System.arraycopy(original, 0, result, 0, newLength); 
     return result; 
    } 

    @Nullable 
    @Override 
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 

     File file = //read the file 
     if (file != null) { 
      try { 
       StrictMode.ThreadPolicy tp = StrictMode.ThreadPolicy.LAX; 
       StrictMode.setThreadPolicy(tp); 
       InputStream in = //Code to get the inputstream; 
       // Start a new thread that pipes the stream data back to the caller. 
       return openPipeHelper(uri, null, null, in, this); 
      } catch (IOException e) { 
       FileNotFoundException fnf = new FileNotFoundException("Unable to open " + uri); 
       throw fnf; 
      } 
     } 

     throw new IllegalArgumentException("Unknown URI " + uri); 
    } 

    @Override 
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 
     return super.update(uri, values, selection, selectionArgs); 
    } 

    @Override 
    public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, 
           Bundle opts, InputStream args) { 
     // Transfer data from the asset to the pipe the client is reading. 
     byte[] buffer = new byte[8192]; 
     int n; 
     FileOutputStream fout = new FileOutputStream(output.getFileDescriptor()); 
     try { 
      while ((n = args.read(buffer)) >= 0) { 
       fout.write(buffer, 0, n); 
      } 
     } catch (IOException e) { 
     } finally { 
      try { 
       args.close(); 
      } catch (IOException e) { 
      } 
      try { 
       fout.close(); 
      } catch (IOException e) { 
      } 
     } 
    } 

} 
+0

嗨@Zeus,我想你分享給我的代碼將是正確的代碼來做我正在尋找的東西。但是,由於我無法在您提供的代碼中填寫空格和佔位符,因此我將無法作證或支持它。感謝您提供代碼。我非常感謝你在這裏的努力。 –

0

我已經決定從內部應用程序存儲的文件複製到外部應用程序存儲(不對外公開的存儲),並從那裏共享文件。我有點驚訝,因爲FileProvider能夠與系統中的任何東西共享內部文件存儲中的文件,但是當我想過濾只是電子郵件客戶端的Intents時,卻無法這樣做。

對初學者來說,實現一個自定義提供程序有點困難。

0

試試這個片段。

Intent testIntent = new Intent(Intent.ACTION_VIEW); 
        Uri data = Uri.parse("mailto:?subject=" + "Feedback" + "&body=" + "Write Feedback here....." + "&to=" + "[email protected]"); 
        testIntent.setData(data); 
        startActivity(testIntent);