React에서 하이브리드 앱 bridge 연결하기 (with nextjs)

Jungmin Lee·2023년 1월 8일
5

회사에서 웹으로 개발한 프로젝트를 앱으로 패키징 작업을 진행하였습니다.
앱에서 로그인 유지와 사진첩 권한, 팝업 창 설정 등등을 해줘야 하기 때문에 brdige 연결 작업을 진행했습니다.
진행하고 생각해보면 그렇게 어려운 작업은 아니였는데, 연결 과정에서는 정말 많은 시행착오를 겪었습니다.
그래서 기록으로 남기기 위해 블로그에 작성하기로 결정했습니다.

nextjs에서 작업을 진행했기에 nextjs 위주로 작성하겠습니다.

1.nextJs에서 안드로이드와 iOS 구별하는 법

// _app.tsx 파일에서 

const dispatch = useDispatch();

useEffect(() => {
    // userAgent에 ios // android 가 있는 지 확인해줍니다.
    const iOS = navigator.userAgent.match(/iOS_App/i);
    const Android = navigator.userAgent.match(/Android_App/i);
    // 전역으로 사용할 것이기 때문에 리덕스에 데이터를 보관해주었습니다. 
    if (iOS) dispatch(userAgentAction.set('iOS_App'));
    if (Android) dispatch(userAgentAction.set('Android_App'));
  }, []);
  1. userAgent로 어떤 기기로 사용하고 있는지 확인합니다.
    nextjs에서는 _app.tsx 파일에서 useEffect로 기기판별을 하도록 해주었습니다.
  2. 전역으로 사용해야 하기때문에 리덕스 or 로컬스토리지에 분기처리를 할 수 있는 값들을 저장합니다.

2.웹에서 앱으로 브릿지 호출

// 웹에서 앱 함수를 실행 시켜준다.
// 여기서 신경써야할 부분은 함수명이 같아야하고, paramter값을 알고 있어야한다.
// 보통은 안드로이드와 iOS가 별도로 처리되니, 따로 분기 처리를 해줄 필요가 있다.

requestPermissionCheck = () => {
    if (userAgent === 'Android_App') {
    window.android.test();
  } else if (userAgent === 'iOS_App') {  
    window.webkit.messageHandlers.test.postMessage('');
  }
}
  1. 안드로이드와 iOS 함수 호출방법이 다르기 때문에 각각 따로 코드를 작성해주어야 합니다.
  2. 안드로이드는 전역으로 사용하기 위해 window에 android라는 객체 안에 함수들을 넣어주었습니다.
    해당 프로젝트는 window.android.test()로 호출을 합니다.
    이건 앱개발자와 소통을 하여 어떻게 사용할건지 정해서 사용하면 됩니다.
    3 iOS는 webkit을 사용하기 때문에 window.webkit.messageHandlers.[함수이름].postMessage()로 호출해주면 됩니다.
    [함수이름]에 호출할 함수명을 작성해주면 됩니다. 여기서 제가 겪었던 이슈에 대해 설명드리자면 아무런 인자가 없을 경우 postMessage()로 호출 했을 떄 브릿지가 가지 않는 현상이 발생했습니다.
    그래서 postMessage('') 처럼 빈문자열을 넣어주었더니 제대로 호출됐습니다.(설정 문제인지,아닌지는 정확한 이유는 파악하지 못했지만, 해당 이슈로 호출이 되지 않았습니다.)
    그리고 저는 겪지 못했지만, 타이밍 이슈가 발생할수도 있기에 호출이 되지 않을 땐, 그 부분도 고려하는게 좋습니다.

3.앱에서 웹으로 브릿지 호출

useEffect(() => {
    if (userAgent === 'Android_App') {
      window.test = () => {alert('안드로이드 호출 성공!')};
    } else if (userAgent === 'iOS_App') {
      window.test = () => {alert('iOS 호출 성공!')};
    }
},[])
  1. 앱에서 웹 함수를 실행합니다.
    즉, 웹에서 실행할 수 있는 함수를 만들어 놓아야합니다.
  2. 리액트 특성상 useEffect안에 함수를 선언 해줍니다.

4.그 밖에 패키징 하는 과정에서 겪었던 팁들 정리

input box focus시 화면 비율 깨졌을 때

     <meta
       name="viewport"
       content="initial-scale=1.0,userscalable=no,maximum-scale=1,width=device-width"
	/>
  • 헤더 태크에 meta 태그를 추가해주면 비율이 깨지지 않고, 잘 유지됩니다.

카메라 사진 권한주기

  //파일 온클릭
  const handleFileClick = () => {
    // 앱이 아닐 경우 그냥 클릭
    if (userAgent === '') {
      fileRef?.current?.click();
    } else {
      // 앱일 경우 웹 => 앱 브릿지 신청
      requestPermissionCheck(userAgent, 'file');
    }
  };

// 앱에서 이미지 or 파일 온클릭 (앱->웹)
  useEffect(() => {
    if (userAgent === 'Android_App') {
      window.openGallery = () => {
        imgRef?.current?.click();
      };
      window.openFileUpload = () => {
        fileRef?.current?.click();
      };
    } else if (userAgent === 'iOS_App') {
      window.openGallery = () => {
        imgRef?.current?.click();
      };
      window.openFileUpload = () => {
        fileRef?.current?.click();
      };
    }
  }, []);


// 사진 input box `capture={true}` 추가
// 안드로이드는 capture atrribute가 필요하지만, iOS는 없어야 합니다. 별도 처리가 필요합니다.
  <input
    ref={imgRef}
    type="file"
    accept="image/*"
    capture={userAgent === 'Android_App' && true}
  />
  • input box를 클릭 했을 때 웹=>앱 브릿지를 통해 권한 신청을 합니다.
  • 권한 수락이 되면 앱=>웹 브릿지를 호출합니다.
    호출한 브릿지는 input box를 클릭하도록 해줍니다.
  • 사진 input 태그에 capture={true} 추가합니다.
    단, 안드로이드는 capture atrribute가 필요하지만, iOS는 capture가 있으면 제대로 작동을 하지 않기 떄문에 별도 처리가 필요합니다.

로그인 상태 유지하기

저희 프로젝트의 경우는 로그인 했을 때 웹에서 앱으로 브릿지를 보냅니다. 보낼 때 로그인 할때 필요한 데이터를 보내줍니다.
로그아웃 할땐 그 데이터들을 삭제해주는 브릿지를 호출해줍니다.
이렇게만 하면 간단하지만, 앱에서 로그인 상태를 유지를 하기위해서는 데이터가 있는지 확인 과정이 필요합니다.
그래서 스플래쉬페이지 or 메인페이지에서 로그인에 필요한 데이터가 기기에 저장되어 있는지 확인을 하기위한 브릿지를 한번 더 호출합니다.
만약 그 브릿지가 있으면 브라우저 로컬스토리지에 저장해서 로그인 처리를 해주고 없다면, 비로그인 상태로 유지됩니다.

  1. 로그인 후 데이터 기기 저장.
  2. 앱 종료 후 다시 실행 했을 때, 스플래쉬 or 메인페이지에서 기기에 데이터 저장 되었있는지 확인.
  3. 데이터가 저장되어 있다면, 그 데이터를 웹스토리지에 저장하여 로그인 유지

** 하이브리드앱이라서 모든 처리는 웹에서 하기 때문에 로그인 유무도 브라우저에서 처리하는 방식으로 진행해야합니다.
즉, 로컬스토리지 or 쿠키에 로그인 필요 데이터가 없으면 로그인 상태가 풀리게 되고, 있으면 로그인 상태가 유지되게 됩니다.

도움받은 사이트들

https://www.howdy-mj.me/next/how-to-detect-device
https://gradler.tistory.com/33

profile
Front-end developer who never gives up.

0개의 댓글