Seamless Multitasking: Unleashing Picture-in-Picture Mode in React Native Apps

Harsh Sharma
2 min readNov 25, 2023

--

This Blog introduces a native Picture-in-Picture (PiP) module for Android in React Native, enhancing React Native applications with seamless PiP functionalities. This integration allows Android users to enjoy a more versatile and intuitive experience while interacting with React Native apps.

To incorporate this module into your React Native project, follow the steps outlined below:

  1. Add the following configurations to your AndroidManifest.xml file within the <activity> tag for MainActivity:
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|smallestScreenSize|orientation"

2. Incorporate the following Java files into your project within the designated package (e.g., com.pipandroid):

PipModule.java

package com.pipandroid;

import android.app.PictureInPictureParams;
import android.os.Build;
import android.util.Rational;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class PipModule extends ReactContextBaseJavaModule {
private Rational aspectRatio;
PipModule(ReactApplicationContext context){
super(context);
aspectRatio = new Rational(3, 4);
}

@Override
public String getName(){
return "PipModule";
}

@ReactMethod
public void EnterPipMode(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PictureInPictureParams params = new PictureInPictureParams.Builder()
.setAspectRatio(this.aspectRatio)
.build();
getCurrentActivity().enterPictureInPictureMode(params);
}
}
}

PipPackage.java

package com.pipandroid;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class PipPackage implements ReactPackage {

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new PipModule(reactContext));
return modules;
}
}

3. In the MainApplication.java file of your project, include the module by adding the following line:

Usage

  const { PipModule } = NativeModules;
PipModule.EnterPipMode();

React Native Code Snippet

import {StyleSheet, View, NativeModules, AppState, Button} from 'react-native';
import Reactfrom 'react';
import Video from 'react-native-video';

const PipComponent = () => {
const {PipModule} = NativeModules;
const [backgroundDeteced, setBackgroundDeteced] = React.useState(false);
// detect when app is in background and enter pip mode -

React.useEffect(() => {
const appstatus = AppState.addEventListener('change', ev => {
if (ev === 'background') {
setBackgroundDeteced(true);
PipModule.EnterPipMode();
} else {
setBackgroundDeteced(false);
}
});
return () => {
appstatus.remove();
};
}, [PipModule]);

return (
<View style={styles.container}>
<Video
source={{
uri: 'https://www.example.com/video.mp4',
}}
style={styles.videoContainer}
fullscreen
repeat
playInBackground
pictureInPicture
posterResizeMode="cover"
resizeMode="cover"
poster="https://www.simplilearn.com/ice9/free_resources_article_thumb/React_Native_Tutorial.jpg"
/>

{!backgroundDeteced && (
<Button
onPress={() => {
PipModule.EnterPipMode();
}}
title="PIP"
/>
)}
</View>
);
};

export default PipComponent;

const styles = StyleSheet.create({
container: {
flex: 1,
},
videoContainer: {
width: '100%',
height: 300,
},
});

--

--