How to implement a ContentProvider for providing image to Gmail, Facebook, Evernote, etc

前端 未结 3 1210
南方客
南方客 2021-01-05 11:00

My previous question (Is it possible to share an image on Android via a data URL?) is related to this question. I have figured out how to share an image from my application

相关标签:
3条回答
  • 2021-01-05 11:50

    Had the same problem and after lots of research and debuging here is my 5 cents: (on my android 2.3.3 and 4.2 devices)

    1. Facebook app will not use openFile(Uri uri, String mode) so we have to give it real URI (in projection[i] == MediaStore.MediaColumns.DATA) with read rights.
    2. You have to give Facebook every projection it asks you, otherwise FB-app will just repeate query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

    It is probably a hack, and wouldn't work on some sensitive data, but you can make file.setReadable(true, false); on internal file somewhere in your code and facebook will be able to see and send the img. No need for android external storage permissions. Probably there is no need for content provider if img will be readable. Can just send link in Intent. But i had strange google+ preview bechavior without provider so decided to keep it. Don't have lots of devices to test and use only Twitter, FB , Google+ ,Skype, Gmail. Works fine for now

    Here is GitHub Demo:

    0 讨论(0)
  • 2021-01-05 11:55

    I had issues with sharing to some email and messaging clients because of the query method. Some recipient apps send in null for the projection parameter. When that happens, your code throws a NullPointerException. The NPE is easy to solve. However, the apps that send null still require some information back. I still can't share to Facebook, but I can share to all other apps I've tested using:

    EDIT I also cannot get it to work with Google Hangout. With that, at least, I get a toast indicating You can't send this file on Hangouts. Try using a picture. See also this question: Picture got deleted after send via Google hangout. I assume this is because I'm using private content and Hangouts can't / won't accept it for some reason.

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        if (projection == null) {
            projection = new String[] {
                    MediaStore.MediaColumns.DISPLAY_NAME,
                    MediaStore.MediaColumns.SIZE,
                    MediaStore.MediaColumns._ID,
                    MediaStore.MediaColumns.MIME_TYPE
            };
        }
    
        final long time = System.currentTimeMillis();
        MatrixCursor result = new MatrixCursor(projection);
        final File tempFile = generatePictureFile(uri);
    
        Object[] row = new Object[projection.length];
        for (int i = 0; i < projection.length; i++) {
    
           if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DISPLAY_NAME) == 0) {
              row[i] = uri.getLastPathSegment();
           } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.SIZE) == 0) {
              row[i] = tempFile.length();
           } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DATA) == 0) {
              row[i] = tempFile;
           } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.MIME_TYPE)==0) {
              row[i] = _mimeType;
           } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DATE_ADDED)==0 ||
                   projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DATE_MODIFIED)==0 ||
                   projection[i].compareToIgnoreCase("datetaken")==0) {
               row[i] = time;
           } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns._ID)==0) {
               row[i] = 0;
           } else if (projection[i].compareToIgnoreCase("orientation")==0) {
               row[i] = "vertical";
           }
        }
    
        result.addRow(row);
        return result;
    }
    
    0 讨论(0)
  • 2021-01-05 11:56

    I'm not familiar with the permissions I am or am not requiring or how to disable them

    Try replacing:

    <provider 
        android:name="PictureContentProvider"
        android:authorities="com.enigmadream.picturecode.snapshot"
        android:grantUriPermissions="true"
        android:readPermission="com.enigmadream.picturecode.snapshot"
        tools:ignore="ExportedContentProvider">
        <grant-uri-permission android:path="/picture.png" />
    </provider>
    

    with:

    <provider 
        android:name="PictureContentProvider"
        android:authorities="com.enigmadream.picturecode.snapshot"
        android:exported="true"
        tools:ignore="ExportedContentProvider">
    </provider>
    

    You really should have android:exported="true" in the first one too, but the permissions change I was referring to represents the removal of android:readPermission and <grant-uri-permissions>.

    Then, get rid of addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); in your Java code.

    This sets up your ContentProvider to be world-readable. Long-term, that might not be the right answer. Short-term, it will help to determine if your Android 2.2.2 problem is because FLAG_GRANT_READ_URI_PERMISSION is not being honored.

    0 讨论(0)
提交回复
热议问题