클립보드 복사, 링크 공유하기 기능 만들기 | 모바일 사파리,크롬 애플기기 에러

인마헷·2023년 11월 19일
post-thumbnail

OpenAI api와 DeepL api로 유저가 질문을 하면 타로 카드를 뽑을 수 있고 이를 GPT가 해석해주는 서비스이다.
DeepL api 경우는 무료 버전을 사용 중인지라..쿼터가 넘으면 사용불가다ㅎ

질문하러 가기 👉🏻 GPTarot💫


링크 공유하기를 구현 핵심으로 생각했는데 다 만들어두고 링크 공유하기 기능에서 막혀버렸다.

Clipboard API 사용하기

원래 참고했던 documment.execCommand()는 더이상 사용하지 않는다. 이를 대체하기 위한 것이 clipboard api인데 아래 문서를 참고했다.

Clipboard 오브젝트 생성 대신에 navigator.clipboard로 접근 가능.
단순히 url 복사만 할 거라서 writeText()를 사용했고, 만약 이미지 등의 복사가 필요하면 write()가 필요해 보인다.
*MDN: Writes text to the system clipboard, returning a  which is resolved once the text is fully copied into the clipboard.

클립보드 복사하기 코드는 대강 다음과 같다.

const copyToClipboard = async (url) => {
  try {
    await navigator.clipboard.writeText(url);
  } catch (err) {
    console.error('Failed to copy!', err);
  }
};

그래서 공유하기 버튼을 클릭하면 링크가 복사되어야 하는데, 문제는 데스크톱에서는 정상 작동하는 clipboard api가 모바일에서만 동작을 하지 않는다는 점이었다.

처음에는 clipboard api 지원이 되지 않는 상황인 것으로 판단하여 fallBack 함수를 정의했다.

응, 그래도 안 돼 🤷🏻‍♀️

더군다나 clipboard api는 크롬과 사파리 모두 모바일, 데스크톱 지원이 되는데.

도대체가 왜 안 되는 건가.

애플 기기에서 클립보드 복사 안 되는 이슈

▶️ 참고한 포스트 : Javascript Clipboard API write() does not work in Safari

위의 질문에서 힌트를 얻어가보자면,

Safari 및 일부 다른 브라우저에서 클립보드 작업은 클릭 이벤트와 같은 사용자 작업에 의해 directly하게 트리거되어야 한다. 클립보드 명령을 실행하기 전에 네트워크 요청(또는 비동기 작업)을 수행하면 브라우저에서 더 이상 사용자의 직접적인 결과로 간주하지 않아 클립보드 작업에 대한 액세스가 차단될 수 있다.

왜 이런 문제가 발생했냐 하면,

const handleClick = async () => {
    try {
      await axiosInstance.post("/save", bodyData);
      const url = `공유할 링크`;
      copyToClipboard(url);
    } catch (error) {
      console.error(error);
    }
  };

공유하기 버튼을 클릭했을 때 그제서야 데이터 베이스에 카드에 대한 해석과 uuid, 카드 이미지 등을 저장하게 설계했었다.

그럼 왜 이렇게 설계했냐?

사용자 권한 별로 기능을 구분할 필요가 없는 작은 서비스였다보니, 굳이 모든 요청에 대해서 데이터베이스 저장을 할 필요가 없다고 판단했고, 그래서 공유하기를 클릭했을 경우에만 네트워크 요청을 보내게끔 코드를 작성했는데. 이게 문제였다.

이를 해결하기 위해 찾은 방법 중 하나가 ClipboardItem 객체를 생성하고 여기에 내가 보낼 요청을 보내고 기다렸다가 복사하는 것이 있었다.

그런데, 음…그냥 Optimistic한 관점을 취하기로…(하핳😂)

대신에 선택한 방법은,

비동기 요청 보내고 그냥 넘기는 게 아니라 await는 유지하되 아래와 같이 코드의 순서를 변경했다. 일단 링크를 카피해두고, 클립보드 카피 요청은 보낸다. 그리고 await를 해서 데이터 베이스에 결과 저장을 기다렸다가 만약에 에러가 나면 alert를 띄우는 것으로….

const handleClick = async () => {
    try {
      const url = `공유할 링크`;
      copyToClipboard(url);
      await axiosInstance.post("/save", bodyData);
    } catch (error) {
      alert("결과 저장에 실패했습니다.");
      console.error(error);
    }
  };

만약에 데이터 베이스에 저장이 안 되면 링크 복사는 성공하지만 공유했을 때 아무것도 뜨지 않는다…ㅋ

아예 그냥 api설계를 다시 해보는 것도 방법일 것 같다. 애초에 카드 선택했을때 uuid 생성과 동시에 DB저장하는 방향으로 향후 다시 바꿔봐야겠다.


이제 남은 건 SNS 공유하기.
트위터는 해결했고, 카카오톡이 남았는데 생각보다 까다롭다.


(+수정)

카카오톡 공유하기 기능 구현 완료.

profile
비공개 글이 너무 많다...My code may sink, but at least I can swim🤿

0개의 댓글