微信小程序禁止录屏方案(Taro)

719 阅读2分钟

前言

经过查询资料得出:微信小程序对于屏幕相关的API不同的操作系统支持程度是不一样的。因此 Android 和 iOS 需采用不同的方案来实现禁止录屏的方案

Android

  /**
   * 安卓系统禁止录屏处理函数
   * @param toggle 是否禁止录屏
   */
  function disableAndroidSys(toggle: boolean) {
    if (Taro.setVisualEffectOnCapture) {
      const visualEffect = toggle ? 'hidden' : 'none';
      Taro.setVisualEffectOnCapture({ visualEffect });
    }
  }

iOS

  /**
   * 苹果系统禁止录屏处理函数
   * @param toggle 是否禁止录屏
   */
  function disableIOSSys(toggle: boolean) {
    if (toggle) {
      // 从其他页面开始录屏切换到播放页
      handleIOSDSRFromOtherPage();
      // 在播放页面开始录屏
      handleIOSDSRFromCurrentPage();
    } else {
      // 取消相关的监听事件
      Taro.offScreenRecordingStateChanged(changeHandler);
    }
  }

  /**
   * 当前页面防止ios录频
   */
  function handleIOSDSRFromCurrentPage() {
    if (Taro.onScreenRecordingStateChanged) {
      Taro.onScreenRecordingStateChanged(changeHandler);
    }
  }

  /**
   * 跨屏幕防止ios录频
   */
  function handleIOSDSRFromOtherPage() {
    if (Taro.getScreenRecordingState) {
      Taro.getScreenRecordingState({
        success: res => {
          // res.state: on(正在录屏) | off(没有开始录屏)
          // 此处只需处理正在录屏的情况
          // @ts-ignore
          if (res.state === 'on') {
            setIosWatermarkingState(true);
          }
        }
      });
    }
  }

  /**
   * 屏幕录制状态变化监听函数
   */
  function changeHandler(res: any) {
    // res.state: start(开始录屏) | stop(结束录屏)
    // @ts-ignore
    if (res.state === 'start') {
      // 展示水印弹窗
      setIosWatermarkingState(true);
    } else {
      // 隐藏水印弹窗
      setIosWatermarkingState(false);
    }
  }

完整代码

将禁止屏幕录制功能封装成了一个hook,这样可以实现比较高效地逻辑复用。

// useDisableScreenRecording.tsx
import Taro from '@tarojs/taro';
import { useState } from 'react';

import { Watermarking } from '@/modules/watermarking';

export const useDisableScreenRecording = () => {
  const [iosWatermarkingState, setIosWatermarkingState] = useState(false);
  /**
   * 禁止录屏处理函数
   * @param toggle 是否禁止录屏
   */
  function disableScreenRecording(toggle: boolean) {
    if (isIOSSystem()) {
      disableIOSSys(toggle);
    } else {
      disableAndroidSys(toggle);
    }
  }

  /**
   * 判断系统是否为Ios
   */
  function isIOSSystem(): boolean {
    return /ios/i.test(Taro.getSystemInfoSync().system);
  }

  /**
   * 安卓系统禁止录屏处理函数
   * @param toggle 是否禁止录屏
   */
  function disableAndroidSys(toggle: boolean) {
    if (Taro.setVisualEffectOnCapture) {
      const visualEffect = toggle ? 'hidden' : 'none';
      Taro.setVisualEffectOnCapture({ visualEffect });
    }
  }

  /**
   * 苹果系统禁止录屏处理函数
   * @param toggle 是否禁止录屏
   */
  function disableIOSSys(toggle: boolean) {
    if (toggle) {
      // 从其他页面开始录屏切换到播放页
      handleIOSDSRFromOtherPage();
      // 在播放页面开始录屏
      handleIOSDSRFromCurrentPage();
    } else {
      // 取消相关的监听事件
      Taro.offScreenRecordingStateChanged(changeHandler);
    }
  }

  /**
   * 当前页面防止ios录频
   */
  function handleIOSDSRFromCurrentPage() {
    if (Taro.onScreenRecordingStateChanged) {
      Taro.onScreenRecordingStateChanged(changeHandler);
    }
  }

  /**
   * 跨屏幕防止ios录频
   */
  function handleIOSDSRFromOtherPage() {
    if (Taro.getScreenRecordingState) {
      Taro.getScreenRecordingState({
        success: res => {
          // res.state: on(正在录屏) | off(没有开始录屏)
          // 此处只需处理正在录屏的情况
          // @ts-ignore
          if (res.state === 'on') {
            setIosWatermarkingState(true);
          }
        }
      });
    }
  }

  /**
   * 屏幕录制状态变化监听函数
   */
  function changeHandler(res: any) {
    // res.state: start(开始录屏) | stop(结束录屏)
    // @ts-ignore
    if (res.state === 'start') {
      // 展示水印弹窗
      setIosWatermarkingState(true);
    } else {
      // 隐藏水印弹窗
      setIosWatermarkingState(false);
    }
  }

  function IosWatermarking() {
    return iosWatermarkingState ? <Watermarking /> : null;
  }

  return { IosWatermarking, disableScreenRecording };
};

下面是使用示例

// page/xxxx/index.tsx
import { View } from '@tarojs/components';
import { useDidHide, useDidShow } from '@tarojs/taro';

import { useDisableScreenRecording } from '@/hooks/useDisableScreenRecording';

import './index.scss';

export default function Play() {
  const { IOSWatermarking, disableScreenRecording } = useDisableScreenRecording();

  useDidShow(() => {
    disableScreenRecording(true);
  });

  useDidHide(() => {
    disableScreenRecording(false);
  });

  return (
    <View className="play">
      {/* 省略的代码 */}
      <IOSWatermarking />
    </View>
  );
}