react-native-screenguard
Version:
A Native screenshot blocking library for React-Native developer, with background customizable after captured. Screenshot detector are also supported.
341 lines (310 loc) • 10.8 kB
text/typescript
import { NativeModules, Platform, TurboModuleRegistry } from 'react-native';
import * as ScreenGuardData from './data';
import { useSGScreenShot } from './useSGScreenShot';
import { useSGScreenRecord } from './useSGScreenRecord';
import * as ScreenGuardConstants from './constant';
import * as ScreenGuardHelper from './helper';
import { type Spec } from './NativeScreenGuard';
const NativeScreenGuard = TurboModuleRegistry.get<Spec>('ScreenGuard') || NativeModules.ScreenGuard;
let _isInitialized = false;
let _isTrackingLogEnabled = false;
let _displayScreenguardOverlayAndroid = true;
/**
* Log error and reject promise
* @param message error message
* @private
*/
const _logError = (message: any) => {
console.error(message);
return Promise.reject(message);
};
export default {
/**
* initialize the screen guard with settings
* @param data ScreenGuardSettingsData
* @version v2.0.0+
*/
async initSettings(data?: ScreenGuardData.ScreenGuardSettingsData | null): Promise<void | string> {
let currentSettings = ScreenGuardConstants.ScreenGuardDefaultSettings;
if (data !== null) {
currentSettings = {
enableCapture: data?.enableCapture ?? false,
enableRecord: data?.enableRecord ?? false,
enableContentMultitask: data?.enableContentMultitask ?? false,
displayScreenGuardOverlay: data?.displayScreenGuardOverlay ?? false,
displayScreenguardOverlayAndroid: data?.displayScreenguardOverlayAndroid ?? true,
timeAfterResume: data?.timeAfterResume ?? ScreenGuardConstants.TIME_DELAYED,
getScreenshotPath: data?.getScreenshotPath ?? false,
limitCaptureEvtCount: data?.limitCaptureEvtCount ?? undefined,
trackingLog: data?.trackingLog ?? false,
}
}
if (
currentSettings.timeAfterResume !== undefined &&
!currentSettings.displayScreenGuardOverlay &&
!currentSettings.displayScreenguardOverlayAndroid
) {
console.warn(
'ScreenGuard: setting timeAfterResume while displayScreenGuardOverlay/displayScreenguardOverlayAndroid = false'
);
}
_isTrackingLogEnabled = currentSettings.trackingLog ?? false;
try {
if (NativeScreenGuard == null) {
return _logError('ScreenGuard is not initialized, please double check!');
}
await NativeScreenGuard?.initSettings(currentSettings);
_isInitialized = true;
_displayScreenguardOverlayAndroid = currentSettings.displayScreenguardOverlayAndroid ?? true;
return;
} catch (error) {
_isInitialized = false;
return _logError(error);
}
},
/**
* activate screenshot blocking with a color effect (iOS 13+, Android 8+)
* @param data ScreenGuardColorData object
* throws error if ScreenGuard is not initialized
* @version v0.0.2+
*/
async register(data: ScreenGuardData.ScreenGuardColorData): Promise<void | string> {
if (!_isInitialized) {
return _logError(
'ScreenGuard is not initialized. Please call initSettings() first!'
);
}
if (Platform.OS === 'android' && !_displayScreenguardOverlayAndroid) {
console.warn(
'ScreenGuard: register() with overlay is not available when displayScreenguardOverlayAndroid = false. Switching to registerWithoutEffect().'
);
return this.registerWithoutEffect();
}
let {
backgroundColor = ScreenGuardConstants.BLACK_COLOR,
} = data;
let currentColor = ScreenGuardHelper.resolveColorString(backgroundColor);
try {
await NativeScreenGuard?.activateShield({
backgroundColor: currentColor,
});
return;
} catch (error) {
return _logError(error);
}
},
/**
* (Android only) activate screenshot and screen record blocking without
* any effect (blur, image, color) on Android (Android 5+)
* throws error if ScreenGuard is not initialized
* warning if called on iOS platform
* @deprecated Use register function with displayScreenguardOverlayAndroid = false instead
* @version v1.0.0+
*/
async registerWithoutEffect(): Promise<void | string> {
if (!_isInitialized) {
return _logError(
'ScreenGuard is not initialized. Please call initSettings() first!'
);
}
if (Platform.OS === 'android') {
await NativeScreenGuard?.activateShieldWithoutEffect();
} else {
console.warn(
'registerWithoutEffect is only available on Android platform!'
);
}
return;
},
/**
* Activate screenshot blocking with a blur effect after captured (iOS 13+, Android 8+)
* throws error if ScreenGuard is not initialized
* @param data ScreenGuardBlurDataObject data object
* @version v0.1.2+
*/
async registerWithBlurView(data: ScreenGuardData.ScreenGuardBlurDataObject): Promise<void | string> {
if (!_isInitialized) {
return _logError(
'ScreenGuard is not initialized. Please call initSettings() first!'
);
}
if (Platform.OS === 'android' && !_displayScreenguardOverlayAndroid) {
console.warn(
'ScreenGuard: registerWithBlurView() is not available when displayScreenguardOverlayAndroid = false. Switching to registerWithoutEffect().'
);
return this.registerWithoutEffect();
}
const {
radius = ScreenGuardConstants.RADIUS_DEFAULT,
} = data;
if (typeof radius !== 'number') {
return _logError('radius must be a number and bigger than 1');
}
if (radius < 1) {
return _logError('radius must bigger than 1!');
}
if (radius >= 1 && radius < 15) {
console.warn(
'Consider a radius value bigger than 15, as content still very clear and easy to read!'
);
}
if (radius > 50) {
console.warn(
'Consider a radius value in between 15 and 50, as blur contents may vanish inside the view!'
);
}
try {
await NativeScreenGuard?.activateShieldWithBlurView({
radius,
});
return;
} catch (error) {
return _logError(error);
}
},
/**
* Activate with an Image uri (iOS 13+, Android 8+)
* throws error if ScreenGuard is not initialized
* throws error if alignment is not in range from 0 -> 8
* @param data ScreenGuardImageDataObject data object,
* @version v1.0.2+
*/
async registerWithImage(data: ScreenGuardData.ScreenGuardImageDataObject): Promise<void | string> {
if (!_isInitialized) {
return _logError('ScreenGuard is not initialized. Please call initSettings() first!');
}
if (Platform.OS === 'android' && !_displayScreenguardOverlayAndroid) {
console.warn(
'ScreenGuard: registerWithImage() is not available when displayScreenguardOverlayAndroid = false. Switching to registerWithoutEffect().'
);
return this.registerWithoutEffect();
}
let {
source,
width,
height,
top,
left,
bottom,
right,
backgroundColor = ScreenGuardConstants.BLACK_COLOR,
alignment,
defaultSource,
} = data;
let newDefaultSource: { uri: string } | null = null;
if (typeof source === 'object' && 'uri' in source) {
if (source.uri.length === 0) {
return _logError('uri must not be empty!');
}
if (width < 1 || isNaN(width)) {
return _logError('width of image must bigger than 0!');
}
if (height < 1 || isNaN(height)) {
return _logError('height of image must bigger than 0!');
}
if (!ScreenGuardConstants.IMAGE_REGEX.test(source.uri)) {
console.warn(
'Looks like the uri is not an image uri. Try to provide a correct image uri for better result!'
);
}
} else if (typeof source === 'number') {
source = { uri: ScreenGuardHelper.resolveAssetSource(data.source) };
}
if (defaultSource == null) {
console.warn(
'Consider adding a default source to display image that cannot be loaded from uri!'
);
newDefaultSource = {
uri: ScreenGuardHelper.resolveAssetSource(
require('./images/screenshot_blocking.jpg')
),
};
} else {
newDefaultSource = {
uri: ScreenGuardHelper.resolveAssetSource(defaultSource),
};
}
if (
alignment != null &&
(alignment > 8 || alignment < 0 || isNaN(alignment))
) {
return _logError(
'alignment must be in range from 0 -> 8 only, values: \n topLeft: 0; \n topCenter: 1; \n topRight: 2; \n centerLeft: 3; \n Center: 4; \n centerRight: 5; \n bottomLeft: 6; \n bottomCenter: 7;\n bottomRight: 8; \n If you want to center the image, leave null instead!'
);
}
if (
alignment == null &&
((top == null && left == null && bottom == null && right == null) ||
Platform.OS === 'android')
) {
alignment = ScreenGuardConstants.Alignment.center;
}
let currentColor = ScreenGuardHelper.resolveColorString(backgroundColor);
try {
await NativeScreenGuard?.activateShieldWithImage({
source,
defaultSource: newDefaultSource,
width,
height,
top,
left,
bottom,
right,
alignment,
backgroundColor: currentColor,
});
return;
} catch (error) {
return _logError(error);
}
},
/**
* Deactivate screenguard
* Clear all screen protector and event listening
* throws error if ScreenGuard is not initialized
* @version v0.0.2+
*/
async unregister(): Promise<void | string> {
try {
if (!_isInitialized) {
return _logError(
'ScreenGuard is not initialized. Please call initSettings() first!'
);
}
await NativeScreenGuard?.deactivateShield();
return;
} catch (error) {
return _logError(error);
}
},
/**
* Get the current logs of screenguard
* throws error if ScreenGuard is not initialized
* @param maxCount maximum number of logs to retrieve
* @version v2.0.0+
*/
async getScreenGuardLogs(maxCount = 10): Promise<Array<ScreenGuardData.ScreenGuardLogEntry> | null> {
try {
if (!_isInitialized) {
return _logError(
'ScreenGuard is not initialized. Please call initSettings() first!'
);
}
if (maxCount < 1) {
return _logError('maxCount must be >= 1!');
}
if (maxCount > 1000000) {
return _logError('maxCount must be <= 1000000!');
}
if (!_isTrackingLogEnabled) {
console.warn(
'ScreenGuard: you may not get logs properly while trackingLog = false'
);
}
return await NativeScreenGuard?.getScreenGuardLogs(maxCount);
} catch (error) {
return _logError(error);
}
},
};
export { ScreenGuardConstants, useSGScreenShot, useSGScreenRecord };