Ich hatte das gleiche Problem. Ich wollte nicht nach den Lese- und Schreibberechtigungen für externen Speicher fragen müssen. Manchmal gibt es auch Probleme, wenn Telefone keine SD-Karten haben oder die Karten nicht mehr montiert werden.
Die folgende Methode verwendet einen ContentProvider namens FileProvider . Technisch gesehen speichern Sie die Bitmap (im internen Speicher) noch vor der Freigabe, müssen jedoch keine Berechtigungen anfordern. Außerdem wird die Bilddatei jedes Mal, wenn Sie die Bitmap freigeben, überschrieben. Und da es sich im internen Cache befindet, wird es gelöscht, wenn der Benutzer die App deinstalliert. Meiner Meinung nach ist es genauso gut, das Bild nicht zu speichern. Diese Methode ist auch sicherer als das Speichern im externen Speicher.
Die Dokumentation ist ziemlich gut (siehe weiterführende Literatur unten), aber einige Teile sind etwas knifflig. Hier ist eine Zusammenfassung, die für mich funktioniert hat.
Richten Sie den FileProvider im Manifest ein
<manifest>
...
<application>
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>
</manifest>
Ersetzen Sie com.example.myapp
durch Ihren App-Paketnamen.
Erstellen Sie res / xml / filepaths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="shared_images" path="images/"/>
</paths>
Dies teilt dem FileProvider mit, wo die Dateien freigegeben werden sollen (in diesem Fall über das Cache-Verzeichnis).
Speichern Sie das Bild im internen Speicher
try {
File cachePath = new File(context.getCacheDir(), "images");
cachePath.mkdirs();
FileOutputStream stream = new FileOutputStream(cachePath + "/image.png");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
Teile das Bild
File imagePath = new File(context.getCacheDir(), "images");
File newFile = new File(imagePath, "image.png");
Uri contentUri = FileProvider.getUriForFile(context, "com.example.myapp.fileprovider", newFile);
if (contentUri != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.setDataAndType(contentUri, getContentResolver().getType(contentUri));
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
startActivity(Intent.createChooser(shareIntent, "Choose an app"));
}
Weiterführende Literatur
Theoretisch ist dies möglich. In der Praxis ist dies wahrscheinlich nicht möglich.
Theoretisch müssen Sie nur eine
Uri
freigeben, die in die Bitmap aufgelöst wird. Der einfachste Ansatz ist, wenn es sich um eine Datei handelt, auf die die andere Anwendung direkt zugreifen kann, z. B. auf einem externen Speicher.Um es überhaupt nicht in Flash zu schreiben, müssten Sie Ihre eigene implementieren
ContentProvider
, herausfinden, wieopenFile()
Sie die speicherinterne Bitmap zurückgeben, und dann eineUri
Darstellung dieser Bitmap in der übergebenACTION_SEND
Intent
. Da a zurückgegeben werdenopenFile()
muss,ParcelFileDescriptor
weiß ich nicht, wie Sie dies ohne eine Darstellung auf der Festplatte tun würden, aber ich habe nicht viel Zeit mit der Suche verbracht.Wenn Sie es einfach nicht im externen Speicher haben möchten, können Sie den
ContentProvider
Weg mithilfe einer Datei im internen Speicher gehen. Dieses Beispielprojekt zeigt ein ProjektContentProvider
, das eine PDF-Datei überACTION_VIEW
einen PDF-Viewer auf einem Gerät bereitstellt. der gleiche Ansatz könnte für verwendet werdenACTION_SEND
.quelle
getCacheDir()
wie es in dieser SO-Antwort vorgeschlagen wird ?Wenn jemand noch nach einer einfachen und kurzen Lösung ohne Speichererlaubnis sucht (unterstützt auch Nougat 7.0). Hier ist es.
Fügen Sie dies im Manifest hinzu
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider>
Erstellen Sie nun provider_paths.xml
<paths> <external-path name="external_files" path="."/> </paths>
Fügen Sie diese Methode schließlich zu Ihrer Aktivität / Ihrem Fragment hinzu (rootView ist die Ansicht, die Sie freigeben möchten).
private void ShareIt(View rootView){ if (rootView != null && context != null && !context.isFinishing()) { rootView.setDrawingCacheEnabled(true); Bitmap bitmap = Bitmap.createBitmap(rootView.getDrawingCache()); if (bitmap != null ) { //Save the image inside the APPLICTION folder File mediaStorageDir = new File(AppContext.getInstance().getExternalCacheDir() + "Image.png"); try { FileOutputStream outputStream = new FileOutputStream(String.valueOf(mediaStorageDir)); bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (ObjectUtils.isNotNull(mediaStorageDir)) { Uri imageUri = FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() + ".provider", mediaStorageDir); if (ObjectUtils.isNotNull(imageUri)) { Intent waIntent = new Intent(Intent.ACTION_SEND); waIntent.setType("image/*"); waIntent.putExtra(Intent.EXTRA_STREAM, imageUri); startActivity(Intent.createChooser(waIntent, "Share with")); } } } } }
Aktualisieren:
Wie @Kathir in den Kommentaren erwähnt hat,
DrawingCache
ist von API 28+ veraltet. Verwenden SieCanvas
stattdessen den folgenden Code .Bitmap bitmap = Bitmap.createBitmap(rootView.getWidth(), rootView.getHeight(), quality); Canvas canvas = new Canvas(bitmap); Drawable backgroundDrawable = view.getBackground(); if (backgroundDrawable != null) { backgroundDrawable.draw(canvas); } else { canvas.drawColor(Color.WHITE); } view.draw(canvas); return bitmap;
quelle
DrawingCache
ist von API 28+ veraltet. Verwenden Sie dazu Canvas oder PixelCopy . Beispiel für die Verwendung von Canvas . Und vergessen Sie nicht, die Hintergrundfarbe (entweder auf Ihreview
oderBitmap
) einzustellen , sonst erhalten Sie einen schwarzen HintergrundDies dient zum Freigeben von CardView als Image und zum Speichern im Cache-Unterverzeichnis des internen Speicherbereichs der App. hoffe es wird hilfreich sein.
@Override public void onClick(View view) { CardView.setDrawingCacheEnabled(true); CardView.buildDrawingCache(); Bitmap bitmap = CardView.getDrawingCache(); try{ File file = new File(getContext().getCacheDir()+"/Image.png"); bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file)); Uri uri = FileProvider.getUriForFile(getContext(),"com.mydomain.app", file); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, uri); shareIntent.setType("image/jpeg"); getContext().startActivity(Intent.createChooser(shareIntent, "Share")); }catch (FileNotFoundException e) {e.printStackTrace();} } });
quelle
Hier Verfahren arbeitet , um einen Screenshot von eigenen App zu machen und teilen Sie es als Bild über jeden Messenger oder E - Mail - Client.
Um dies zu beheben , die Bitmap nicht aktualisieren Problem , das ich verbessern Suragch ‚s Antwort, mit Gurupad Mamadapur ‘ s Kommentar und hinzugefügt eigene Modifikationen.
Hier ist Code in Kotlin- Sprache:
private lateinit var myRootView:View // root view of activity @SuppressLint("SimpleDateFormat") private fun shareScreenshot() { // We need date and time to be added to image name to make it unique every time, otherwise bitmap will not update val sdf = SimpleDateFormat("yyyyMMdd_HHmmss") val currentDateandTime = sdf.format(Date()) val imageName = "/image_$currentDateandTime.jpg" // CREATE myRootView = window.decorView.rootView myRootView.isDrawingCacheEnabled = true myRootView.buildDrawingCache(true) // maybe You dont need this val bitmap = Bitmap.createBitmap(myRootView.drawingCache) myRootView.isDrawingCacheEnabled = false // SAVE try { File(this.cacheDir, "images").deleteRecursively() // delete old images val cachePath = File(this.cacheDir, "images") cachePath.mkdirs() // don't forget to make the directory val stream = FileOutputStream("$cachePath$imageName") bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream) // can be png and any quality level stream.close() } catch (ex: Exception) { Toast.makeText(this, ex.javaClass.canonicalName, Toast.LENGTH_LONG).show() // You can replace this with Log.e(...) } // SHARE val imagePath = File(this.cacheDir, "images") val newFile = File(imagePath, imageName) val contentUri = FileProvider.getUriForFile(this, "com.example.myapp.fileprovider", newFile) if (contentUri != null) { val shareIntent = Intent() shareIntent.action = Intent.ACTION_SEND shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // temp permission for receiving app to read this file shareIntent.type = "image/jpeg" // just assign type. we don't need to set data, otherwise intent will not work properly shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri) startActivity(Intent.createChooser(shareIntent, "Choose app")) } }
quelle