@flare-engine/share
Cross-platform screenshot capture (Skia makeImageSnapshot) + share-sheet orchestration with pluggable transports. captureScreenshot(source, opts?) returns { bytes, base64, format, width, height }. ShareManager cascades through registered transports — first one whose canShare(payload) returns true wins. Built-in transports cover Web Share API, Web Clipboard fallback, native RN Share, and expo-sharing (image files, for Android screenshots). createScreenshotScene wires a one-shot capture scene for store-asset workflows.
Install
bun add @flare-engine/share
Usage
import { Share } from 'react-native';
import { captureScreenshot, ShareManager, createNativeShareTransport,
createWebShareTransport, createWebClipboardTransport } from '@flare-engine/share';
import type { CaptureSource } from '@flare-engine/share';
declare const source: CaptureSource;
const shot = captureScreenshot(source, { format: 'png' });
const share = new ShareManager()
.register(createNativeShareTransport(Share))
.register(createWebShareTransport(navigator, File))
.register(createWebClipboardTransport(navigator));
if (shot) {
await share.share({ message: 'New high score! https://example.com', screenshot: shot });
}
Platform notes:
createWebShareTransportattaches the screenshot as aFilewhen the browser'snavigator.canShare({ files })accepts it.createNativeShareTransportattaches it on iOS as adata:image/<format>;base64,…URL, only whenurlis unset — an expliciturlwins and no image is attached then. Android's RNShareforwards onlytitleandmessage, so put a link inmessage; the image is not attached there, and a payload with a screenshot but nomessageopens an empty sheet that still reportsdispatched: true.createWebClipboardTransportcopiesmessageandurltext only.createExpoShareTransportshares the screenshot as an image file; see below.
Android screenshots
RN's Share cannot attach an image on Android. createExpoShareTransport(sharing, files) writes
the screenshot to a file and hands its URI to expo-sharing. Register it before the RN
transport: its canShare is true only when the payload has a screenshot, so screenshot payloads
reach expo-sharing and text-only payloads fall through to RN Share.
import { Share } from 'react-native';
import * as Sharing from 'expo-sharing';
import { File, Paths } from 'expo-file-system';
import { createExpoShareTransport, createNativeShareTransport, ShareManager } from '@flare-engine/share';
import type { ShareFileWriterLike } from '@flare-engine/share';
const files: ShareFileWriterLike = {
async writeBase64File(name, base64) {
const f = new File(Paths.cache, name);
await f.write(base64, { encoding: 'base64' });
return f.uri;
},
};
const share = new ShareManager()
.register(createExpoShareTransport(Sharing, files))
.register(createNativeShareTransport(Share));
files is one callback that writes base64 data to a file and resolves to its URI. The adapter
above uses the File API of expo-file-system 58, where write creates the file or overwrites
it. With the expo-file-system/legacy entry, write it this way instead:
import { cacheDirectory, writeAsStringAsync } from 'expo-file-system/legacy';
import type { ShareFileWriterLike } from '@flare-engine/share';
const files: ShareFileWriterLike = {
async writeBase64File(name, base64) {
const uri = `${cacheDirectory}${name}`;
await writeAsStringAsync(uri, base64, { encoding: 'base64' });
return uri;
},
};
Limits:
expo-sharingshares one file and no text. The screenshot goes out alone:messageandurlare dropped, andtitlebecomes the chooser'sdialogTitle.- The file is always named
screenshot.<format>, so each share overwrites the previous one. - The result is
{ dispatched: true, via: 'native' }once the sheet has opened;expo-sharingdoes not say whether the user finished the share. WhenisAvailableAsync()resolves false, nothing is written and the result is{ dispatched: false, via: 'native' }. A failed write or a rejectedshareAsyncrejects theshare()promise.
See API spec.
License
Apache-2.0