Meine vorherige Frage (Is it possible to share an image on Android via a data URL?) bezieht sich auf diese Frage. Ich habe herausgefunden, wie ich ein Bild von meiner Anwendung an eine andere Anwendung weitergeben kann, ohne die Erlaubnis zu haben, Dateien auf externen Speicher zu schreiben. Allerdings habe ich immer noch eine Reihe von Problemverhalten:So implementieren Sie einen ContentProvider für die Bereitstellung von Bildern an Google Mail, Facebook, Evernote usw.
- Wenn ich versuche, das Bild von meinem Handy (Android 2.2.2) zu teilen, fatale Fehler in den Empfangs Anwendungen auftreten, und sie nicht kommen mit dem Bild überhaupt. (Könnte das ein Ergebnis eines Vorgangs in meiner App sein, der unter Android 2.2.2 nicht unterstützt wird? Oder hätte das einen Fehler in meiner App und nicht in der Ziel-App verursacht?)
- Wenn ich versuche, das Bild zu teilen zu Evernote, alles funktioniert gut, aber manchmal ein paar Sekunden nach dem Speichern der Notiz, bekomme ich eine Nachricht am unteren Rand der App-Bildschirm (von der Evernote App): "java.lang.SecurityException: Permission Denial: Eröffnungs-Provider com.enigmadream.picturecode.PictureContentProvider aus ProcessRecord {413db6d0 1872: com.evernote/u0a10105} (pid = 1872, uid = 10105), die nicht aus der uid 10104 exportiert wird "
- Wenn ich versuche, das Bild auf Facebook zu teilen, gibt es ein Rechteck für das Bild, aber kein Bild darin.
Unten ist mein ContentProvider-Code. Es muss einen einfacheren und/oder geeigneteren Weg geben, einen dateibasierten ContentProvider (insbesondere die Abfragefunktion) zu implementieren. Ich erwarte, dass viele Probleme von der Abfrage-Implementierung herrühren. Die interessante Sache ist, dass diese funktioniert sehr gut auf meinem Nexus 7, wenn Sie zu GMail gehen. Es nimmt den korrekten Anzeigenamen und die Größe für den Anhang auch auf.
public class PictureContentProvider extends ContentProvider implements AutoAnimate {
public static final Uri CONTENT_URI = Uri.parse("content://com.enigmadream.picturecode.snapshot/picture.png");
private static String[] mimeTypes = {"image/png"};
private Uri generatedUri;
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new RuntimeException("PictureContentProvider.delete not supported");
}
@Override
public String getType(Uri uri) {
return "image/png";
}
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new RuntimeException("PictureContentProvider.insert not supported");
}
@Override
public boolean onCreate() {
generatedUri = Uri.EMPTY;
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
long fileSize = 0;
MatrixCursor result = new MatrixCursor(projection);
File tempFile;
try {
tempFile = generatePictureFile(uri);
fileSize = tempFile.length();
} catch (FileNotFoundException ex) {
return result;
}
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] = getContext().getString(R.string.snapshot_displaystring);
} else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.SIZE) == 0) {
row[i] = fileSize;
} else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DATA) == 0) {
row[i] = tempFile;
} else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.MIME_TYPE)==0) {
row[i] = "image/png";
}
}
result.addRow(row);
return result;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new RuntimeException("PictureContentProvider.update not supported");
}
@Override
public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
return mimeTypes;
}
private File generatePictureFile(Uri uri) throws FileNotFoundException {
if (generatedUri.compareTo(uri)==0)
return new File(getContext().getFilesDir(), "picture.png");;
Context context = getContext();
String query = uri.getQuery();
String[] queryParts = query.split("&");
String pictureCode = "016OA";
int resolution = 36;
int frame = 0;
int padding = 0;
for (String param : queryParts) {
if (param.length() < 2)
continue;
if (param.substring(0,2).compareToIgnoreCase("p=") == 0) {
pictureCode = param.substring(2);
} else if (param.substring(0,2).compareToIgnoreCase("r=") == 0) {
resolution = Integer.parseInt(param.substring(2));
} else if (param.substring(0, 2).compareToIgnoreCase("f=") == 0) {
frame = Integer.parseInt(param.substring(2));
} else if (param.substring(0, 2).compareToIgnoreCase("a=") == 0) {
padding = Integer.parseInt(param.substring(2));
}
}
Bitmap picture = RenderPictureCode(pictureCode, resolution, frame, padding);
File tempFile = new File(context.getFilesDir(), "picture.png");
FileOutputStream stream;
stream = new FileOutputStream(tempFile);
picture.compress(CompressFormat.PNG, 90, stream);
try {
stream.flush();
stream.close();
} catch (IOException e) {
e.printStackTrace();
throw new Error(e);
}
picture.recycle();
generatedUri = uri;
return tempFile;
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File tempFile = generatePictureFile(uri);
return ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
...
}
Ich habe dies auch in der AndroidManifest.xml Datei als Geschwister der <activity>
Elemente:
<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>
Der Code, der die Absicht erstellt sieht wie folgt aus:
resolution = mPicView.getWidth();
if (mPicView.getHeight() > resolution)
resolution = mPicView.getHeight();
String paddingText = mPadding.getEditableText().toString();
int padding;
try {
padding = Integer.parseInt(paddingText);
} catch (NumberFormatException ex) {
padding = 0;
}
Uri uri = Uri.parse(PictureContentProvider.CONTENT_URI
+ "?p=" + Uri.encode(mPicView.getPictureCode()) + "&r=" + Integer.toString(resolution)
+ "&f=" + Integer.toString(mPicView.getFrame()) + "&a=" + Integer.toString(padding));
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/png");
share.putExtra(Intent.EXTRA_STREAM, uri);
share.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_subject_made));
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(share, getString(R.id.menu_share)));
BEARBEITEN Hier sind die ersten zwei Zeilen des Stack-Trace, wenn der Fehler auf meinem Telefon auftritt:
04-07 13: 56: 24,423: E/DatabaseUtils (19431): java.lang.SecurityException: Permission Denial: Lesen com.enigmadream.picturecode.PictureContentProvider uri Gehalt: //com.enigmadream .picturecode.snapshot/picture.png? p = 01v131 & r = 36 & f = 0 a = 0 & von pid = 19025, uid = 10062 erfordert com.enigmadream.picturecode.snapshot
04-07 13 : 56: 24.423: E/DatabaseUtils (19431): um android.content.ContentProvider $ Transport.enforceReadPermission (ContentProvider .java: 271)
„Wenn ich versuche, das Bild von meinem Handy (Android 2.2 zu teilen.2), fatale Fehler treten in den empfangenden Anwendungen auf, und sie kommen überhaupt nicht auf das Bild "- es sollte Stack-Traces für diese geben. Da ich noch nie ein' content: // '' Uri' verwendet habe Abfrageparameter können Sie mit dem Entfernen experimentieren. Gehen Sie stattdessen mit einer REST-artigen 'Uri'-Syntax (' content: //com.enigmadream.picturecode.snapshot/p/.../r/.../f/. ../ a /.../ picture.png'). Sie können auch die erforderlichen Berechtigungen temporär deaktivieren und nachsehen, ob das hilft, Ihr Problem zu identifizieren. " – CommonsWare
Ich weiß nicht, wie ich eine Stack-Ablaufverfolgung des Fehlers bekommen könnte, wenn es so ist Ich weiß, dass die Abfrageparameter unter bestimmten Umständen funktionieren, weil ich Bilder erzeuge, die nach den Parametern generiert werden.Ist die Behandlung von Abfrageparametern in einem Inhalts-URI ein Unterschied zwischen Android-Versionen? Ich habe gerade die Bedeutung von REST unter https://en.wikipedia.org/wiki/Representational_state_transfer nachgelesen und nichts von query st gesehen klingelt (die Wortabfrage findet nicht einmal auf dieser Seite statt). Wie ist dein Beispiel eher "RESTful"? – BlueMonkMN
Auch, wird es nicht ein Problem geben, wenn ich versuche, die Parameter in den Pfad einzubetten, in dem die Berechtigungen nicht mehr für alle verschiedenen Pfade gelten? – BlueMonkMN