Seamless Multitasking: Unleashing Picture-in-Picture Mode in React Native Apps
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:
- 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,
},
});