Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Android’s sharing system, not a custom publisher for every network. Render your app data into an image, save it behind a secure content:// URI, then send that URI with an ACTION_SEND intent. Intent.createChooser() opens the Android Sharesheet so the user can select an installed social or messaging app.

This approach keeps your template design inside your app while leaving delivery to Android and the destination app. The destination can resize, crop, add editing controls, or reject the format, so test the complete flow with the apps and Android versions you support.

What the implementation does

A dynamic image template is an app-side rendering step. Your code combines values such as a title, score, price, chart, avatar, or user-selected photo with a fixed layout and produces a PNG, JPEG, WebP, or another format. The resulting file is exposed through a FileProvider (or another supported provider such as MediaStore). An ACTION_SEND intent then carries the provider’s URI in Intent.EXTRA_STREAM.

The receiving activity must be able to read that URI. Do not pass a private filesystem path and assume another app can open it. Grant temporary read access with the intent flags; Android expires that grant automatically.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Design the template before writing sharing code

Choose destination-safe dimensions

Social services use different aspect ratios and may crop or resize incoming images. Select a primary output ratio for your intended destinations, keep essential text away from edges, and preview the result at the smaller size a recipient may display. If one design cannot work everywhere, render separate variants rather than shrinking everything into an unreadable canvas.

Keep text and imagery legible

  • Use a clear hierarchy: one headline, a supporting value, and optional attribution or branding.
  • Reserve safe margins for destination cropping and rounded previews.
  • Check long localized strings, large numbers, missing avatars, and dark or light user images.
  • Let the user review the rendered image before opening the Sharesheet.

Balance format, quality, and size

JPEG is broadly compatible for photographs; PNG preserves sharp text and transparency; WebP and AVIF can reduce size when the destination accepts them. Android’s media-sharing guidance recommends balancing compression and quality. Confirm the actual format acceptance and size limits of each destination before you promise support.

Render an image from app data (Kotlin example)

The following example draws a simple card into a bitmap. It deliberately keeps rendering separate from sharing, so you can substitute Canvas, Jetpack Compose, a server-rendered asset, or another template engine.

fun renderShareCard(context: Context, title: String, value: String): File {
    val width = 1200
    val height = 630
    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    canvas.drawColor(Color.rgb(24, 28, 36))

    val titlePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.WHITE
        textSize = 64f
        typeface = Typeface.DEFAULT_BOLD
    }
    val valuePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.rgb(122, 211, 255)
        textSize = 110f
        typeface = Typeface.DEFAULT_BOLD
    }

    canvas.drawText(title, 72f, 170f, titlePaint)
    canvas.drawText(value, 72f, 330f, valuePaint)

    val file = File.createTempFile("share-card-", ".png", context.cacheDir)
    FileOutputStream(file).use { output ->
        check(bitmap.compress(Bitmap.CompressFormat.PNG, 100, output))
    }
    bitmap.recycle()
    return file
}

For a production template, measure text and wrap or truncate it rather than drawing unbounded strings. Generate the file off the main thread, remove temporary files after the receiving app has had time to read them, and handle storage failures as a normal user-visible error.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Expose the file securely with FileProvider

Add the provider to the manifest

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

Allow only the directory you use

Create res/xml/file_paths.xml. A cache directory is appropriate for an image that exists only for sharing.

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <cache-path name="share_cache" path="share/" />
</paths>

Write the rendered file under context.cacheDir/share/, then obtain its URI:

val shareFile = File(File(context.cacheDir, "share"), "card.png")
shareFile.parentFile?.mkdirs()
// Write your rendered bitmap to shareFile before calling getUriForFile.
val uri = FileProvider.getUriForFile(
    context,
    "${context.packageName}.fileprovider",
    shareFile
)

Keep the provider non-exported and grant access only for the URI being shared. Never broaden the configured path unnecessarily.

Open the Android Sharesheet for one image

fun shareImage(context: Context, imageUri: Uri, mimeType: String) {
    val sendIntent = Intent(Intent.ACTION_SEND).apply {
        type = mimeType
        putExtra(Intent.EXTRA_STREAM, imageUri)
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }

    val chooser = Intent.createChooser(sendIntent, null).apply {
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }
    context.startActivity(chooser)
}

Call it with the MIME type matching the bytes you created, for example image/png, image/jpeg, or image/webp. A specific type gives Android better intent matching than a generic wildcard. If there is no compatible activity, catch ActivityNotFoundException and offer to save the image or copy a link instead.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Include optional text carefully

You may add a caption or link with Intent.EXTRA_TEXT:

val sendIntent = Intent(Intent.ACTION_SEND).apply {
    type = "image/png"
    putExtra(Intent.EXTRA_STREAM, imageUri)
    putExtra(Intent.EXTRA_TEXT, "See my latest result: https://example.com/result/123")
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}

Android 10 (API level 29) introduced richer text previews in the Sharesheet, including optional title and thumbnail metadata. That preview is not a guarantee that every destination will publish the caption, link, or thumbnail. Verify behavior in each target app.

Share multiple rendered images

Use ACTION_SEND_MULTIPLE only when the user is intentionally sharing more than one image. Supply an ArrayList<Uri> and a type suitable for the files.

fun shareImages(context: Context, uris: ArrayList<Uri>, mimeType: String) {
    val intent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
        type = mimeType
        putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }
    context.startActivity(Intent.createChooser(intent, null))
}

Some receiving apps accept only one item or apply their own ordering and editing rules. Treat that as destination-specific behavior, not an Android guarantee.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Optional chooser enhancements by Android version

Android 10 and later (API 29+)

Text-preview behavior can make a caption easier to review before the user selects a destination. Keep the ordinary image share working when preview metadata is unavailable.

Android 14 and later (API 34+)

Custom Sharesheet actions are documented for API 34 and later. They are optional enhancements, not prerequisites for sending an image. Gate them by SDK level and retain the normal chooser path for older devices.

FileProvider versus MediaStore

Choice Use it when Important consideration
FileProvider The rendered asset is temporary and owned by your app. Configure narrow paths and grant temporary URI permission.
MediaStore The user should keep the image in shared device media. Manage media insertion and lifecycle rather than deleting a private cache file immediately.

Both provide content URIs that other apps can read when permission is granted. Choose based on whether the output is a transient share artifact or a user-visible saved asset.

Validate the complete flow

  1. Render with short, long, translated, empty, and unusually large values.
  2. Inspect the output dimensions, MIME type, transparency, and file size before sharing.
  3. Install several intended destination apps and confirm they appear in the Sharesheet.
  4. Open each destination and verify that it can read the URI after your activity leaves the foreground.
  5. Test Android versions you support, including a device without any compatible share target.
  6. Test dark mode, slow storage, process recreation, and rotation while rendering.
  7. Check that temporary files are cleaned up without deleting a file before the recipient reads it.

Troubleshooting common failures

No apps appear in the Sharesheet

Likely causes are an incorrect MIME type, an unsupported action, or no installed activity that accepts images. Use the actual output type, try a known compatible destination, and provide a save-to-device fallback.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“Permission denied” in the receiving app

The URI may be a private file:// URI, the provider authority may not match, or the read flag was omitted. Return a content:// URI from FileProvider.getUriForFile(), verify the manifest authority, and add FLAG_GRANT_READ_URI_PERMISSION.

The receiver says the file is invalid

Check that rendering completed and the stream was closed before launching the chooser. Ensure the declared MIME type matches the encoded bytes and that the file has nonzero length.

The image is cropped or text is missing

The destination is applying its own aspect ratio or editor. Keep critical content inside safe margins, render a destination-specific variant, and test the current destination app rather than relying on the chooser preview.

Caption behavior differs between apps

EXTRA_TEXT is an optional payload. Some apps ignore it, place it in an editor, or alter links. Treat caption delivery as destination-specific and avoid promising automatic publication.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and privacy notes

  • Render and compress on a worker thread; large bitmaps can cause memory pressure.
  • Reuse decoded assets where practical, but do not retain full-resolution bitmaps longer than needed.
  • Keep personal data in the image to the minimum the user intends to share and show a review screen.
  • Use deterministic template inputs so a retry produces the same visual result.
  • Do not log access tokens, private URLs, or the full contents of a personalized image.
  • When sharing remote images, download and validate them before rendering so a failed network request cannot produce a misleading blank card.

Or skip the browser setup:

If your app or backend needs a clean screenshot of a web page rather than a locally rendered Android card, ScreenshotNeo provides a website screenshot API and MCP server. One request returns PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; those steps can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo API documentation for parameters and authentication.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo includes full-page capture with lazy images, CSS-selector element capture, device presets, custom viewport and retina scale, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, caching with your chosen TTL, signed links, asynchronous jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API, and an OpenAPI specification. Every feature is on every plan: 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots, with yearly billing giving two months free. Create a free ScreenshotNeo account to start.

Frequently Asked Questions

Can I force a particular social app to open?

You can target a specific package with an explicit intent, but the general user-friendly flow is the Android Sharesheet. Destination availability and behavior change, so keep the chooser or another fallback unless your product requirement is app-specific.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should the template be generated on the device or on a server?

Either works. Device rendering gives immediate previews and avoids an upload; server rendering can centralize fonts, branding, and heavy assets. In both cases, finish with a readable image exposed through a content URI before invoking the chooser.

Is a screenshot the same as a dynamic share image?

No. A template is a designed rendering of selected data. A screenshot captures a page or interface. Use the template flow for app-generated cards and a screenshot service when the source is a web page.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.