Как предотвратить захват экрана в Android

Можно ли предотвратить запись экрана в приложении Android?

Я хотел бы разработать безопасное приложение для Android. В этом мне нужно обнаружить программное обеспечение записи экрана, которые работают в фоновом режиме и убить их. Я использовал SECURE FLAG для предотвращения скриншотов. Но я не знаю, возможно ли предотвратить захват видео с экрана Android. Дайте мне знать, как предотвратить захват экрана (видео / скриншоты).

17 ответов

Решение

Я хочу сказать, что невозможно полностью предотвратить захват экрана / видео любого приложения для Android с помощью поддерживаемых средств. Но если вы хотите заблокировать его только для обычных устройств Android, SECURE FLAG является существенным.

1) Флаг безопасности блокирует как обычный снимок экрана, так и захват видео.

Также в документации по этой ссылке сказано, что

Флаг окна: относиться к содержимому окна как к безопасному, не допуская его появления на скриншотах или просмотра на незащищенных экранах.

Приведенное выше решение наверняка предотвратит захват видео приложениями.

Смотрите ответ здесь.

2) Существуют альтернативные способы захвата содержимого экрана.

Может быть возможно сделать снимок экрана другого приложения на рутированном устройстве или с помощью SDK,

которые оба дают мало шансов, что вы либо заблокируете его, либо получите уведомление об этом.

Например: существует программное обеспечение для зеркалирования экрана вашего телефона на компьютер через SDK, поэтому программное обеспечение для захвата экрана может использоваться там, которое не будет обнаружено вашим приложением.

Смотрите ответ здесь.

Просто добавьте эту строку:

getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);

Перед вашим setContentView() метод.

Я видел все ответы, которые подходят только для одного действия, но есть мое решение, которое блокирует снимок экрана для всех действий без добавления кода к действию. Прежде всего создайте класс Custom Application и добавьтеregisterActivityLifecycleCallbacks.Затем зарегистрируйте его в своем манифесте.

MyApplicationContext.class

public class MyApplicationContext extends Application {
    private  Context context;
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
        setupActivityListener();
    }

    private void setupActivityListener() {
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);            }
            @Override
            public void onActivityStarted(Activity activity) {
            }
            @Override
            public void onActivityResumed(Activity activity) {

            }
            @Override
            public void onActivityPaused(Activity activity) {

            }
            @Override
            public void onActivityStopped(Activity activity) {
            }
            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }
            @Override
            public void onActivityDestroyed(Activity activity) {
            }
        });
    }



}

Манифест

 <application
        android:name=".MyApplicationContext"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

Чтобы отключить захват экрана:

Добавьте следующую строку кода в onCreate() метод:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
                           WindowManager.LayoutParams.FLAG_SECURE);

Чтобы включить захват экрана:

Найти для LayoutParams.FLAG_SECURE и удалите строку кода.

Для пользователей Java

getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);

Для пользователей kotlin

window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)

Вы можете сделать свое приложение владельцем устройства / профиля и позвонить setScreenCaptureDisabled(), Из документации этот API-интерфейс выполняет следующие действия:

public void setScreenCaptureDisabled (Администратор ComponentName, логическое значение отключено) Добавлено на уровне API 21

Вызывается владельцем устройства / профиля, чтобы установить, отключен ли захват экрана. Отключение захвата экрана также предотвращает отображение контента на устройствах отображения, которые не имеют защищенного видеовыхода. Смотрите FLAG_SECURE для более подробной информации о безопасных поверхностях и защищенных дисплеях.

Администратор вызывающего устройства должен быть владельцем устройства или профиля. Если это не так, будет выдано исключение безопасности. Параметры admin С каким DeviceAdminReceiver связан этот запрос. деактивирован Захват экрана отключен или нет.

В качестве альтернативы вы можете стать партнерским приложением MDM(Управление мобильными устройствами).OEMs предоставляет дополнительные API-интерфейсы своим партнерским приложениям MDM для управления устройством. Например, samsung предоставляет API для управления записью экрана на устройстве своим партнерам по MDM.

В настоящее время это единственный способ обеспечить ограничение экрана.

Попробуй это:

getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);

Кажется, вы знаете, как отключить скриншоты из своего приложения, и есть другие ответы, которые помогут вам в этом. Но я постараюсь дать вам важную информацию, которую никто не дает вам.

1) У вас не может быть приложения, которое на 100% защищено от снятия скриншотов (фото / видео). Официального способа делать скриншоты в Android нет. Если приложение записывает экраны, оно должно использовать некоторые неподдерживаемые методы (либо рутирование, либо использование SDK).

У вас очень мало возможностей для блокировки приложения, если оно использует root-доступ к экранам записи.

2) Никто не упомянул эту проблему здесь, но будьте очень осторожны при использовании WindowManager.LayoutParams.FLAG_SECURE, На многих устройствах (например, на Samsung Galaxy ACE, например, GT-S5830) было проверено, что это делает весь вид зашифрованным. Как это,

введите описание изображения здесь

Пожалуйста, поставьте чек, как это,

if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}

Он отлично работает на устройствах ICS, так что никаких проблем нет.

3) Я также обнаружил, что даже на более новых устройствах, таких как Android 4.3, это вызывает проблемы с анимацией при повороте экрана. Пожалуйста, проверьте этот отчет об ошибке.

Я использовал это решение, чтобы сделать снимок вручную в приложении и запретить захват сцен, когда приложение работает в фоновом режиме, надеюсь, это поможет.

@Override
protected void onResume() {
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
    super.onResume();
}

@Override
protected void onPause() {
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
    super.onPause();
}

Согласно этому официальному руководству, вы можете добавить WindowManager.LayoutParams.FLAG_SECURE на ваш макет окна, и это будет запрещать скриншоты.

Добавьте эту строку в событие OnCreate на MainActivity (Xamarin)

Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);

Пользователи Kotlin могут добавить следующий код в класс приложения, чтобы предотвратить создание снимков экрана приложения.

      class MediSageApplication : Application() {

override fun onCreate() {
  
    super.onCreate()
   
    registerActivityLifecycle()
   
}

private fun registerActivityLifecycle() {
    registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
        override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
            activity.window.setFlags(
                WindowManager.LayoutParams.FLAG_SECURE,
                WindowManager.LayoutParams.FLAG_SECURE
            )
        }

        override fun onActivityStarted(activity: Activity) {}
        override fun onActivityResumed(activity: Activity) {}
        override fun onActivityPaused(activity: Activity) {}
        override fun onActivityStopped(activity: Activity) {}
        override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
        override fun onActivityDestroyed(activity: Activity) {}
    })
}

}

По поводу блокировки возможности сделать скриншот в приложении:

      Window window = requireActivity().getWindow();
window.addFlag(WindowManager.LayoutParams.FLAG_SECURE);

не забудьте убрать этот флаг (например, в onDestroy) - чтобы включить скриншоты в других безопасных местах приложения:

      window.clearFlags(WWindowManager.LayoutParams.FLAG_SECURE);
      public class InShotApp extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycle();
        }
    
        private void registerActivityLifecycle() {
    
            registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
                    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);            }
    
                @Override
                public void onActivityStarted(@NonNull Activity activity) {
    
                }
    
                @Override
                public void onActivityResumed(@NonNull Activity activity) {
    
                }
    
                @Override
                public void onActivityPaused(@NonNull Activity activity) {
    
                }
    
                @Override
                public void onActivityStopped(@NonNull Activity activity) {
    
                }
    
                @Override
                public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
    
                }
    
                @Override
                public void onActivityDestroyed(@NonNull Activity activity) {
    
                }
            });
    
        }
    }

О скриншоте фото, FLAG_SECURE не работает рутированное устройство.

но если вы контролируете файл скриншота, вы можете предотвратить получение исходного файла.

попробуй это.

1. мониторинг скриншота (файловый монитор) с помощью удаленного сервиса Android
2. удалить оригинальное изображение скриншота.
3. доставить экземпляр растрового изображения, чтобы вы могли изменить.

Легко и элегантно:

      import android.view.WindowManager.LayoutParams;

// ...

@Override
public void onWindowFocusChanged(boolean isFocused) {
  if (isFocused) {
    getWindow().clearFlags(LayoutParams.FLAG_SECURE);
  } else {
    getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
  }
  super.onWindowFocusChanged(isFocused);
}

Для тех, кому нужно отключить скриншоты и использовать Jetpack Compose, это то, что вам нужно:

      fun Activity.disableScreenshots() {
  window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
}

fun Activity.enableScreenshots() {
  window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}

@Composable
fun DisableScreenshots() {
  val context = LocalContext.current
  DisposableEffect(Unit) {
    context.getActivity()?.disableScreenshots()
    onDispose {
      context.getActivity()?.enableScreenshots()
    }
  }
}

Затем просто вызовите DisableScreenshots из вашей составной функции;)

Другие вопросы по тегам