@strasberry/capacitor-cast
v1.0.0
Published
This is a plugin for Capacitor that enables cast functionality for web, iOS and Android.
Downloads
372
Readme
@strasberry/capacitor-cast
Capacitor plugin to control Google Cast sessions from Web, iOS, and Android with one API.
Install
npm install @strasberry/capacitor-cast
npx cap syncQuickstart
import { Cast } from '@strasberry/capacitor-cast';
await Cast.initialize();
const capabilities = await Cast.getCapabilities();
if (!capabilities.isSupported) {
// Platform/runtime does not expose Google Cast sender APIs.
return;
}
await Cast.showDevicePicker();
await Cast.loadMedia({
url: 'https://example.com/video.mp4',
contentType: 'video/mp4',
title: 'My Video',
autoplay: true,
});Documentation
- Documentation index
- Getting Started
- Configuration
- Platform index
- Platform details:
- Runtime & Permissions API
- Advanced Usage Example
- Angular + Ionic Standalone CastService Example
- Troubleshooting
- Official Chromecast resources
Platform Prerequisites
Web
- Run in a secure context (
https://) orhttp://localhostduring development. - Use a Cast sender-compatible browser/runtime. Mobile browser support is limited.
- Ensure sender and receiver are on reachable networks and cast discovery is allowed.
- Full Web platform guide: docs/platforms/web.md
iOS
- The plugin ships with Swift Package support and is validated with:
npm run verify:ios- If your Capacitor iOS app uses Swift Package Manager, keep the generated
CapApp-SPMsetup and runnpx cap sync iosafter updates. - For Cast discovery on iOS 14+, provide Local Network + Bonjour entries in your app
Info.plist:NSLocalNetworkUsageDescriptionNSBonjourServicesincluding_googlecast._tcpand your app-specific Cast service (for example_<APP_ID>._googlecast._tcp)
- Full iOS platform guide: docs/platforms/ios.md
Android
- The plugin bundles Google Cast framework dependency and registers its Cast
OptionsProvidervia manifest merge. - If the host app already defines
com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME, keep only one provider and ensurereceiverApplicationIdis consistently configured. - Full Android platform guide: docs/platforms/android.md
Compatibility
- Capacitor:
@capacitor/core >= 8.0.0 - iOS deployment target:
15.0+ - Android min SDK:
24+ - Android target SDK in plugin template:
36
Configuration
Set plugin values in capacitor.config.ts (or capacitor.config.json):
/// <reference types="@strasberry/capacitor-cast" />
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
plugins: {
Cast: {
uiMode: 'picker',
autoJoinPolicy: 'origin_scoped',
},
},
};
export default config;receiverApplicationId: optional. Defaults toCC1AD845(Default Media Receiver) when omitted.receiverAppId: backward-compatible alias forreceiverApplicationId.uiMode: optional, defaults topicker.autoJoinPolicy: optional, defaults toorigin_scoped.- Detailed config guide: docs/configuration.md
uiMode behavior:
picker:showDevicePicker()andrequestSession()can open device chooser.headless:showDevicePicker()rejects withUI_MODE_NOT_AVAILABLE;requestSession()can only resume an already active session.nativeButton: host-native cast UI drives connection;showDevicePicker()andrequestSession()reject withUI_MODE_NOT_AVAILABLE.
autoJoinPolicy accepted values:
origin_scoped(default)tab_and_origin_scopedpage_scoped
Call initialize() once before any cast method. Configuration is read from Capacitor plugin config and is not overridden at runtime.
On web-only runtime, ensure window.Capacitor.config.plugins.Cast (or plugins.cast) is available before initialize().
Lifecycle & Events
- Register listeners once per app lifecycle (avoid rebinding the same callbacks on each render/re-init).
- Supported listener events:
castErrormessageReceived
- Read runtime state explicitly via:
getCastState()getSession()getMediaStatus()
- Snapshot payloads are intentionally platform-specific and thin:
- Web
getCastState()aligns withcast.framework.CastStateEventDatashape. - Web
getMediaStatus()aligns withcast.framework.RemotePlayershape.
- Web
- On web, trigger
showDevicePicker()/requestSession()from a direct user gesture.
Migration Notes (vNext)
getCastState().castStateis now a raw snapshot object (ornull), not a normalized string.- Web
getMediaStatus().mediaStatusnow exposesRemotePlayersnapshot data. - Session snapshots no longer include plugin-derived connection booleans (
isConnected,isConnecting) on native platforms.
Custom Messaging (Generic)
Use custom namespaces to exchange arbitrary application messages with your receiver.
await Cast.subscribeNamespace({ namespace: 'urn:x-cast:com.example.channel' });
await Cast.sendMessage({
namespace: 'urn:x-cast:com.example.channel',
message: {
action: 'PING',
timestamp: new Date().toISOString(),
},
});
await Cast.addListener('messageReceived', (event) => {
console.log(event.namespace, event.message, event.raw);
});- The plugin only transports namespace + payload.
- Message schema and protocol versioning are fully owned by your app sender/receiver.
- Incoming JSON strings are parsed to objects when possible; otherwise payload is exposed as raw string.
Error Handling
The plugin emits and rejects with typed CastErrorCode values:
UNSUPPORTED_PLATFORM: Cast sender runtime is unavailable.NOT_INITIALIZED:initialize()has not been called yet.NO_ACTIVE_SESSION: operation requires an active cast session.INVALID_ARGUMENT: missing or invalid method input.UI_MODE_NOT_AVAILABLE: method not available for currentuiMode.OPERATION_FAILED: native/web Cast SDK operation failed.
Troubleshooting
- No devices discovered:
- Verify Web secure context, local network reachability, and iOS local network permissions.
UNSUPPORTED_PLATFORMon Web:- Confirm a Cast sender-compatible browser/runtime and successful sender SDK load.
- Ensure
window.Capacitor.config.plugins.Castexists beforeinitialize().
- Web console logs
GET chrome-extension://invalid/ net::ERR_FAILED:- This can be emitted by Google Cast sender bootstrap and is often non-blocking.
- Verify actual impact through
initialize().isSupportedandgetCapabilities().canShowDevicePicker.
NO_ACTIVE_SESSIONon media controls:- Start or resume a cast session before calling
loadMedia,play,pause,seek, or volume methods.
- Start or resume a cast session before calling
- Session resume not working in
headlessmode:- Ensure a restorable cast session exists;
headlesswill not open a picker.
- Ensure a restorable cast session exists;
- Android app already has Cast integration:
- Resolve
OPTIONS_PROVIDER_CLASS_NAMEownership to a single provider.
- Resolve
- Android logs many
Invalid stack map tablewarnings incom.google.android.gms.cast:- Disable Jetifier (
android.enableJetifier=false) or exclude Cast artifacts withandroid.jetifier.ignorelist.
- Disable Jetifier (
- Xcode warns about
example-app/node_modules/.../.swiftpm/xcodewhen plugin is linked locally:- Remove example artifacts from the plugin workspace:
rm -rf example-app/node_modules example-app/.swiftpm
- Remove example artifacts from the plugin workspace:
- Full troubleshooting guide: docs/troubleshooting.md
API
isInitialized()checkPermissions()requestPermissions()initialize()getCapabilities()getCastState()getSession()requestSession()showDevicePicker()endSession(...)loadMedia(...)play()pause()stop()seek(...)setVolume(...)setMuted(...)getMediaStatus()sendMessage(...)subscribeNamespace(...)unsubscribeNamespace(...)addListener('castError', ...)addListener('messageReceived', ...)removeAllListeners()- Interfaces
- Type Aliases
isInitialized()
isInitialized() => Promise<IsInitializedResult>Returns whether the plugin has been initialized.
Returns: Promise<IsInitializedResult>
checkPermissions()
checkPermissions() => Promise<CastPermissionStatus>Returns the current local network permission status.
Returns: Promise<CastPermissionStatus>
requestPermissions()
requestPermissions() => Promise<CastPermissionStatus>Requests local network permission when applicable.
Returns: Promise<CastPermissionStatus>
initialize()
initialize() => Promise<InitializeResult>Initializes the plugin from capacitor.config.* values.
Returns: Promise<InitializeResult>
getCapabilities()
getCapabilities() => Promise<CastCapabilities>Returns the capabilities for the current platform/runtime.
Returns: Promise<CastCapabilities>
getCastState()
getCastState() => Promise<CastStateResult>Returns the current cast state from the underlying SDK.
Returns: Promise<CastStateResult>
getSession()
getSession() => Promise<SessionResult>Returns the currently active cast session snapshot if any.
Returns: Promise<SessionResult>
requestSession()
requestSession() => Promise<void>Requests a cast session.
showDevicePicker()
showDevicePicker() => Promise<void>Opens the cast device picker when available for the configured UI mode.
endSession(...)
endSession(options?: EndSessionOptions | undefined) => Promise<void>Ends the active cast session.
| Param | Type |
| ------------- | --------------------------------------------------------------- |
| options | EndSessionOptions |
loadMedia(...)
loadMedia(request: LoadMediaRequest) => Promise<LoadMediaResult>Loads media in the active cast session.
| Param | Type |
| ------------- | ------------------------------------------------------------- |
| request | LoadMediaRequest |
Returns: Promise<LoadMediaResult>
play()
play() => Promise<void>Resumes playback for the active media item.
pause()
pause() => Promise<void>Pauses playback for the active media item.
stop()
stop() => Promise<void>Stops playback for the active media item.
seek(...)
seek(options: SeekOptions) => Promise<void>Seeks the active media item to a position in seconds.
| Param | Type |
| ------------- | --------------------------------------------------- |
| options | SeekOptions |
setVolume(...)
setVolume(options: SetVolumeOptions) => Promise<void>Sets remote device volume in range [0, 1].
| Param | Type |
| ------------- | ------------------------------------------------------------- |
| options | SetVolumeOptions |
setMuted(...)
setMuted(options: SetMutedOptions) => Promise<void>Sets remote device muted state.
| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | SetMutedOptions |
getMediaStatus()
getMediaStatus() => Promise<MediaStatusResult>Returns the current media status snapshot if available.
Returns: Promise<MediaStatusResult>
sendMessage(...)
sendMessage(options: SendMessageOptions) => Promise<void>Sends a custom message to the active cast session on the provided namespace.
| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| options | SendMessageOptions |
subscribeNamespace(...)
subscribeNamespace(options: NamespaceOptions) => Promise<void>Subscribes native/web SDK message callbacks for an explicit namespace.
| Param | Type |
| ------------- | ------------------------------------------------------------- |
| options | NamespaceOptions |
unsubscribeNamespace(...)
unsubscribeNamespace(options: NamespaceOptions) => Promise<void>Unsubscribes native/web SDK message callbacks for an explicit namespace.
| Param | Type |
| ------------- | ------------------------------------------------------------- |
| options | NamespaceOptions |
addListener('castError', ...)
addListener(eventName: 'castError', listenerFunc: (event: CastErrorEvent) => void) => Promise<PluginListenerHandle>Listens for typed cast errors.
| Param | Type |
| ------------------ | ----------------------------------------------------------------------------- |
| eventName | 'castError' |
| listenerFunc | (event: CastErrorEvent) => void |
Returns: Promise<PluginListenerHandle>
addListener('messageReceived', ...)
addListener(eventName: 'messageReceived', listenerFunc: (event: MessageReceivedEvent) => void) => Promise<PluginListenerHandle>Listens for incoming custom namespace messages.
| Param | Type |
| ------------------ | ----------------------------------------------------------------------------------------- |
| eventName | 'messageReceived' |
| listenerFunc | (event: MessageReceivedEvent) => void |
Returns: Promise<PluginListenerHandle>
removeAllListeners()
removeAllListeners() => Promise<void>Removes all plugin listeners.
Interfaces
IsInitializedResult
| Prop | Type |
| ------------------- | -------------------- |
| isInitialized | boolean |
CastPermissionStatus
| Prop | Type |
| ------------------ | ----------------------------------------------------------- |
| localNetwork | PermissionState |
InitializeResult
| Prop | Type |
| --------------------------- | ------------------------------------------------- |
| isSupported | boolean |
| uiMode | CastUiMode |
| receiverApplicationId | string |
CastCapabilities
| Prop | Type |
| ---------------------------- | -------------------- |
| isSupported | boolean |
| canRequestSession | boolean |
| canShowDevicePicker | boolean |
| supportsMediaControl | boolean |
| supportsVolumeControl | boolean |
| supportsCustomChannels | boolean |
CastStateResult
| Prop | Type |
| --------------- | --------------------------------------------------------------- |
| castState | CastStateSnapshot |
SessionResult
| Prop | Type |
| ------------- | --------------------------------------------------------------------------- |
| session | CastSessionSnapshot | null |
EndSessionOptions
| Prop | Type |
| ----------------- | -------------------- |
| stopCasting | boolean |
LoadMediaResult
| Prop | Type |
| --------------- | ------------------- |
| requestId | string |
LoadMediaRequest
| Prop | Type | Description |
| -------------------- | ---------------------------------------------------------------- | --------------------------------------------------------- |
| url | string | Media URL reachable by the receiver device. |
| contentType | string | MIME type of the media (for example video/mp4). |
| title | string | Convenience title field mapped to receiver metadata. |
| subtitle | string | Convenience subtitle field mapped to receiver metadata. |
| posterUrl | string | Poster image URL added to metadata images when provided. |
| streamType | CastStreamType | Stream type used by Cast receivers. |
| autoplay | boolean | Whether playback should start automatically after load. |
| currentTime | number | Initial playback position in seconds. |
| customData | Record<string, unknown> | Custom payload forwarded to the receiver load request. |
| tracks | CastTrack[] | Optional text/audio/video tracks for the media item. |
| activeTrackIds | number[] | Active track identifiers to enable right after loading. |
| metadata | CastMediaMetadata | Optional metadata payload merged with convenience fields. |
CastTrack
| Prop | Type |
| ----------------- | ---------------------------------------------------------------- |
| trackId | number |
| type | 'TEXT' | 'AUDIO' | 'VIDEO' |
| name | string |
| language | string |
| subtype | string |
| contentId | string |
| contentType | string |
| customData | Record<string, unknown> |
CastMediaMetadata
| Prop | Type |
| ----------------- | ---------------------------------------------------------------- |
| title | string |
| subtitle | string |
| studio | string |
| releaseDate | string |
| images | string[] |
| customData | Record<string, unknown> |
SeekOptions
| Prop | Type |
| -------------- | ------------------- |
| position | number |
SetVolumeOptions
| Prop | Type |
| ----------- | ------------------- |
| level | number |
SetMutedOptions
| Prop | Type |
| ----------- | -------------------- |
| muted | boolean |
MediaStatusResult
| Prop | Type |
| ----------------- | ----------------------------------------------------------------------------------- |
| mediaStatus | CastMediaStatusSnapshot | null |
SendMessageOptions
| Prop | Type | Description |
| --------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| namespace | string | Cast message namespace (for example urn:x-cast:com.example.channel). |
| message | string | Record<string, unknown> | Message payload sent to the receiver. |
NamespaceOptions
| Prop | Type | Description |
| --------------- | ------------------- | ---------------------------------------------------------------------- |
| namespace | string | Cast message namespace (for example urn:x-cast:com.example.channel). |
PluginListenerHandle
| Prop | Type |
| ------------ | ----------------------------------------- |
| remove | () => Promise<void> |
CastErrorEvent
| Prop | Type | Description |
| ------------- | ---------------------------------------------------------------- | --------------------------------------------------- |
| code | CastErrorCode | Stable plugin error code. |
| message | string | Human-readable error message. |
| method | string | Plugin method that emitted or propagated the error. |
| data | Record<string, unknown> | Optional platform-specific diagnostic payload. |
MessageReceivedEvent
| Prop | Type | Description |
| --------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| namespace | string | Namespace on which the message was received. |
| message | string | Record<string, unknown> | Parsed message payload when JSON object parsing succeeds, otherwise raw string. |
| raw | string | Raw message string when available from the Cast SDK. |
Type Aliases
PermissionState
'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'
CastUiMode
'picker' | 'nativeButton' | 'headless'
CastStateSnapshot
Raw cast state snapshot (platform-specific shape).
Record<string, unknown> | null
Record
Construct a type with a set of properties K of type T
{ [P in K]: T; }
CastSessionSnapshot
Raw session snapshot (platform-specific shape).
Record<string, unknown>
CastStreamType
'BUFFERED' | 'LIVE' | 'OTHER'
CastMediaStatusSnapshot
Raw media status snapshot (platform-specific shape).
Record<string, unknown>
CastErrorCode
'UNSUPPORTED_PLATFORM' | 'NOT_INITIALIZED' | 'NO_ACTIVE_SESSION' | 'INVALID_ARGUMENT' | 'UI_MODE_NOT_AVAILABLE' | 'OPERATION_FAILED'
