Skip to content

Commit

Permalink
feat: iOS background prevent
Browse files Browse the repository at this point in the history
  • Loading branch information
wn-na committed Jul 2, 2024
1 parent b6b211d commit 194c5de
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 16 deletions.
28 changes: 20 additions & 8 deletions example/0.73/src/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as React from 'react';
import { StyleSheet, View, Button, Text } from 'react-native';
import {StyleSheet, View, Button, Text} from 'react-native';
import {
CaptureProtection,
CaptureProtectionModuleStatus,
useCaptureProtection,
} from 'react-native-capture-protection';
import { useNavigation } from '@react-navigation/native';
import {useNavigation} from '@react-navigation/native';
export default function Main() {
const { isPrevent, status } = useCaptureProtection();
const {isPrevent, status} = useCaptureProtection();
const navigation = useNavigation<any>();

React.useEffect(() => {
Expand All @@ -16,27 +16,27 @@ export default function Main() {
React.useEffect(() => {
console.log(
'Main Prevent Status is',
status ? CaptureProtectionModuleStatus?.[status] : undefined
status ? CaptureProtectionModuleStatus?.[status] : undefined,
);
}, [status]);

return (
<View style={styles.container}>
<Text style={{ color: isPrevent?.record ? 'blue' : 'black' }}>
<Text style={{color: isPrevent?.record ? 'blue' : 'black'}}>
{'Record Prevent : ' + isPrevent?.record}
</Text>
<Text style={{ color: isPrevent?.screenshot ? 'blue' : 'black' }}>
<Text style={{color: isPrevent?.screenshot ? 'blue' : 'black'}}>
{'Screenshot Prevent : ' + isPrevent?.screenshot}
</Text>
<Text style={{ color: 'black' }}>
<Text style={{color: 'black'}}>
{'Status : ' +
(status ? CaptureProtectionModuleStatus?.[status] : undefined)}
</Text>
<Button
title="set Record Protect Screen by Text"
onPress={() => {
CaptureProtection.setScreenRecordScreenWithText?.(
'This is Text Message!'
'This is Text Message!',
);
}}
/>
Expand Down Expand Up @@ -70,6 +70,18 @@ export default function Main() {
CaptureProtection.preventScreenshot();
}}
/>
<Button
title="allow background"
onPress={() => {
CaptureProtection.allowBackground();
}}
/>
<Button
title="prevent background"
onPress={() => {
CaptureProtection.preventBackground();
}}
/>
</View>
);
}
Expand Down
13 changes: 13 additions & 0 deletions example/under0.73/src/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@ export default function Main() {
CaptureProtection.preventScreenshot();
}}
/>

<Button
title="allow background"
onPress={() => {
CaptureProtection.allowBackground();
}}
/>
<Button
title="prevent background"
onPress={() => {
CaptureProtection.preventBackground();
}}
/>
</View>
);
}
Expand Down
96 changes: 92 additions & 4 deletions ios/CaptureProtection.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ @implementation CaptureProtection {
CAPTURE_DETECTED,
UNKNOWN
};
bool isBackgroundObserver;
bool isPreventBackground;
UITextField* secureTextField;
UIViewController *protecterViewController;
UIViewController *protecterScreenViewController;
}

RCT_EXPORT_MODULE();
Expand Down Expand Up @@ -156,12 +159,75 @@ - (void)removeRecordProtectionScreen {
});
}

- (void)secureScreenshotView: (BOOL)isSecure {
- (void) addBackgroundObserver {
[[NSNotificationCenter defaultCenter] addObserverForName: UIApplicationWillResignActiveNotification
object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"UIApplicationWillResignActiveNotification");
[self secureBackgroundView:true];
});
}];
[[NSNotificationCenter defaultCenter] addObserverForName: UIApplicationDidEnterBackgroundNotification
object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"UIApplicationDidEnterBackgroundNotification");
[self secureBackgroundView:true];
});
}];

[[NSNotificationCenter defaultCenter] addObserverForName: UIApplicationDidBecomeActiveNotification
object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"UIApplicationDidBecomeActiveNotification");
[self secureBackgroundView:false];
});
}];
[[NSNotificationCenter defaultCenter] addObserverForName: UIApplicationWillEnterForegroundNotification
object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"UIApplicationWillEnterForegroundNotification");
[self secureBackgroundView:false];
});
}];
}

- (void)secureBackgroundView: (BOOL)show {
dispatch_async(dispatch_get_main_queue(), ^{
if (self->protecterScreenViewController != nil) {
[self->protecterScreenViewController willMoveToParentViewController:nil];
[self->protecterScreenViewController.view removeFromSuperview];
[self->protecterScreenViewController removeFromParentViewController];
}
if (!self->isPreventBackground) {
return;
}

if (show) {
UIViewController* viewController = [[UIViewController alloc] init];
viewController.view.window.windowLevel = UIWindowLevelAlert;
self->protecterScreenViewController = viewController;
viewController.view.backgroundColor = UIColor.whiteColor;
UIWindow *window = [UIApplication sharedApplication].keyWindow;

[window makeKeyAndVisible];

[window.layer.superlayer addSublayer:viewController.view.layer];
[self->secureTextField.layer.sublayers.firstObject addSublayer:viewController.view.window.layer];
}

});
}

- (void)secureScreenshotView: (BOOL)isSecure {
dispatch_async(dispatch_get_main_queue(), ^{
if (self->isBundleObserver != true) {
self->isBundleObserver = true;
[self bundleObserver];
}
if (self->isBackgroundObserver != true) {
self->isBackgroundObserver = true;
[self addBackgroundObserver];
}
if (self->secureTextField == nil) {
self->secureTextField = [[UITextField alloc] init];
self->secureTextField.userInteractionEnabled = false;
Expand All @@ -170,7 +236,7 @@ - (void)secureScreenshotView: (BOOL)isSecure {

[window makeKeyAndVisible];

[window.layer.superlayer addSublayer:self->secureTextField.layer];
[window.layer.superlayer addSublayer:self->secureTextField.layer];
[self->secureTextField.layer.sublayers.firstObject addSublayer:window.layer];
}
[self->secureTextField setSecureTextEntry:isSecure];
Expand All @@ -191,7 +257,11 @@ - (void) removeScreenShotObserver {
}
}

- (void) addScreenRecordObserver {
- (void) addScreenRecordObserver {
if (self->isBackgroundObserver != true) {
self->isBackgroundObserver = true;
[self addBackgroundObserver];
}
if (!hasScreenRecordObserver) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(eventScreenRecord:) name:UIScreenCapturedDidChangeNotification object:nil];
hasScreenRecordObserver = YES;
Expand Down Expand Up @@ -330,6 +400,20 @@ - (void) stopObserving {
}
};

RCT_REMAP_METHOD(allowBackground,
allowBackgroundResolver: (RCTPromiseResolveBlock)resolve
allowBackgroundRejecter: (RCTPromiseRejectBlock)reject
) {
isPreventBackground = NO;
};

RCT_REMAP_METHOD(preventBackground,
preventBackgroundResolver: (RCTPromiseResolveBlock)resolve
preventBackgroundRejecter: (RCTPromiseRejectBlock)reject
) {
isPreventBackground = YES;
};

RCT_REMAP_METHOD(allowScreenshot,
removeScreenshotListener: (BOOL)removeScreenshotListener
allowScreenshotResolver: (RCTPromiseResolveBlock)resolve
Expand All @@ -341,6 +425,7 @@ - (void) stopObserving {
if (removeScreenshotListener) {
[self removeScreenShotObserver];
}
isPreventBackground = NO;
isPreventScreenshot = NO;
if (hasListeners) {
[self sendEventWithName:@"CaptureProtectionListener" body:[self eventMessage:UNKNOWN]];
Expand All @@ -360,7 +445,8 @@ - (void) stopObserving {
@try {
[self secureScreenshotView:true];
[self addScreenShotObserver];
isPreventScreenshot = YES;
isPreventBackground = YES;
isPreventBackground = YES;
if (hasListeners) {
[self sendEventWithName:@"CaptureProtectionListener" body:[self eventMessage:UNKNOWN]];
}
Expand Down Expand Up @@ -423,4 +509,6 @@ - (void) stopObserving {
}
#endif



@end
4 changes: 2 additions & 2 deletions ios/CaptureProtection.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -208,7 +208,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-capture-protection",
"version": "1.9.8",
"version": "1.9.9",
"description": "It’s a library for React Native to control simple capture events(i.e. Screenshot or Screen record)",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down
2 changes: 1 addition & 1 deletion react-native-capture-protection.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Pod::Spec.new do |s|
s.license = package["license"]
s.authors = package["author"]

s.platforms = { :ios => "11.0" }
s.platforms = { :ios => "13.0" }
s.source = { :git => "https://github.com/0xlethe/react-native-capture-protection.git", :tag => "#{s.version}" }

s.source_files = "ios/**/*.{h,m,mm}"
Expand Down
16 changes: 16 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,20 @@ const preventScreenshot = async (): Promise<void> => {
return undefined;
};

const allowBackground = async (): Promise<void> => {
if (Platform.OS === 'ios') {
return await CaptureProtectionModule?.allowBackground?.();
}
return undefined;
};

const preventBackground = async (): Promise<void> => {
if (Platform.OS === 'ios') {
return await CaptureProtectionModule?.preventBackground?.();
}
return undefined;
};

/**
* **This function only work in `iOS`**
*
Expand Down Expand Up @@ -432,6 +446,8 @@ export const CaptureProtection = {
requestPermission,
getPreventStatus,
useCaptureProtection: useCaptureProtectionFunction,
allowBackground,
preventBackground,
};

export { CaptureProtectionModuleStatus, CaptureEventStatus } from './type';

0 comments on commit 194c5de

Please sign in to comment.