#android #ios #reactjs #react-native #screenshot
#Android #iOS #reactjs #react-native #скриншот
Вопрос:
Я наткнулся на несколько решений, специфичных для ios и Android, для предотвращения захвата экрана и создания скриншотов. Но как мне отключить захват экрана в react native?
Ответ №1:
Android
Внутри /android/app/src/main/java/com/{Project_Name}/MainActivity.java
вы можете добавить следующие строки. Запретить захват экрана с помощью SetFlag FLAG_SECURE
, используйте приведенный ниже код в качестве примера:
import android.os.Bundle;
import android.view.WindowManager;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
позже, когда вы захотите снять флаг безопасности
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
iOS
наложение экрана в AppDelegate.m
, возьмите этот пример:
- (void)applicationWillResignActive:(UIApplication *)application {
// fill screen with our own colour
UIView *colourView = [[UIView alloc]initWithFrame:self.window.frame];
colourView.backgroundColor = [UIColor whiteColor];
colourView.tag = 1234;
colourView.alpha = 0;
[self.window addSubview:colourView];
[self.window bringSubviewToFront:colourView];
// fade in the view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 1;
}];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// grab a reference to our coloured view
UIView *colourView = [self.window viewWithTag:1234];
// fade away colour view from main view
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 0;
} completion:^(BOOL finished) {
// remove when finished fading
[colourView removeFromSuperview];
}];
}
Комментарии:
1. Можете ли вы объяснить, что делает решение для iOS? В моем приложении это просто приведет к тому, что приложение превратится в белый экран, что сделает приложение «недоступным для просмотра» в фоновом режиме, но вы все равно сможете делать скриншоты в приложении
2. Как с этим справиться, например, если скриншот «Перейти к защищенному сообщению» недоступен, в противном случае он должен быть доступен.
3. Это решение работает только тогда, когда приложение работает в фоновом режиме. Для меня applicationWillResignActive не вызывается, когда пользователь делает скриншоты
4.
import android.os.Bundle;
добавьте эту строку сверху в Android
Ответ №2:
Таким образом, для сборки iOS на платформе React Native остается мало работы. Поэтому наберитесь терпения и ознакомьтесь со следующим подходом.
Я использую пакет react-native-video для воспроизведения мультимедиа. Моим требованием было показать счетчик, если у пользователя включена запись экрана.
-
Из https://developer.apple.com/documentation/uikit/uiscreen/2921651-captured ?language=objc я понял, что
captured
для этого свойства установлено значение YES. Я добавил observer в AppDelegate.m вdidFinishLaunchingWithOptions
методе.[[UIScreen mainScreen] addObserver:self forKeyPath:@"captured" options:NSKeyValueObservingOptionNew context:nil];
-
Поскольку RN позволяет взаимодействовать с собственными модулями, я решил добавить bridge, чтобы уведомлять, когда
capture
флаг установлен в YES.
Я создал два файла ScreenRecordingNotification.h и .m
.h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#ifndef ScreenCaptureNotification_h
#define ScreenCaptureNotification_h
@interface ScreenCaptureNotification : RCTEventEmitter <RCTBridgeModule>
-(void) isScreenCaptureEnabled:(BOOL)isCaptured;
@end
#endif /* ScreenCaptureNotification_h */
и .m выглядит так
#import <Foundation/Foundation.h>
#import "ScreenCaptureNotification.h"
#import <React/RCTLog.h>
@implementation ScreenCaptureNotification
(id)allocWithZone:(NSZone *)zone {
static ScreenCaptureNotification *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(amp;onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents {
return @[
@"isScreenCaptureEnabled"];
}
-(void) isScreenCaptureEnabled:(BOOL)isCaptured {
[self sendEventWithName:@"isScreenCaptureEnabled" body:@{@"value": @(isCaptured)}];
}
@end
-
импортировал
#import "ScreenCaptureNotification.h"
в AppDelegate и добавил следующий метод.- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"captured"]){ NSLog(@"Screen Capture is Enabled"); RCTLog(@"Screen Capture is Enabled"); if (@available(iOS 11.0, *)) { ScreenCaptureNotification *manager = [ScreenCaptureNotification allocWithZone: nil]; [manager isScreenCaptureEnabled:UIScreen.mainScreen.isCaptured]; } } }
А также добавить [[UIScreen mainScreen] addObserver:self forKeyPath:@"captured" options:NSKeyValueObservingOptionNew context:nil];
в didFinishLaunchingWithOptions
.
На этом изменения на стороне iOS завершаются.
- Теперь вам нужно добавить прослушиватель в файлы .js для уведомлений, которые отправляет iOS. Как только вы получите уведомление, вам решать, что с ним делать. Примерно это будет выглядеть следующим образом.
addListener() {
let bridge = new NativeEventEmitter(NativeModules.ScreenCaptureNotification);
this.screenCaptureEnabled = bridge.addListener("isScreenCaptureEnabled",res => {
this.setState({ screenCapture: true })
})
}
и
render() {
if (this.state.screenCapture) {
//Show spinner
return <Spinner />
}
return (
<Vido uri ... />
)
}
Я открыт для предложений по внесению изменений в этот пост. Не забудьте проголосовать, если этот пост помог вам.
Комментарии:
1. Будет ли свойство capture иметь значение true, если пользователь попытается сделать снимок экрана?
2. @DhruvilShah ты должен попробовать. Я попробовал запись экрана, и она работает так, как ожидалось.
3. @Naren Я попробовал ваше решение, но оно не работает, не могли бы вы, пожалуйста, поделиться кодом на стороне react-native в функциональном компоненте
4. @vijaykahar понимает это. React native и iOS могут взаимодействовать с помощью bridge. Когда вы получаете флаг от iOS для React Native, вы устанавливаете флаг в redux, который запрещает приложению выполнять повторный запуск. В файле класса react вы добавляете mapStateToProps, чтобы получить обновленное значение из redux. Я не могу поделиться кодом, но если вы поделитесь своим, я смогу это проверить.
5. Отображаются последние проблемы с неопределенным символом: _OBJC_CLASS_ $ _ScreenCaptureNotification Получение этой ошибки в Xcode 12.2
Ответ №3:
Запретить захват экрана
Android
Запретить захват экрана, установив флаг secure
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
Если вы хотите удалить флаг secure
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
Комментарии:
1. Спасибо за ответ. Как насчет IOS?
2. Вы могли бы хотя бы упомянуть, куда мы должны поместить эту строку кода.
3. этот ответ недостаточно ясен, вы не указываете, куда именно мы должны вставить эту строку кода!
4. @BurimSyla Посмотрите на мой ответ, чтобы узнать точное местоположение, куда следует поместить эту строку кода.
Ответ №4:
В Android
/android/app/src/main/java/com/{имя_проекта}/MainActivity.java
напишите несколько инструкций импорта
import android.os.Bundle;
import android.view.WindowManager;
Запретить захват экрана, установив флаг безопасное использование приведенного ниже кода внутри класса MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
Ответ №5:
- Добавьте эти строки в AppDelegate.m ниже didFinishLaunchingWithOptions, когда пользователь с записью экрана выходит из приложения, и если запись экрана в приложении не открыта только для ios react-native
Ответ №6:
снимок экрана false в вашем приложении поместите этот полный код в свой
android / app / src/ main / javacom/ mainactivity / java
package com.Yourprojectname;
import com.facebook.react.ReactActivity;
import android.os.Bundle;
import android.view.WindowManager;
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "YOUR PROJECT NAME";
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);}}