I'm working on a react native application where there are two different scenarios that I want to cover in terms of disabling pip, preventing screenshots and prevent screen recording.
Content that is going to be read by the users is rendered using React native webview. Every url(web page) for content contains vimeo videos and youtube videos, I've inspected the html page and found that inside web page some external cdn library is used to play the vimeo videos and youtube videos.
Now I'm facing two different problems:
- I've used Expo screen capture to prevent user from taking screenshots and doing screen recording, this works fine when video is played inline, when user play the video in fullscreen, user is able to take screenshots and do the screen recording
- In case of ios user is able to do pip for videos that are being played, this pip mode is working in two ways: 1) in app pip and 2) pip after application is minimised. So when videos are in pip mode user can do screen recording and take screenshots
I've used injectedJavascript prop for hiding the pip button player, but it is not working also expo screen capture doesn't work on full screen videos and pip videos.
I'm looking for the solution where screen capture will be prevented in full screen video and pip video because disabling pip doesn't solve my problem.
Any help will be appreciated!
Code for web view:
import {
StyleSheet,
View,
Alert,
Platform,
BackHandler,
Linking,
AppState,
} from 'react-native';
import React, {useRef, useState, Fragment, useEffect} from 'react';
import WebView from 'react-native-webview';
import CloseBtn from '../../components/CloseBtn';
import Color from '../../theme/Color';
import QsLoader from '../../components/QsLoader';
import {SafeAreaView} from 'react-native-safe-area-context';
import {Config} from '../../config';
import {useDispatch, useSelector} from 'react-redux';
import {ShowLogs} from '../../utils/helper';
import i18next, {changeLanguage} from 'i18next';
import {lastLocationSubmodule} from '../../store/features/contentSlice';
import AsyncStorage from '@react-native-async-storage/async-storage';
import RNScreenshotPrevent from 'react-native-screenshot-prevent';
import Orientation from 'react-native-orientation-locker';
import KeepAwake from 'react-native-keep-awake';
import * as ScreenCapture from 'expo-screen-capture';
import User from '../../models/user';
import DeviceInfo from 'react-native-device-info';
import { appErrorApi } from '../../store/features/appErrorSlice';
/**
* Component to show submodules
*/
const ContentWebView = ({navigation, route}) => {
const {
linkUrl,
title,
loginForm,
saveStatus,
inAppReview,
selectedModuleIndex,
singleChapterObj,
finalModuleId,
} = route?.params;
const webviewRef = useRef();
const homeState = useSelector(state => state.home.response);
const appConfigState = useSelector(state => state.appConfig);
const [first, setfirst] = useState(true);
const [appState, setAppState] = useState(AppState.currentState);
if (Platform.OS === 'ios') RNScreenshotPrevent.enabled(true); //prevent screenshot
const screenCapturePrevent = async () => {
Platform.OS === 'ios' ? RNScreenshotPrevent.enableSecureView() : null;
await ScreenCapture.preventScreenCaptureAsync();
};
const screenCaptureAllow = async () => {
await ScreenCapture.allowScreenCaptureAsync();
Platform.OS === 'ios' ? RNScreenshotPrevent.disableSecureView() : null; //disable ss for other screen
Platform.OS === 'ios' ? RNScreenshotPrevent.enabled(false) : null;
};
const dispatch = useDispatch();
const {t} = i18next;
const noInternetAlert = async (err) => {
if (
err &&
err?.nativeEvent &&
err?.nativeEvent?.description
) {
await appErrorApiCall(
`submodule: ${err?.nativeEvent?.description}`,
);
}
Alert.alert(
t('offlineText'),
t('checkConnectivity'),
[
{
text: 'OK',
onPress: () => {
loginForm ? null : navigation.pop();
},
},
],
{cancelable: false},
);
if (Platform.OS !== 'ios') {
webviewRef.current?.stopLoading();
// To display a blank white page, set the source of the WebView to 'about:blank'
webviewRef.current?.injectJavaScript(
'document.open(); document.close();',
);
}
};
/**
Handling android backpress
*/
useEffect(() => {
screenCapturePrevent(); //preventing screen capture
KeepAwake.activate();
const onBackPress = async () => {
navigation.navigate('Home'); // Navigate to Home when back button is pressed
return true; // Return true to indicate that we have handled the back press
};
BackHandler.addEventListener('hardwareBackPress', onBackPress);
return () => {
BackHandler.removeEventListener('hardwareBackPress', onBackPress);
screenCaptureAllow();
KeepAwake.deactivate();
Orientation.lockToPortrait();
};
}, []);
/**
* saving last location of submodule
*/
const checkWhichModuleId = async moduleID => {
if (singleChapterObj?.iSubModuleId) {
dispatch(
lastLocationSubmodule({
chapter: singleChapterObj.iChapterId,
iSubModuleId: moduleID,
iFirstSubModule: null,
}),
);
} else if (singleChapterObj?.iFirstSubModule) {
dispatch(
lastLocationSubmodule({
chapter: singleChapterObj.iChapterId,
iSubModuleId: null,
iFirstSubModule: moduleID,
}),
);
}
};
/**
* Getting module id from url
*/
const getModuleId = data => {
let values = data?.url.split('/');
if (values[values.length - 1]?.length > 2) {
checkWhichModuleId(Number(values[values.length - 1]?.split('?')[0]));
} else {
checkWhichModuleId(Number(values[values.length - 1]));
}
};
const injectedJavaScript = `
// disable pip mode for videos
let videos = document.getElementsByTagName('video');
for(let video of videos) {
video.setAttribute('disablePictureInPicture', 'true');
}
let youtubeVideos = document.getElementsByTagName('iframe')
for(let ytvideo of youtubeVideos){
ytvideo.setAttribute('allow','accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; web-share')
ytvideo.setAttribute('disablePictureInPicture', 'true');
}
return true;
`;
//pausing the all available videos
const pauseVideosInWebView = () => {
if (webviewRef.current) {
const pauseVideoScript = `
let videos = document.getElementsByTagName('video');
for(let video of videos) {
video.pause();
}
`;
webviewRef.current.injectJavaScript(pauseVideoScript);
}
};
useEffect(() => {
// event listener for app state changes
const handleAppStateChange = nextAppState => {
if (appState === 'active' && nextAppState === 'background') {
// App is going to the background
pauseVideosInWebView();
}
setAppState(nextAppState);
};
let appStateListner = AppState.addEventListener(
'change',
handleAppStateChange,
);
return () => {
appStateListner.remove();
};
}, [appState]);
//record error in data base in case of web page fails to load
const appErrorApiCall = async message => {
let userData = await User.retrieve();
let user_id = userData?.userId || 0;
let data = {
vErrorMessage: message,
user_id: user_id,
vDeviceType: Platform.OS,
vDeviceModel: DeviceInfo.getModel(),
vDeviceOS: DeviceInfo.getSystemVersion(),
};
dispatch(appErrorApi(data))
.then(res => {
ShowLogs('aapApi response', res);
})
.catch(err => ShowLogs('aapApi error', err));
};
const url = `${Config.ProgramBaseUrl}/submodules/success`;
return (
<SafeAreaView style=>
<View style=>
<CloseBtn navigation={navigation} screen={title} />
</View>
<WebView
style=
source=
ref={webviewRef}
startInLoadingState={true}
mediaPlaybackRequiresUserAction={false}
allowsInlineMediaPlayback={true}
decelerationRate={1}
onError={noInternetAlert}
allowsFullscreenVideo={true}
onNavigationStateChange={async data => {
if (!data.url.match(url)) {
getModuleId(data);
}
if (data.url.match(url)) {
if (
selectedModuleIndex == 1 &&
homeState.result.vDay == 1 &&
appConfigState?.response?.bSubscribed == 0
) {
} else {
navigation.popToTop();
}
first
? (saveStatus(
true,
false,
singleChapterObj,
finalModuleId,
selectedModuleIndex,
),
inAppReview(singleChapterObj),
setfirst(false))
: null;
}
}}
renderError={(errorDomain, errorCode, errorDesc) =>
ShowLogs('renderError')
}
useWebView2={true}
javaScriptEnabled={true}
automaticallyAdjustContentInsets={false}
cacheEnabled={false}
cacheMode="LOAD_NO_CACHE"
injectedJavaScript={injectedJavaScript}
renderLoading={() => <QsLoader />}
/>
</SafeAreaView>
);
};
export default ContentWebView;
from How to disable pip and prevent screenshots in react native?
No comments:
Post a Comment