Pause and resume Genuin feeds with your app lifecycle
Stop Genuin video when an embed scrolls away, your screen changes, or your app goes to the background, and start it again when the viewer comes back.
Genuin embeds, placements, and full-screen feeds start playing video once they load. Each SDK pauses on its own in some situations. In the others, the video keeps playing, sometimes with sound, until your app calls pause. This page lists what each SDK handles, then the calls for the rest.
What each SDK handles on its own
| Situation | Android 2.1.5 | iOS 2.1.5 | Web 2.0.6 |
|---|---|---|---|
| The embed scrolls out of view | A grid pauses. A carousel moves to the floating mini player when the embed has one, and otherwise keeps playing. | Pauses when the view leaves the nearest scroll view, and resumes when it comes back. | Pauses when the container leaves the viewport, and resumes when it comes back. With a floating player, playback moves to it. |
| Another screen covers yours | Embed and placement views keep playing. A full-screen feed fragment pauses in its own onPause. | Pauses 0.3 seconds after the view leaves the window, and resumes when it returns. | Not applicable. |
| The app or tab goes to the background | Embed and placement views keep playing. A full-screen feed fragment pauses. | Pauses when the app resigns active, and resumes when it's active again. | Pauses when the tab is hidden or the browser window loses focus, and resumes when it's back. |
| A phone call or similar audio interruption | Pauses on a short loss of audio focus, and resumes when focus returns. | Pauses, and resumes when iOS reports that playback can resume. | No separate handling; the tab and focus rule above applies. |
The floating mini player is the embed's Enable Floating View setting in Brand Control Center. The genuin-react-native package renders the native Android and iOS views, so those two columns apply to React Native. genuin_sdk 1.0.1 for Flutter wraps native SDK 1.1.9.x; its controls are in Step 4.
Step 1: Pause and resume on Android
- Tie every
GenuinEmbedViewandGenuinPlacementViewto the screen that hosts it. Without these calls, audio continues after the user leaves the screen or the app:
override fun onResume() {
super.onResume()
genuinEmbedView.play() // resumes autoplay on the focused tile
}
override fun onPause() {
genuinEmbedView.pause() // stays paused until the next play()
super.onPause()
}
override fun onDestroy() {
genuinEmbedView.release() // frees the players
super.onDestroy()
}In a Fragment, make the same calls from onResume, onPause, and onDestroyView. pause() sticks: the view doesn't restart when it scrolls back into view, and it waits for play(). When the user opens a video full screen, the SDK skips the next pause() so the transition plays smoothly.
- If a carousel sits in a scrolling layout and the embed has no floating player, pause it yourself when it leaves the screen:
var carouselVisible = true
scrollView.setOnScrollChangeListener { _, _, _, _, _ ->
val visible = genuinEmbedView.getLocalVisibleRect(Rect())
if (visible != carouselVisible) {
carouselVisible = visible
if (visible) genuinEmbedView.play() else genuinEmbedView.pause()
}
}- A
FeedEmbedFragmentpauses and resumes with its ownonPauseandonResume. A fragment you hide withFragmentTransaction.hide()stays resumed, so callfragment.pause()when you hide it andfragment.play()when you show it.
The SDK requests audio focus when a video plays with sound. To give focus back to your own player, call GenuinSDK.abandonAudioFocus(). To follow Genuin playback in your own UI, register GenuinSDK.registerPlayerCallback, described in Integrate the Genuin Android SDK.
Step 2: Pause and resume on iOS
GenuinEmbedView and GenuinPlacementView pause and resume on their own when the view leaves the window, when the app moves to the background, and during audio interruptions. Full-screen feeds and standard walls pause when they disappear and when the app moves to the background. You need code in two cases:
- The view stays in the window behind something else: A sheet, a popover, or your own overlay doesn't remove the embed from the window, so it keeps playing.
- Your app plays its own media: Genuin doesn't pause for audio your app starts.
pause() and play() act once. After pause(), the SDK still resumes the video when the app becomes active again or the view scrolls back into view. To hold playback until you release it, use pauseByExternalPlayer() and playByExternalPlayer():
import UIKit
import GenuinCore
final class ProductViewController: UIViewController, UIAdaptivePresentationControllerDelegate {
var embedView: GenuinEmbedView? // the view you created with GenuinEmbedView(attributes:)
func showSizeGuide(_ sheet: UIViewController) {
embedView?.pauseByExternalPlayer() // held through app switches and scrolling
sheet.presentationController?.delegate = self
present(sheet, animated: true)
}
// Runs when the person swipes the sheet away. Call playByExternalPlayer()
// wherever you dismiss the sheet in code too.
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
embedView?.playByExternalPlayer()
}
}playByExternalPlayer() resumes only a view that pauseByExternalPlayer() paused, and only while the view is in a window. If the viewer paused the video themselves, pauseByExternalPlayer() has no effect. To follow Genuin playback in your UI, set GenuinSDK.shared.playbackDelegate, described in Integrate the Genuin iOS SDK.
Step 3: Pause and resume in React Native
On iOS, the native views handle the cases in the first table, and the components ignore their ref. On Android, Feed, StandardWall, and HomeFeed are fragments that pause with your activity. Carousel is a native view with no lifecycle of its own. It keeps playing after navigation and in the background until you call its ref.
import { useCallback, useEffect, type RefObject } from 'react';
import { AppState, Platform } from 'react-native';
import { useFocusEffect } from '@react-navigation/native';
import type { PlayPauseRef } from 'genuin-react-native';
export function useGenuinPlayback(ref: RefObject<PlayPauseRef | null>) {
useFocusEffect(
useCallback(() => {
ref.current?.resume();
return () => ref.current?.pause(); // the screen loses focus or unmounts
}, [ref])
);
useEffect(() => {
if (Platform.OS !== 'android') return; // iOS pauses on its own
const subscription = AppState.addEventListener('change', (state) => {
if (state === 'active') ref.current?.resume();
else ref.current?.pause();
});
return () => subscription.remove();
}, [ref]);
}Call useGenuinPlayback(carouselRef) in the screen that renders the Carousel. On Android, pause() and resume() call the native view's pause() and play(), or the fragment's pause() and play(). When a Carousel unmounts, the package doesn't release its players, so the pause in the focus cleanup matters.
Step 4: Pause and resume in Flutter
genuin_sdk 1.0.1 has pause and resume methods on Android only. On iOS the plugin has no implementation, and each call throws MissingPluginException, so guard every call with Platform.isAndroid. Each method takes the same embedId and uniqueId you gave the widget.
| Widget | Pause | Resume |
|---|---|---|
| Carousel | pauseCarousel(Map) | resumeCarousel(Map) |
| Feed | pauseFeed(Map) | resumeFeed(Map) |
| StandardWall | pauseStandWall(Map) | resumeStandWall(Map) |
| HomeFeed | pauseHomeFeed() | resumeHomeFeed() |
Pause when the app goes to the background and when another route covers the screen. The route observer must also be in MaterialApp(navigatorObservers: [routeObserver]):
final routeObserver = RouteObserver<ModalRoute<void>>();
class _CarouselSectionState extends State<CarouselSection> with WidgetsBindingObserver, RouteAware {
final _genuin = GenuinSdk();
final Map<String, dynamic> _config = {'embedId': '{{EMBED_ID}}', 'uniqueId': 'home'};
void _pause() { if (Platform.isAndroid) _genuin.pauseCarousel(_config); }
void _resume() { if (Platform.isAndroid) _genuin.resumeCarousel(_config); }
@override
void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); }
@override
void didChangeDependencies() { super.didChangeDependencies(); routeObserver.subscribe(this, ModalRoute.of(context)!); }
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) _pause();
if (state == AppLifecycleState.resumed) _resume();
}
@override
void didPushNext() => _pause(); // another route now covers this one
@override
void didPopNext() => _resume(); // this route is visible again
@override
void dispose() { routeObserver.unsubscribe(this); WidgetsBinding.instance.removeObserver(this); super.dispose(); }
@override
Widget build(BuildContext context) =>
const SizedBox(height: 300, child: Carousel(embedId: '{{EMBED_ID}}', uniqueId: 'home'));
}The state belongs to a StatefulWidget named CarouselSection. It imports dart:io, package:flutter/material.dart, package:genuin_sdk/genuin_sdk.dart, and package:genuin_sdk/genuin_carousel_embed_view.dart. Give every widget instance its own uniqueId, because the plugin finds the view by embedId plus uniqueId.
Step 5: Pause and resume on the web
The Web SDK plays a video only while the page has focus and some part of the embed's container is in the viewport. On desktop browsers, focus follows the window's focus and blur events and the tab's visibility. On iOS Safari, it follows visibilitychange, pagehide, and pageshow. The expand view keeps playing while it's open, wherever the container is.
To hold playback yourself, for example while your own video or a modal is open, send the player commands. They apply to every embed on the page and last until you send the opposite command:
function openDialog(dialog) {
window.genuin.emit("player:pause");
dialog.showModal();
dialog.addEventListener("close", () => window.genuin.emit("player:play"), { once: true });
}After player:play, a video plays again only when its container is in view and the page has focus. To follow playback in your own UI, subscribe to onPlay and onPause. Their payloads carry isInView and isFocused, which tell you why the state changed. In a single-page app, call window.genuin.destroy() when you leave the section that shows embeds, and init again when you return.
Step 6: Test playback
Run each check with sound on, on a real device:
- Scroll the embed off the screen and back. Video stops and restarts as the first table describes, or your scroll listener takes over.
- Open another screen from yours, then come back.
- Send the app to the background for 10 seconds, then bring it back. Lock the screen as well.
- Start a phone call, or ask the voice assistant something, while a video plays with sound.
- Open a sheet or dialog over the embed, then close it.
- On the web, switch tabs, then click into another window and back.
Limitations
- Android views ignore the lifecycle:
GenuinEmbedViewandGenuinPlacementViewdon't observe the activity. Withoutpause(), audio continues in the background. - Android carousels can play off screen: Without a floating player, a carousel that scrolls away keeps playing until you pause it.
- iOS
pause()doesn't hold: The SDK resumes after an app switch or a scroll back into view. UsepauseByExternalPlayer()to hold. - React Native refs work on Android only: On iOS,
pause()andresume()have no effect. - Flutter controls are Android only: The iOS plugin throws
MissingPluginExceptionfor every pause and resume method. - Web commands are page-wide:
player:pauseandplayer:playact on every embed on the page.

