林's

[Front] 불펌방지 적용하는 방법 본문

프로그래밍/웹프론트

[Front] 불펌방지 적용하는 방법

풀림이 2019. 12. 14. 21:32

context menu

요즘은, pc보다 모바일을 더 많이 사용하는 시대죠.

사진이나 동영상의 경우 스마트폰을 길게 누르면 나타나는 contextmenu 창을 통해 손 쉽게 이미지나 영상을 다운로드 할 수 있습니다.

저작권이 있는 이미지라면, 이는 상당히 골치아픈 문제가 될 수 있습니다.

사용자와 창작자 둘을 보호하기 위한 취지로 개발된 소스이나, 요즘 스마트폰은 해상도도 좋아서, 스크린샷을 찍어버리면 사실 답이 없습니다.. ㅎㅎ

그래도 개발해야한다면 어쩔 수 없겠죠.. 안드로이드와 PC, 그리고 IOS 계열의 경우 크로스 브라우징을 생각한 적용법을 알아봅시다.

 

1. 과거에는 어떻게 했을까?

단순히, contextmenu 이벤트를 캐치해서 기본동작을 막아버리는 방법을 사용했습니다.

1). PC/Android

class ImageProtector {

  protect = (img) => {
      img.addEventListener('contextmenu', this.onContextMenu);
  };

  unprotect = (img) => {
      img.removeEventListener('contextmenu', this.onContextMenu);
  };

  onContextMenu = (e) => {
      e.preventDefault();
      e.stopPropagation();
      // alert("저작권 보호를 위해서 복사는 금지되어 있습니다.");
  };
}

export default new ImageProtector();

 

2). IOS/IPhone

ios는 간단합니다. 아래의 css를 img 엘리먼트에 추가해주면 됩니다.

 

.hide_context_menu {
  -webkit-touch-callout: none;
}

요로케 말이죠~

<img className="hide_context_menu"/> 

하지만, 이 css는 ios11 이하에서는 동작하지 않습니다.

 

2. 크로스 브라우징

오래된 IOS 버전에서는 위의 css 가 적용되지 않고, Android WebView 에서도 contextmenu 가 동작하지 않는 경우가 있습니다.

이럴 경우에는, contextmenu 가 뜨기 직전에 alert() 함수를 호출시켜서 컨텍스트 메뉴가 뜨는 걸 막는 방법이 있습니다.

alert와 confirm 함수에는 이전 프로세스를 일시 정지 시키는 기능이 내장되어 있기 때문인데요.

이러한 특징을 활용하여, 메뉴창이 뜨기 바로 직전에 호출시켜서 막아버리는 방법을 사용해보죠!

 

const DURATION_TOUCH = 420;

class ImageProtector {
  static timer = null;
  protect = (img) => {
    img.addEventListener("touchstart", this.onTouch, false);
    img.addEventListener("touchmove", this.stopTimer, false);
    img.addEventListener("touchend", this.stopTimer, false);
  }

  unProtect = (img) => {
    img.removeEventListener("touchstart", this.onTouch);
    img.removeEventListener("touchmove", this.stopTimer);
    img.removeEventListener("touchend", this.stopTimer);
  }

  onTouch = () => {
    this.stopTimer(); // 확대 축소와 관련된 이벤트를 쓰고 있을 경우 타이머를 꺼줘야합니다.
    ImageProtector.timer = setTimeout(() => {
      alert("저작권 보호를 위해 이미지를 저장할 수 없습니다.");
      this.stopTimer(); // alert 이후에 사진선택 상태일 시, touchend 가 호출되지 않습니다. 그래서 여기서 제거해요.
    }, DURATION_TOUCH);
  }

  stopTimer = () => {
    ImageProtector.timer && (ImageProtector.timer = clearTimeout(ImageProtector.timer));
  }
}

export default new ImageProtector();

사용하실 때는 import ImageProtector from "소스 경로";

처럼 편한 이름으로 임포트를 하시고, 이미지 레퍼런스를 함수에 전달해서 쓰시면 됩니다. : )

ImageProtector.protect(이미지레퍼런스);

ImageProtector.unprotect(이미지레퍼런스);

 

저와같은 문제를 겪으셨던 분들에게 많은 도움이 되길 기도합니다. ^^

Comments