- 지난 PWA 시리즈에 이어서 작성한 내용입니다.
- 한동안 코딩 테스트 준비로 프로그래머스 문제에 집중하다가 다시 작성!!
[01 QR code란? ]
- QR 코드(Quick Response code)는 컴퓨터가 만든 흑백 격자무늬 패턴 코드로, 정보를 나타내는 매트릭스 형식의 이차원 코드이다.
- 기존의 바코드는 기본적으로 가로 배열에 최대 20여 자의 숫자 정보만 넣을 수 있는 1차원적 구성이지만, QR코드 원리는 가로, 세로를 활용하는 2차원적 구성이다.
- 숫자 : 최대 7,079
- 문자 : 최대 4,296
- 한자 : 최대 1,817
- QR 코드의 자세한 작동 구조가 궁금하다면 아래 참고에서 확인한다.
참고 : https://codingcoding.tistory.com/95
[02 QR code 생성 ]
(1) 외부 라이브러리 결정
- QR code를 생성해주는 라이브러리는 정말 많지만, 나는 사용하기 쉽고 가운데 로고를 넣는 기능을 제공하는 quickchart.io를 사용했다.
- 다음과 같이 경로를 설정하면 반환값이 바로 QR code 이미지이기 때문에 편하게 사용할 수 있다.
- 나는 처음에 axios로 요청을 보내야하는 줄 알았는데 그냥 React 컴포넌트 img 태그 안에서 src를 해당 링크로 설정해주는 것만으로 QR code가 잘 출력된다!
https://quickchart.io/qr?text=Here's%20my%20text&dark=f00&light=0ff&ecLevel=Q&format=svg\
(2) img 호스팅 서버
- 개인 S3를 사용하면 좋지만 AWS 과금 문제 때문에 함부로 사용하기가 무섭기(?) 때문에..! 그럴 때 편하게 사용할 수 있는 무료 이미지 호스팅 서버들이 있다.
- 보안은 보장하지 못하니 중요한 문서보다는 이렇게 프로젝트에서 사용할 이미지 정도 업로드하고 사용하기 좋을 것 같다.
- 내가 사용한 곳은 ifh.cc 여기인데 무료 버전은 만료 기한이 있어서 나중에 찾은 imgbb가 더 좋은 것 같다.
- 아래와 같이 링크로 간단히 접근할 수 있다! QR code 가운데에 넣을 이미지 경로 준비 완료!!
<img src="https://i.ibb.co/TRS5yP4/favico4.png" alt="favico4" border="0">
(3) QR code
- QR code로는 데이터를 전송하거나 redirect할 URL을 넣어줄 수 있다.
- 내가 사용한 quickchart.io 라이브러리는 text 파라미터에 그 값을 넣어주면 됐다.
- link는 구독 버튼을 누를 수 있는 모바일용 페이지를 encoding하여 넣어주었다.
- 모바일 접근시 사용자 인증을 위해 query string으로 JWT Token을 암호화 전송했는데, 해당 내용은 다음 포스팅에서 다룰 예정이다.
- 그외에도 공식문서를 참고해 ecLevel과 size, centerImageUrl 옵션을 설정해주었다.
const QRcode = `https://quickchart.io/qr?text=${encodedPageLink}&ecLevel=L&size=200¢erImageUrl=https://ifh.cc/g/Y4Z5z3.png`;
더보기
모달창 component
<input type="checkbox" id="QRcode" className="modal-toggle" />
<label htmlFor="QRcode" className="modal cursor-pointer">
<label className="modal-box relative" htmlFor="">
<h2 className="card-title mb-1 text-teal-500">영양제 일정 알림 구독 서비스</h2>
<div className="divider">Web</div>
<div className="items-center justify-center flex flex-row space-x-2 p-2">
<button
onClick={subscribe}
className="px-4 py-1 text-sm text-teal-600 font-semibold rounded-full border border-teal-200 hover:text-white hover:bg-teal-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-teal-600 focus:ring-offset-2"
>
구독하기
</button>
<button
onClick={unsubscribe}
className="px-4 py-1 text-sm text-teal-600 font-semibold rounded-full border border-teal-200 hover:text-white hover:bg-teal-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-teal-600 focus:ring-offset-2"
>
구독 취소
</button>
</div>
<div className="divider">Mobile</div>
<div className="items-center justify-center flex flex-col">
<img src={useMemo(() => QRcode, [])} alt="QRcode" width="170" height="170" className="rounded-xl" />
<h3 className="text-slate-900 mt-5 text-base font-medium tracking-tight">모바일 알림 구독 QR</h3>
<p className="text-slate-500 mt-2 text-sm text-left">
영양제 일정 알림 서비스는 현재 ios에서 지원되지 않아 Android 또는 Web에서만 가능합니다. Android 접속시 google 애플리케이션의 google lens를 이용하시는 것을 추천드립니다.
</p>
</div>
</label>
</label>
[03 구독 기능 연결하기 ]
(1) 구독 / 구독 취소 버튼
- 연결된 페이지에서 구독과 구독 취소 기능을 이용할 수 있도록 버튼을 각각 만들어주었다.
- 해당 함수는 Web에서 구독, 구독 취소할 때 사용하는 함수와 같다.
더보기
/mobile/Subscribe.tsx
/* eslint-disable jsx-a11y/anchor-is-valid */
/* eslint-disable no-unreachable */
// 사용자가 모바일에서 qrcode 타고 넘어온 화면
// qrcode에 parameter로 jwt_token값 들어 있음
// 해당 jwt_token이랑 device_token으로 구독 정보 추가하도록 backend에 요청
import React from "react";
import axios from "axios";
import { AES, enc } from "crypto-js";
const Subscribe = () => {
const queryString = new URLSearchParams(window.location.search);
let encryptedToken: any = queryString.get("token");
encryptedToken = encryptedToken.replaceAll(" ", "+");
console.log(encryptedToken);
const secretKey: any = process.env.REACT_APP_SECRET_KEY;
const decryptedToken = AES.decrypt(encryptedToken, secretKey);
const jwtToken = decryptedToken.toString(enc.Utf8);
const subscribe = async () => {
const sw = await navigator.serviceWorker.ready;
// 사용자 기기 정보로 구독 요청
const subscription = await sw.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: process.env.REACT_APP_WEB_PUSH_PUBLIC_KEY,
});
// 사용자 기기 정보 DB에 추가
await axios
.post(
`${process.env.REACT_APP_MODE}:${process.env.REACT_APP_BACK_PORT}/subscribe/create`,
{ device_token: subscription },
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${jwtToken}`,
},
},
)
.then(() => {
alert("구독 신청이 완료되었습니다.");
});
};
const unsubscribe = async () => {
console.log("unsubscribe function");
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription();
if (!subscription) {
alert("구독 정보가 없는 기기입니다.");
return;
}
// 사용자 기기 정보 DB에서 삭제
await axios
.post(
`${process.env.REACT_APP_MODE}:${process.env.REACT_APP_BACK_PORT}/subscribe/delete`,
{ device_token: subscription },
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${jwtToken}`,
},
},
)
.then(() => {
alert("구독이 취소되었습니다.");
});
// 사용자 기기 정보로 구독 취소 요청
await subscription.unsubscribe();
};
return (
<div className="min-h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-md w-full space-y-8">
<div>
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">Subscribe our Service</h2>
<br />
<p className="mt-2 text-center text-sm text-gray-600">
Web 혹은 Android에서만 가능합니다. <br />
알림 권한 요청에 "허용"을 눌러주세요.
</p>
</div>
<div className="flex justify-center">
<button
className="px-4 py-1 text-sm text-teal-600 font-semibold rounded-full border border-teal-200 hover:text-white hover:bg-teal-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-teal-600 focus:ring-offset-2"
onClick={() => subscribe()}
>
구독하기
</button>
</div>
<div className="flex justify-center">
<button
className="mb-32 px-4 py-1 text-sm text-teal-600 font-semibold rounded-full border border-teal-200 hover:text-white hover:bg-teal-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-teal-600 focus:ring-offset-2"
onClick={() => unsubscribe()}
>
구독 취소하기
</button>
</div>
</div>
</div>
);
};
export default Subscribe;
(2) 고려할 점
- 나는 각각의 버튼을 분리해놓는게 좋다고 판단해서 QR 접속 이후 본인이 클릭하도록 했지만, QR code 접속시 바로 구독이 되도록 하려면 subscribe( ) 함수를 useEffect 훅에 넣는 방식으로 수정할 수 있을 것 같다.
- 여기까지 해서 기능구현은 모두 완료가 되었는데, 이후 개선한 점은 외전이라고 붙여서 올릴 예정이다.
'엘리스 AI트랙 4기 > 프로젝트' 카테고리의 다른 글
[PWA] Push Notification 외전2. chrome에서의 subscription token 만료 문제 (feat. nodemailer) (0) | 2022.07.31 |
---|---|
[PWA] Push Notification 외전1. query string으로 사용자 인증값 전달하기 (feat. AES 암호화) (0) | 2022.07.27 |
[PWA] Push Notification 알림 자동 발송하기 (feat. node-schedule) (1) | 2022.07.18 |
[PWA] Push Notification 상황별 다른 알림 옵션 설정하기 (0) | 2022.07.16 |
[PWA] Push Notification Nodejs 프로젝트에 적용하기 (0) | 2022.07.15 |