Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature/#443] Notification 딥링크/웹링크 설정 #468

Merged
merged 21 commits into from
Dec 4, 2023

Conversation

yxnsx
Copy link
Contributor

@yxnsx yxnsx commented Nov 26, 2023

푸시 알림 Notification의 딥링크 및 웹링크 처리 로직을 구현하였습니다.
지금은 간단하게 설명만 적었지만 .. 나중에 시퀀스다이어그램이라도 추가해놓겠습니다..


주요 클래스

  • DeepLinkType.kt
    • 앱 내에서 사용 중인 딥링크가 정의된 enum 클래스입니다.
    • 추가 딥링크 정의가 필요할 시에 이 클래스에 정의해서 사용하시면 됩니다.
  • SchemeActivity.kt
    • 딥링크 및 웹링크의 유효성을 체크하고 해당 intent를 처리하는 Activity입니다.

DeepLinkType.kt

enum class DeepLinkType(
    val link: String
) {
    HOME("home") {
        override fun getIntent(
            context: Context,
            userStatus: UserStatus,
            deepLink: String,
        ): Intent {
            return getHomeIntent(context, userStatus)
        }
    },
    NOTIFICATION_LIST("home/notification") {
        override fun getIntent(
            context: Context,
            userStatus: UserStatus,
            deepLink: String,
        ): Intent {
            return userStatus.setIntent(
                context,
                Intent(context, NotificationHistoryActivity::class.java)
            )
        }
    },
    NOTIFICATION_DETAIL("home/notification/detail") {
        override fun getIntent(
            context: Context,
            userStatus: UserStatus,
            deepLink: String,
        ): Intent {
            val notificationId = deepLink.extractQueryParameter("id")
            return userStatus.setIntent(
                context,
                NotificationDetailActivity.getIntent(
                    context,
                    NotificationDetailActivity.StartArgs(notificationId)
                )
            )
        }
    },
    ...
}

DeepLinkType 내에 정의된 딥링크들은 위와 같은 형태이고요 ..

    companion object {
        private fun UserStatus.setIntent(
            context: Context,
            intent: Intent,
        ): Intent {
            return when (this == UserStatus.UNAUTHENTICATED) {
                true -> AuthActivity.newInstance(context)
                false -> intent
            }
        }

        fun getHomeIntent(
            context: Context,
            userStatus: UserStatus,
            deepLinkType: DeepLinkType? = null
        ): Intent {
            return userStatus.setIntent(
                context,
                HomeActivity.getIntent(
                    context,
                    HomeActivity.StartArgs(
                        userStatus = userStatus,
                        deepLinkType = deepLinkType
                    )
                )
            )
        }

        operator fun invoke(deepLink: String): DeepLinkType {
            return try {
                val link = deepLink.split("?")[0]
                val expiredAt = deepLink.extractQueryParameter("expiredAt")
                when (expiredAt.isExpiredDate()) {
                    true -> EXPIRED
                    else -> entries.find { it.link == link } ?: UNKNOWN
                }
            } catch (exception: Exception) {
                Timber.e(exception)
                UNKNOWN
            }
        }
    }

DeepLinkType의 companion object로 위와 같은 함수들을 선언해두었습니다.
딥링크를 통해 이동하는 페이지는 현재 모두 솝트 회원을 대상으로 하고 있기 때문에
인텐트 매핑 과정에서 UserStatus가 UNAUTHENTICATED인 경우 AuthActivity로 넘기도록 처리하였습니다.


SchemeActivity

    private fun handleDeepLink() {
        val link = args?.link
        val linkIntent = when (link.isNullOrBlank()) {
            true -> NotificationDetailActivity.getIntent(
                this,
                NotificationDetailActivity.StartArgs(
                    notificationId = args?.notificationId ?: ""
                )
            )
            false -> checkLinkExpiration(link)
        }

        when (!isTaskRoot) {
            true -> startActivity(linkIntent)
            false -> TaskStackBuilder.create(this).apply {
                if (!isIntentToHome(linkIntent)) addNextIntentWithParentStack(
                    DeepLinkType.getHomeIntent(this@SchemeActivity, UserStatus.of(dataStore.userStatus))
                )
                addNextIntent(linkIntent)
            }.startActivities()
        }
        finish()
    }

    private fun checkLinkExpiration(link: String): Intent {
        return try {
            val expiredAt = link.extractQueryParameter("expiredAt")
            when (expiredAt.isExpiredDate()) {
                true -> DeepLinkType.getHomeIntent(
                    this,
                    UserStatus.of(dataStore.userStatus),
                    DeepLinkType.EXPIRED
                )
                else -> when (link.contains("http://") || link.contains("https://")) {
                    true -> Intent(Intent.ACTION_VIEW, Uri.parse(link))
                    false -> DeepLinkType.invoke(link).getIntent(
                        this,
                        UserStatus.of(dataStore.userStatus),
                        link
                    )
                }
            }
        } catch (exception: Exception) {
            Timber.e(exception)
            DeepLinkType.getHomeIntent(
                this,
                UserStatus.of(dataStore.userStatus),
                DeepLinkType.UNKNOWN
            )
        }
    }

수신한 링크가

  • 공백인지
  • 만료되었는지,
  • 알 수 없는 링크인지

등에 대한 유효성을 체크합니다.

유효성 체크가 끝나면 http:// 또는 https:// 포함 여부로 링크를 딥링크/웹링크로 구분하고
해당 타입에 따른 intent를 실행합니다.

  • 딥링크일 경우, DeepLinkType.invoke(link).getIntent()
  • 웹링크일 경우, Intent(Intent.ACTION_VIEW, Uri.parse(link))

@yxnsx yxnsx added the enhancement New feature or request label Nov 26, 2023
@yxnsx yxnsx self-assigned this Nov 26, 2023
@yxnsx yxnsx requested a review from a team as a code owner November 26, 2023 09:40
@yxnsx yxnsx force-pushed the feature/yxnsx/#443-notification-links branch from a8f84f1 to 34dd6db Compare November 26, 2023 09:49
@yxnsx yxnsx force-pushed the feature/yxnsx/#443-notification-links branch from 34dd6db to c0923af Compare November 26, 2023 09:52
Copy link
Member

@l2hyunwoo l2hyunwoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

한번만 확인해주세요

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yxnsx 이거 전부 singleTask건 이유가 있을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

마이페이지를 예로 들면,
마이페이지에 있는 상태에서 마이페이지로 딥링크가 설정된 노티를 클릭할 시
마이페이지가 2중으로 뜨는 문제가 있습니다..!
그래서 딥링크를 통해 라우팅되는 페이지에는 singleTask를 걸어놨어요

Copy link
Contributor

@hjh1161514 hjh1161514 Dec 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 이 부분이 궁금했는데요, 딥링크 시 이동되는 화면 위에 다른 activity가 열리는 경우는 없을까요?? (마이페이지의 경우 마이페이지에서 다른 activity로 이동) 그런 경우가 있다면 singleTop이 더 안전할 것 같아서요.

Comment on lines 372 to 374
data class StartArgs(
val isNeedToOpenAttendanceCodeDialog: Boolean = false,
) : Serializable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 형식으로 Argument로 넘겨야 하는 이유가 있을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

원래는 출석체크 페이지로 이동하는 딥링크 / 출석체크 페이지에서 다이얼로그까지 여는 딥링크
이렇게 두 가지의 딥링크가 있었는데 다이얼로그까지 여는 딥링크의 경우 사용 빈도가 낮을 것 같다고 해서
출석체크 페이지로 이동하는 딥링크로 통합되었습니다!
이부분은 이제 불필요한 부분이긴 하네요 원복해서 푸시해뒀습니다

Comment on lines 33 to 40
val linkIntent = when (
link.contains("http://")
|| link.contains("https://")
) {
true -> checkWebLinkExpiration(link)
false -> checkDeepLinkExistence(link)

}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이정도면 그냥 if문으로 처리해줘도 될듯?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오키 ~~! 수정해서 푸시해뒀습니다

@kimdahyee
Copy link
Contributor

주소의 expire date는 DeepLinkType enum class의 invoke 함수와 schemeActivity에서 두번 체크하게 되는걸까요 ~?

@yxnsx
Copy link
Contributor Author

yxnsx commented Dec 3, 2023

주소의 expire date는 DeepLinkType enum class의 invoke 함수와 schemeActivity에서 두번 체크하게 되는걸까요 ~?

@kimdahyee 중복된 부분 삭제해서 푸시해뒀습니다~!

@yxnsx yxnsx merged commit 809044b into develop Dec 4, 2023
1 check passed
@yxnsx yxnsx deleted the feature/yxnsx/#443-notification-links branch December 4, 2023 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request size/XL
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants