social_share_kit

Share text, links and files directly to a chosen app — X, WhatsApp, Instagram, Facebook, Threads, Telegram, LinkedIn, Messenger, TikTok, SMS, mail — or to the system share sheet.

Two things set it apart from a share-sheet wrapper:

  • It tells you what will work before you try. What each app accepts differs sharply by platform. X takes text and up to four images on Android, but only text on iOS. Instagram strips pre-filled captions everywhere. SocialShareKit.capabilities() reports all of it up front, so you can disable a button instead of discovering the limit after the user taps it.
  • It bundles no vendor SDKs by default. Sharing goes through published URL schemes, Android intents and system composers, so the base install needs no app id, no client token and no AppDelegate wiring. Where a vendor SDK genuinely buys something, it is a separate opt-in package: social_share_kit_facebook gives you the native Facebook Share Dialog on both platforms. You pay for it only if you want it.
final result = await SocialShareKit.shareTo(
  ShareTarget.x,
  ShareContent.text('Shipping today', url: 'https://example.com'),
);

switch (result.status) {
  case ShareStatus.success:        // the composer opened
  case ShareStatus.appNotInstalled: // hide the button next time
  case ShareStatus.unsupportedContent: // result.message says why
  default: break;
}

Install

dependencies:
  social_share_kit: ^0.2.0

Android needs nothing. The <queries> declarations and the FileProvider ship in the plugin's own manifest and merge into your app.

iOS needs two Info.plist keys. iOS reports every app as missing unless its scheme is listed, so this is not optional:

<key>LSApplicationQueriesSchemes</key>
<array>
  <string>twitter</string>          <!-- X -->
  <string>whatsapp</string>
  <string>instagram</string>
  <string>instagram-stories</string>
  <string>barcelona</string>       <!-- Threads -->
  <string>fb</string>
  <string>facebook-stories</string>
  <string>fb-messenger</string>
  <string>tg</string>              <!-- Telegram -->
  <string>linkedin</string>
  <string>snssdk1233</string>      <!-- TikTok -->
</array>

<!-- Only if you share to Instagram feed or Reels -->
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Saves the media you share so Instagram can open it.</string>

Trim the list to the targets you offer; Apple caps it at 50 entries. The Facebook add-on needs two more entries and some app-id wiring — see its README.

What each target accepts

supported · clip accepted but the app strips it, so it goes to the clipboard · not supported

Target Android iOS
x text · link · 4 media text · link
whatsapp text · link · files text · link · 1 image
instagramFeed clip · 10 media clip · 1 media
instagramReels clip · 1 video clip · 1 video
instagramDirect text · link text · link
instagramStory story story
facebook clip · link · 10 media — †
facebook + add-on link · 6 photos or 1 video · cancel reported link · 6 photos or 1 video · cancel reported
facebookStory story story
messenger text · link · media link only
telegram text · link · files text · link
threads text · link · 10 media clip
linkedinFeed text · link · 1 image clip + link
linkedinDirect text · link · 1 image text · link
tiktok clip · 35 media — ‡
sms text · link · files text · link · files · cancel reported
email text · link · files · subject text · link · files · subject · cancel reported
systemSheet everything everything · cancel reported
clipboard text text

† Fixed by the Facebook add-on. Without it, Facebook's iOS app publishes no sharing URL scheme, so there is nothing to open. ‡ Needs TikTok's OpenSDK. No add-on for it yet — use fallbackToSystemSheet: true.

Read this at runtime rather than from the table:

final caps = SocialShareKit.capabilities(ShareTarget.x);
caps.supportsFiles   // false on iOS, true on Android
caps.maxFiles        // 4 on Android
caps.textLimit       // 280
caps.prefillsText    // false for Instagram, Facebook, TikTok
caps.note            // the caveat, in prose

Facebook

Facebook is the one target where the base package hits a wall it cannot argue with: the Facebook iOS app publishes no sharing URL scheme. There is no intent system on iOS and no deep link to open, so ShareTarget.facebook returns ShareStatus.unsupportedPlatform there. On Android it works as an ordinary intent, though Facebook strips any pre-filled caption.

Adding social_share_kit_facebook replaces that with the native Share Dialog on both platforms:

dependencies:
  social_share_kit: ^0.2.0
  social_share_kit_facebook: ^0.1.0
void main() {
  SocialShareKitFacebook.register();   // the only line you add
  runApp(const MyApp());
}

// unchanged — now routed through the SDK
await SocialShareKit.shareTo(
  ShareTarget.facebook,
  ShareContent.files(['/path/photo.jpg']),
);
base package with the add-on
Android plain intent native Share Dialog
iOS unsupportedPlatform native Share Dialog
Photos via intent up to 6
Video via intent 1
Link via intent attached as a proper link
Cancellation not detectable ShareStatus.cancelled
Setup none Facebook app id + client token

Cancellation reporting is the part worth noting: SharingDelegate and FacebookCallback fire on the real outcome, so success means the dialog actually completed rather than merely opened. No URL-scheme target can tell you that.

The cost is the Facebook app registration the base package avoids — an app id and client token in Info.plist and strings.xml, plus some manifest and AppDelegate wiring. The add-on's README has the exact steps. Drop the dependency and everything reverts; no call site changes either way.

ShareTarget.facebookStory does not need the add-on. The story composer works through a documented pasteboard and intent handoff, so it stays in the base package.

Writing your own add-on

Implement ShareTargetHandler, declare which targets it claims, and call SocialShareKit.registerHandler. A handler that widens what a target accepts must say so in capabilitiesFor — core validates content against the capability table before delegating, so a handler that does not advertise its wider surface will never be reached.

Usage

// text only
await SocialShareKit.shareTo(ShareTarget.whatsapp, ShareContent.text('Hello'));

// files only
await SocialShareKit.shareTo(
  ShareTarget.instagramFeed,
  ShareContent.files(['/path/photo.jpg']),
);

// both
await SocialShareKit.shareTo(
  ShareTarget.telegram,
  ShareContent.textWithFiles(text: 'Look', files: ['/path/a.png', '/path/b.png']),
);

// a link as a distinct field — required by the LinkedIn feed composer on iOS,
// which ignores URLs embedded in body text
await SocialShareKit.shareTo(
  ShareTarget.linkedinFeed,
  ShareContent.link('https://example.com', text: 'My commentary'),
);

File paths must be absolute paths to files your app can read. On Android they are handed over as content:// URIs from the plugin's own FileProvider, which covers your cache, files, and external directories.

Falling back

await SocialShareKit.shareTo(
  ShareTarget.x,
  ShareContent.files(['/path/clip.mp4']),
  fallbackToSystemSheet: true, // X takes no files on iOS — use the sheet there
);

The fallback triggers when the target cannot take this content on this platform. It does not trigger on empty content, which is a caller bug rather than a platform limit.

Stories

The only calls in the base package needing a Facebook app id — both composers require one for attribution and reject the share without it. No SDK involved.

await SocialShareKit.shareStory(
  ShareTarget.instagramStory,
  StoryContent(
    appId: '<your facebook app id>',
    backgroundImage: '/path/bg.jpg',
    stickerImage: '/path/sticker.png',   // transparent PNG
    attributionUrl: 'https://example.com',
    text: 'Copied to the clipboard for pasting',
  ),
);

A story needs a background image, a background video, or both gradient colours. Neither composer accepts pre-filled text, so text rides along on the clipboard.

Checking what is installed

final installed = await SocialShareKit.installedTargets();
if (installed[ShareTarget.whatsapp] == true) { /* show the button */ }

A target can read as missing purely because your app cannot see it — Android 11+ hides packages absent from <queries> (handled for you), iOS hides schemes absent from LSApplicationQueriesSchemes (yours to add).

Fitting text to a composer

Nothing is truncated automatically; ShareText is there when you want it.

ShareText.stripHtml('<p>Rich <b>text</b></p>');   // 'Rich text'

ShareText.truncateForTarget(
  longPost,
  ShareTarget.x,
  keepSuffix: 'https://example.com',   // reserves room so the link survives
);

What success means

That the target's composer opened. Not that the user posted — no mainstream social app reports that back, and any package claiming otherwise is guessing.

Only sms, email and systemSheet distinguish cancelled from success, because only they hand control back to your app. Everything else is a one-way URL or intent handoff. Adding the Facebook add-on puts facebook in that first group too — the SDK reports the real outcome. ShareCapabilities.reportsCancellation tells you which is which, and it follows whatever add-ons are registered.

Errors

Calls complete with a ShareResult rather than throwing — a missing app is an ordinary outcome. ArgumentError is thrown only for programming mistakes: passing a story target to shareTo, or a non-story target to shareStory.

Contributing

flutter test                      # 73 unit tests
cd example && flutter test        # widget tests
cd example && flutter test integration_test   # on a device

The capability table in lib/src/models/share_capabilities.dart is mirrored by enums in android/…/ShareTargets.kt and ios/…/ShareTarget.swift. Adding a target means touching all three; the integration test fails if the native side omits one.

Licence

MIT. See LICENSE.

Libraries

social_share_kit
Share text, links and files to specific social apps from Flutter.