Отключить захват экрана / скриншот в приложении React Native

#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 для воспроизведения мультимедиа. Моим требованием было показать счетчик, если у пользователя включена запись экрана.

  1. Из 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];

  2. Поскольку 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
  
  1. импортировал #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 завершаются.

  1. Теперь вам нужно добавить прослушиватель в файлы .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:

  1. Добавьте эти строки в 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
  );}}