[기능구현][RN] Deep link를 수신 후 앱 특정 페이지로 redirect 하기

Wonhyun Kwon·2023년 5월 18일
0

기능 구현

목록 보기
1/4
post-thumbnail

📌 딥링크에 대한 자세한 내용은 여기를 클릭하면 된다.

Environment

  1. 개발 플랫폼: macOS
  2. 개발 언어: JavaScript, TypeScript
  3. 개발 프레임워크: React Native(0.68.5)
  4. 버전 관리: GitHub
  5. 개발 도구: Visual Studio Code
  6. 배포 환경: Xcode(14.1), Android Studio(chipmunk 2021.2.1)

개발 목적

1. 문제점 도출

  • none

2. 요구 사항

  • url 에 따라 목적에 맞는 앱 페이지 연결

3. 기대값 설정

  • url 에 따라 navigation 을 이용하여 원하는 페이지로 redirect
  • url 에 포함되어 있는 query 전달 및 해당 함수 실행
  • 앱의 역할이 끝난 후 다시 기존 페이지로 redirect

문제 해결

1. 환경설정

1) iOS

RN 을 사용하긴 하지만 URL을 통해 접속했을 때, 해당 URL을 제어해주기 위해서 다음과 같이 native 단에서 들어가야 할 필수 코딩이 있다.

ios > {프로젝트} > AppDelegate.mm 파일

// 파일 상단에 import
#import <React/RCTLinkingManager.h>


// 본문에 다음 내용 insert
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  return [RCTLinkingManager application:application openURL:url options:options];
}

다음으로 Xcode 에서 Deep link 를 설정한다.
참고로 Universal link 가 아닌 일반적인 URL Schemes 를 적용했다.

먼저, Xcode 에서 아래 이미지에 따라 들어간다.

Identifier 에 프로젝트의 Bundle ID 를 넣는다.
URL Schemes 부분에 본인이 원한하는 이름의 프로토콜 이름을 정하면 된다
ex) whkwon 으로 지정하면 프로토콜이 커스터마이징 되어 앞으로 브라우저에서 whkwon:// 딥링크를 타고 앱 접속을 시도할 수 있다.


2) Android

아래와 같이 AndroidManifest.xml 파일에 intent-filter 태그를 추가한다.

android > app > src > main > AndroidManifest.xml

<intent-filter>
	<action android:name="android.intent.action.MAIN" />
	<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<!-- 여기서부터 추가 -->
<intent-filter>
	<action android:name="android.intent.action.VIEW" />
	<category android:name="android.intent.category.DEFAULT" />
	<category android:name="android.intent.category.BROWSABLE" />
	<data android:scheme="kwt" android:host="main" />
</intent-filter>

🔔 참고
Android 는 하기 adb 명령어를 통해 Deep link 를 실행할 수 있다.

adb shell am start -W -a android.intent.action.VIEW -d "${scheme}://${host}" ${앱 패키지명}

2. URL 처리

딥링크를 타고 들어오면 가장 먼저 어떤 URL 인지 파악해야 한다.
이를 위해 RN 은 기본적으로 Linking 컴포넌트를 지원한다.

Linking 컴포넌트란 ?

  • 앱 내에서 URL 을 처리하고 외부 앱이나 브라우저와의 상호작용을 관리한다.
  • 지정된 URL 을 사용자의 기본 웹 브라우저나 다른 앱에서 연다.
  • 외부 앱에서 현재 앱으로 돌아올 때 콜백을 처리할 수 있다.
  • Deep link 를 통해 특정 화면으로 이동시킨다.

Linking 의 여러 가지 메소드가 존재하지만, Deep link 로부터 들어오는 URL 을 파악하고 처리하기 위해선 addEventListener() 메소드가 필요하다.

  const handleOpenURL = ({ url }: any) => {
    const path = url.split('//')[1];
    if (path.startsWith('wc?uri=')) {
      const uri = decodeURIComponent(path.slice(7));
      navigation.navigate('작업 처리할 컴포넌트', { uri: uri ? uri : '' });
    }
  };

  Linking.addEventListener('url', handleOpenURL);

먼저, URL 을 listening 하여 콜백 함수를 실행한다. (제일 아래줄 코드)
콜백 함수 안에서는 path 를 잘라내기 위해 split 메소드로 // 이후의 값을 가져왔다.
if 조건문으로 path 별 원하는 결과를 수행하도록 분기점을 만들었고, 브라우저 상에서 encoding 되어 들어오는 값을 decoding 하여 최종적으로 처리를 원하는 컴포넌트에 navigation 으로 파라미터와 함께 넘겨주었다.


3. 이슈 사항

1) Webview의 Custom URI Scheme 에러

react-native-webview 라이브러리를 사용하여 앱 내에서 브라우저가 실행되는 in-app-browser 환경에서 작업하였다.

하지만, iOS 에서만 Custom URI Scheme 을 인식하지 못하는 문제점을 발견했다. (하기 이미지 참조)
(물론, regular한 URL 프로토콜인 http 또는 https 에서는 URL 오픈이 잘됐다.)

이를 위해 첫 번째는, info.plist 에서 LSApplicationQueriesSchemes 키 값을 추가하는 것이었다.
LSApplicationQueriesSchemes 란, Xcode 의 info에선 Queried URL Schemes 로 정의되며, 외부 앱의 URI Scheme 을 허용하는 설정이다.

info.plist 기준 아래와 같이 설정하였다.

ios > {프로젝트} > info.plist

<key>LSApplicationQueriesSchemes</key>
<array>
	<!-- :// 은 생략하고 scheme 이름만 넣는다. -->
	<string>customschemes</string> 
</array>

하지만, 여전히 동작하지 않았다.


그 다음 Webview 파라미터인 onShouldStartLoadWithRequest 를 이용해서 원하는 action을 만들어줬다.
(참고로 react-native-webview 의 버전은 "11.23.1" 을 사용하였다.)

onShouldStartLoadWithRequest 파라미터는 링크 요청이 발생하기 전에 호출되는 콜백으로 action을 정의하는 함수이다. booleanreturn 하는데, true 이면 해당 페이지를 load하고, false 이면 링크를 무시한다.

이를 이용해서 사전에 정한 URI Schemeredirection 할 땐 Link를 Open하여 앱의 특정 페이지로 유도는 하지만, WebViewURI Scheme 을 load하지 않도록 설정하여 해결하였다.

<WebView
  ...
  onShouldStartLoadWithRequest={event => {
    if (event.url.startsWith('yourScheme://')) {
      Linking.openURL(event.url); // link는 open하여 딥링크를 실행한다.
      return false; // 하지만, WebView는 link를 load하지 않는다.
    }
    return true;
  }}
/>

2) 앱이 꺼진 상태에서 딥링크 클릭 시 초기화되는 이슈

앱이 종료 된 상태로 외부에서 딥링크를 클릭했을 때, 앱은 실행되지만 Action은 하지 않는 경우다.

원인은 모든 앱이 공통적으로 처음 시작할 때 '초기화' 작업을 거치기 때문에 Linking.addEventListener 로 딥링크를 리스닝하던 작업 역시 초기화가 되어버린다.

따라서, 앱 시작 시 Linking.getInitialURL() 메소드를 사용하여 딥링크가 있는지 확인하고, 있을 경우 따로 처리를 해줘야 한다.

useEffect(() => {
  const getInitURL = async () => {
    const initURL = await Linking.getInitialURL(); // 없을 경우 null을 반환한다.
    if (initURL) {
      const path = initURL.split('//')[1];
      if (path.startsWith('wc?uri=')) {
        const uri = decodeURIComponent(path.slice(7));
        navigation.navigate('작업 처리할 컴포넌트', { uri: uri ? uri : '' });
      }
    }
  };
  getInitURL();
}, []);

개선 및 향상

  • 딥링크 사용성에 대한 가장 큰 목적은 '광고 성과를 높이는 것' 에 있다.
    우리가 원하는 서비스를 필요로 하는 사용자에게 알리기 위해선 홍보는 필수이며, 필요성을 느낀 사용자는 클릭 하나로 우리의 서비스를 제공할 수 있어야 한다.

  • 그런 의미에서 딥링크는 광고 성과를 최적화 할 수 있는 방법 중 하나이다.
    이를 구현함으로서 서비스를 이용하기 위해 적어도 3~4번의 클릭과 불필요한 페이지 depth, 서비스를 이용하기 위해 사용자가 갖춰야 할 학습 내용 등을 모두 무시하고 단 한 번의 클릭으로 특정 페이지를 redirection 하여 바로 서비스를 이용할 수 있도록 함으로써 사용자 경험(UX) 및 편의성을 극대화하였다.

profile
모든 사용자가 만족하는 UI를 만드는 FE 개발자 권원현입니다.

0개의 댓글