diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9a85b9266..9a8d3586c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -38,7 +38,6 @@
android:host="oauth"
android:scheme="kakao${NATIVE_APP_KEY}" />
-
diff --git a/core/designsystem/src/main/java/com/terning/core/designsystem/type/NotificationRedirect.kt b/core/designsystem/src/main/java/com/terning/core/designsystem/type/NotificationRedirect.kt
index 9b85a3d8b..221aa43c0 100644
--- a/core/designsystem/src/main/java/com/terning/core/designsystem/type/NotificationRedirect.kt
+++ b/core/designsystem/src/main/java/com/terning/core/designsystem/type/NotificationRedirect.kt
@@ -1,12 +1,14 @@
package com.terning.core.designsystem.type
-enum class NotificationRedirect(val path: String) {
+enum class DeeplinkType(val path: String) {
CALENDAR("calendar"),
HOME("home"),
- SEARCH("search");
+ SEARCH("search"),
+ KAKAOLINK("kakaolink"),
+ INTERN("intern");
companion object {
- fun from(type: String?): NotificationRedirect? =
+ fun from(type: String?): DeeplinkType? =
entries.firstOrNull { it.path.equals(type, ignoreCase = true) }
}
}
diff --git a/core/designsystem/src/main/java/com/terning/core/designsystem/util/DeeplinkDefaults.kt b/core/designsystem/src/main/java/com/terning/core/designsystem/util/DeeplinkDefaults.kt
index 211113ff9..fd105e119 100644
--- a/core/designsystem/src/main/java/com/terning/core/designsystem/util/DeeplinkDefaults.kt
+++ b/core/designsystem/src/main/java/com/terning/core/designsystem/util/DeeplinkDefaults.kt
@@ -1,7 +1,24 @@
package com.terning.core.designsystem.util
+import android.net.Uri
+
object DeeplinkDefaults {
+ private const val SCHEME: String = "terning"
const val REDIRECT: String = "redirect"
+ const val INTERN_ID: String = "internId"
+
+ fun build(
+ host: String,
+ redirect: String? = null,
+ internId: String? = null
+ ): String {
+ val uriBuilder = Uri.Builder()
+ .scheme(SCHEME)
+ .authority(host)
+
+ redirect?.let { uriBuilder.appendQueryParameter(REDIRECT, it) }
+ internId?.let { uriBuilder.appendQueryParameter(INTERN_ID, it) }
- fun build(base: String) = "terning://${base}"
-}
\ No newline at end of file
+ return uriBuilder.build().toString()
+ }
+}
diff --git a/core/designsystem/src/main/java/com/terning/core/designsystem/util/KakaoUtil.kt b/core/designsystem/src/main/java/com/terning/core/designsystem/util/KakaoUtil.kt
index 267575616..cabf68afb 100644
--- a/core/designsystem/src/main/java/com/terning/core/designsystem/util/KakaoUtil.kt
+++ b/core/designsystem/src/main/java/com/terning/core/designsystem/util/KakaoUtil.kt
@@ -37,7 +37,6 @@ class KakaoUtil @Inject constructor(
} catch (e: Exception) {
Timber.e("웹 공유 실패: ${e.message}")
}
-
}
}
}
diff --git a/core/firebase/src/main/java/com/terning/core/firebase/messageservice/TerningMessagingService.kt b/core/firebase/src/main/java/com/terning/core/firebase/messageservice/TerningMessagingService.kt
index 5996f7fc7..8c9a7493c 100644
--- a/core/firebase/src/main/java/com/terning/core/firebase/messageservice/TerningMessagingService.kt
+++ b/core/firebase/src/main/java/com/terning/core/firebase/messageservice/TerningMessagingService.kt
@@ -16,9 +16,8 @@ import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.terning.core.analytics.AmplitudeTracker
import com.terning.core.analytics.EventType
-import com.terning.core.designsystem.type.NotificationRedirect
+import com.terning.core.designsystem.type.DeeplinkType
import com.terning.core.designsystem.util.DeeplinkDefaults
-import com.terning.core.designsystem.util.DeeplinkDefaults.REDIRECT
import com.terning.core.firebase.R
import com.terning.domain.user.repository.UserRepository
import com.terning.navigator.NavigatorProvider
@@ -162,10 +161,10 @@ class TerningMessagingService : FirebaseMessagingService() {
}
private fun buildDeeplink(type: String, isForeground: Boolean): String {
- val base = NotificationRedirect.from(type) ?: return ""
+ val base = DeeplinkType.from(type) ?: return ""
- return if (isForeground) DeeplinkDefaults.build(base.path)
- else DeeplinkDefaults.build("splash?$REDIRECT=${base.path}")
+ return if (isForeground) DeeplinkDefaults.build(host = base.path)
+ else DeeplinkDefaults.build(host = BACKGROUND_HOST, redirect = base.path)
}
companion object {
@@ -174,6 +173,7 @@ class TerningMessagingService : FirebaseMessagingService() {
private const val BODY: String = "body"
private const val TYPE: String = "type"
private const val IMAGE_URL: String = "imageUrl"
+ private const val BACKGROUND_HOST: String = "splash"
const val FROM_NOTIFICATION: String = "fromNotification"
}
}
diff --git a/feature/home/src/main/java/com/terning/feature/home/HomeRoute.kt b/feature/home/src/main/java/com/terning/feature/home/HomeRoute.kt
index e1a3c0fb5..0e9afed13 100644
--- a/feature/home/src/main/java/com/terning/feature/home/HomeRoute.kt
+++ b/feature/home/src/main/java/com/terning/feature/home/HomeRoute.kt
@@ -22,6 +22,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
@@ -81,6 +82,7 @@ private const val ZERO_TOTAL_COUNT = 0
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun HomeRoute(
+ internId: String?,
paddingValues: PaddingValues,
viewModel: HomeViewModel = hiltViewModel(),
navigateToCalendar: () -> Unit,
@@ -103,6 +105,15 @@ fun HomeRoute(
}
}
+ var hasHandledInternDeeplink by rememberSaveable { mutableStateOf(false) }
+
+ LaunchedEffect(internId, hasHandledInternDeeplink) {
+ if (internId != null && !hasHandledInternDeeplink) {
+ navigateToIntern(internId.toLong())
+ hasHandledInternDeeplink = true
+ }
+ }
+
LaunchedEffect(key1 = true) {
viewModel.getProfile()
viewModel.getFilteringInfo()
diff --git a/feature/home/src/main/java/com/terning/feature/home/navigation/HometNavigation.kt b/feature/home/src/main/java/com/terning/feature/home/navigation/HomeNavigation.kt
similarity index 75%
rename from feature/home/src/main/java/com/terning/feature/home/navigation/HometNavigation.kt
rename to feature/home/src/main/java/com/terning/feature/home/navigation/HomeNavigation.kt
index 3108a889e..fb47438c0 100644
--- a/feature/home/src/main/java/com/terning/feature/home/navigation/HometNavigation.kt
+++ b/feature/home/src/main/java/com/terning/feature/home/navigation/HomeNavigation.kt
@@ -8,14 +8,19 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink
+import androidx.navigation.toRoute
import com.terning.core.designsystem.util.DeeplinkDefaults
import com.terning.core.navigation.MainTabRoute
import com.terning.feature.home.HomeRoute
+import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-fun NavController.navigateHome(navOptions: NavOptions? = null) {
+fun NavController.navigateHome(
+ internId: String?,
+ navOptions: NavOptions? = null
+) {
navigate(
- route = Home,
+ route = Home(internId),
navOptions = navOptions
)
}
@@ -33,7 +38,9 @@ fun NavGraphBuilder.homeNavGraph(
)
)
) {
+ val args = it.toRoute()
HomeRoute(
+ internId = args.internId,
paddingValues = paddingValues,
navigateToCalendar = navigateToCalendar,
navigateToIntern = navigateToIntern
@@ -42,4 +49,7 @@ fun NavGraphBuilder.homeNavGraph(
}
@Serializable
-data object Home : MainTabRoute
\ No newline at end of file
+data class Home(
+ @SerialName("internId")
+ val internId: String? = null
+) : MainTabRoute
diff --git a/feature/intern/src/main/java/com/terning/feature/intern/InternRoute.kt b/feature/intern/src/main/java/com/terning/feature/intern/InternRoute.kt
index 7f52a79cf..af2bd8564 100644
--- a/feature/intern/src/main/java/com/terning/feature/intern/InternRoute.kt
+++ b/feature/intern/src/main/java/com/terning/feature/intern/InternRoute.kt
@@ -85,7 +85,8 @@ fun InternRoute(
navController = navController,
onClickShareButton = {
viewModel.onKakaoShareClicked(
- (internState.loadState as UiState.Success).data
+ (internState.loadState as UiState.Success).data,
+ announcementId.toString()
)
},
onDismissCancelDialog = {
diff --git a/feature/intern/src/main/java/com/terning/feature/intern/InternViewModel.kt b/feature/intern/src/main/java/com/terning/feature/intern/InternViewModel.kt
index 05dbd5df8..cfd954b3e 100644
--- a/feature/intern/src/main/java/com/terning/feature/intern/InternViewModel.kt
+++ b/feature/intern/src/main/java/com/terning/feature/intern/InternViewModel.kt
@@ -19,7 +19,7 @@ import javax.inject.Inject
@HiltViewModel
class InternViewModel @Inject constructor(
private val internRepository: InternRepository,
- private val kakaoUtil: KakaoUtil
+ private val kakaoUtil: KakaoUtil,
) : ViewModel() {
private val _internUiState = MutableStateFlow(InternUiState())
@@ -68,7 +68,8 @@ class InternViewModel @Inject constructor(
}
fun onKakaoShareClicked(
- internInfo: InternInfo
+ internInfo: InternInfo,
+ announcementId: String,
) {
val templateArgs = mapOf(
"COMPANY_IMG" to internInfo.companyImage,
@@ -76,8 +77,15 @@ class InternViewModel @Inject constructor(
"DEADLINE" to internInfo.deadline,
"START_DATE" to internInfo.startYearMonth,
"PERIOD" to internInfo.workingPeriod,
- "REGI_WEB_DOMAIN" to internInfo.url
- )
+ "A_E" to "kakaolink",
+ "A_E_D" to "intern",
+ "I_E" to "kakaolink",
+ "I_E_D" to "jobDetail",
+ "redirect" to "intern",
+ "internId" to announcementId,
+ "action" to "jobDetail",
+ "JOB_ID" to announcementId
+ )
kakaoUtil.shareToKakaoTalk(templateArgs)
}
}
diff --git a/feature/intern/src/main/java/com/terning/feature/intern/InternViewSideEffect.kt b/feature/intern/src/main/java/com/terning/feature/intern/InternViewSideEffect.kt
deleted file mode 100644
index 9954265af..000000000
--- a/feature/intern/src/main/java/com/terning/feature/intern/InternViewSideEffect.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-import androidx.annotation.StringRes
-
-sealed class InternViewSideEffect {
- data class Toast(@StringRes val message: Int) :
- InternViewSideEffect()
-}
\ No newline at end of file
diff --git a/feature/main/build.gradle.kts b/feature/main/build.gradle.kts
index 79698c6ef..cd074e5cb 100644
--- a/feature/main/build.gradle.kts
+++ b/feature/main/build.gradle.kts
@@ -1,11 +1,28 @@
import com.terning.build_logic.extension.setNamespace
+import java.util.Properties
plugins {
alias(libs.plugins.terning.feature)
}
+val properties = Properties().apply {
+ load(rootProject.file("local.properties").inputStream())
+}
+
android {
+ buildFeatures {
+ buildConfig = true
+ }
+
setNamespace("feature.main")
+
+ defaultConfig {
+ buildConfigField(
+ "String",
+ "NATIVE_APP_KEY",
+ properties.getProperty("native.app.key"),
+ )
+ }
}
dependencies {
diff --git a/feature/main/src/main/AndroidManifest.xml b/feature/main/src/main/AndroidManifest.xml
index acad7f973..7088005cb 100644
--- a/feature/main/src/main/AndroidManifest.xml
+++ b/feature/main/src/main/AndroidManifest.xml
@@ -24,6 +24,18 @@
+
+
+
+
+
+
+
+
+
+
{
+ private fun handleDeeplink(intent: Intent?): Triple {
val uri = intent?.data
val uriString = uri?.toString()
- if (uriString.isNullOrEmpty()) return null to null
+ if (uriString.isNullOrEmpty()) return Triple(null, null, null)
val host = uri.host
val redirect = uri.getQueryParameter(REDIRECT)
+ val internId = uri.getQueryParameter(INTERN_ID)
if (!intent.getBooleanExtra(ALREADY_TRACKED, false)
&& intent.getBooleanExtra(FROM_NOTIFICATION, false)
@@ -64,7 +68,7 @@ class MainActivity : ComponentActivity() {
intent.putExtra(ALREADY_TRACKED, true)
- return host to redirect
+ return Triple(host, redirect, internId)
}
companion object {
@@ -74,4 +78,4 @@ class MainActivity : ComponentActivity() {
context: Context,
) = Intent(context, MainActivity::class.java)
}
-}
\ No newline at end of file
+}
diff --git a/feature/main/src/main/java/com/terning/feature/main/MainNavigator.kt b/feature/main/src/main/java/com/terning/feature/main/MainNavigator.kt
index 9fd4f965f..ded0c4e9e 100644
--- a/feature/main/src/main/java/com/terning/feature/main/MainNavigator.kt
+++ b/feature/main/src/main/java/com/terning/feature/main/MainNavigator.kt
@@ -8,7 +8,7 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navOptions
-import com.terning.core.designsystem.type.NotificationRedirect
+import com.terning.core.designsystem.type.DeeplinkType
import com.terning.feature.calendar.calendar.navigation.Calendar
import com.terning.feature.calendar.calendar.navigation.navigateCalendar
import com.terning.feature.home.navigation.Home
@@ -26,13 +26,18 @@ class MainNavigator(
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination
- fun getStartDestination(redirect: String?, host: String?) =
- when (NotificationRedirect.from(host)) {
- NotificationRedirect.SEARCH -> Search
- NotificationRedirect.HOME -> Home
- NotificationRedirect.CALENDAR -> Calendar
- else -> Splash(redirect)
- }
+ fun getStartDestination(
+ host: String?,
+ redirect: String?,
+ internId: String?
+ ) = when (DeeplinkType.from(host)) {
+ DeeplinkType.SEARCH -> Search
+ DeeplinkType.HOME -> Home(internId = null)
+ DeeplinkType.CALENDAR -> Calendar
+ DeeplinkType.KAKAOLINK -> Splash(redirect = redirect, internId = internId)
+
+ else -> Splash(redirect = redirect)
+ }
val currentTab: MainTab?
@Composable get() = MainTab.find { tab ->
@@ -52,7 +57,7 @@ class MainNavigator(
}
when (tab) {
- MainTab.HOME -> navController.navigateHome(navOptions)
+ MainTab.HOME -> navController.navigateHome(navOptions = navOptions, internId = null)
MainTab.CALENDAR -> navController.navigateCalendar(navOptions)
MainTab.SEARCH -> navController.navigateSearch(navOptions)
MainTab.MY_PAGE -> navController.navigateMyPage(navOptions)
diff --git a/feature/main/src/main/java/com/terning/feature/main/MainScreen.kt b/feature/main/src/main/java/com/terning/feature/main/MainScreen.kt
index 2dbbb7f53..45074d91f 100644
--- a/feature/main/src/main/java/com/terning/feature/main/MainScreen.kt
+++ b/feature/main/src/main/java/com/terning/feature/main/MainScreen.kt
@@ -65,6 +65,7 @@ import kotlinx.coroutines.launch
fun MainScreen(
host: String?,
redirect: String?,
+ internId: String?,
navigator: MainNavigator = rememberMainNavigator(),
) {
val context = LocalContext.current
@@ -90,7 +91,7 @@ fun MainScreen(
val amplitudeTracker = LocalTracker.current
val splashNavOptions = NavOptions.Builder().setPopUpTo(
- route = Splash(redirect),
+ route = Splash(redirect = redirect, internId = internId),
inclusive = true
).build()
@@ -145,11 +146,18 @@ fun MainScreen(
ExitTransition.None
},
navController = navigator.navController,
- startDestination = navigator.getStartDestination(redirect = redirect, host = host)
+ startDestination = navigator.getStartDestination(
+ host = host,
+ redirect = redirect,
+ internId = internId
+ )
) {
splashNavGraph(
- navigateHome = {
- navigator.navController.navigateHome(navOptions = splashNavOptions)
+ navigateHome = { internId ->
+ navigator.navController.navigateHome(
+ navOptions = splashNavOptions,
+ internId = internId
+ )
},
navigateSignIn = {
navigator.navController.navigateSignIn(navOptions = splashNavOptions)
@@ -188,7 +196,10 @@ fun MainScreen(
inclusive = true
}
}
- navigator.navController.navigateHome(navOptions)
+ navigator.navController.navigateHome(
+ navOptions = navOptions,
+ internId = null
+ )
},
navigateSignUp = { authId ->
val navOptions = navOptions {
@@ -225,7 +236,10 @@ fun MainScreen(
inclusive = true
}
}
- navigator.navController.navigateHome(navOptions)
+ navigator.navController.navigateHome(
+ navOptions = navOptions,
+ internId = null
+ )
}
)
startHomeNavGraph(
@@ -235,7 +249,10 @@ fun MainScreen(
inclusive = true
}
}
- navigator.navController.navigateHome(navOptions)
+ navigator.navController.navigateHome(
+ navOptions = navOptions,
+ internId = null
+ )
}
)
filteringOneNavGraph(navHostController = navigator.navController)
diff --git a/feature/main/src/main/java/com/terning/feature/main/MainTab.kt b/feature/main/src/main/java/com/terning/feature/main/MainTab.kt
index 5d0868749..44048defd 100644
--- a/feature/main/src/main/java/com/terning/feature/main/MainTab.kt
+++ b/feature/main/src/main/java/com/terning/feature/main/MainTab.kt
@@ -18,7 +18,7 @@ enum class MainTab(
HOME(
icon = R.drawable.ic_nav_home,
contentDescription = R.string.bottom_nav_home,
- route = Home
+ route = Home(null)
),
CALENDAR(
icon = R.drawable.ic_nav_calendar,
diff --git a/feature/splash/src/main/java/com/terning/feature/splash/SplashRoute.kt b/feature/splash/src/main/java/com/terning/feature/splash/SplashRoute.kt
index 49a5fbbc0..ba4458e4f 100644
--- a/feature/splash/src/main/java/com/terning/feature/splash/SplashRoute.kt
+++ b/feature/splash/src/main/java/com/terning/feature/splash/SplashRoute.kt
@@ -28,7 +28,7 @@ import com.terning.core.designsystem.extension.launchPlayStore
import com.terning.core.designsystem.theme.TerningMain
import com.terning.core.designsystem.theme.TerningPointTheme
import com.terning.core.designsystem.theme.White
-import com.terning.core.designsystem.type.NotificationRedirect
+import com.terning.core.designsystem.type.DeeplinkType
import com.terning.domain.update.entity.UpdateState
import com.terning.feature.splash.component.TerningMajorUpdateDialog
import com.terning.feature.splash.component.TerningPatchUpdateDialog
@@ -37,7 +37,8 @@ import kotlinx.coroutines.launch
@Composable
internal fun SplashRoute(
redirect: String?,
- navigateToHome: () -> Unit,
+ internId: String?,
+ navigateToHome: (internId: String?) -> Unit,
navigateToSignIn: () -> Unit,
navigateToCalendar: () -> Unit,
navigateToSearch: () -> Unit,
@@ -73,6 +74,7 @@ internal fun SplashRoute(
}
}
}
+
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
@@ -85,15 +87,13 @@ internal fun SplashRoute(
when (sideEffect) {
is SplashSideEffect.HasAccessToken -> {
if (sideEffect.hasAccessToken) {
- if (redirect.isNullOrBlank()) {
- navigateToHome()
- } else {
- when (NotificationRedirect.from(redirect)) {
- NotificationRedirect.CALENDAR -> navigateToCalendar()
- NotificationRedirect.HOME -> navigateToHome()
- NotificationRedirect.SEARCH -> navigateToSearch()
- else -> navigateToHome()
- }
+ when (DeeplinkType.from(redirect)) {
+ DeeplinkType.CALENDAR -> navigateToCalendar()
+ DeeplinkType.HOME -> navigateToHome(null)
+ DeeplinkType.SEARCH -> navigateToSearch()
+ DeeplinkType.INTERN -> navigateToHome(internId.orEmpty())
+
+ else -> navigateToHome(null)
}
} else {
navigateToSignIn()
diff --git a/feature/splash/src/main/java/com/terning/feature/splash/navigation/SplashNavigation.kt b/feature/splash/src/main/java/com/terning/feature/splash/navigation/SplashNavigation.kt
index 301103528..1f683533b 100644
--- a/feature/splash/src/main/java/com/terning/feature/splash/navigation/SplashNavigation.kt
+++ b/feature/splash/src/main/java/com/terning/feature/splash/navigation/SplashNavigation.kt
@@ -11,10 +11,10 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
fun NavGraphBuilder.splashNavGraph(
- navigateHome: () -> Unit,
+ navigateHome: (internId: String?) -> Unit,
navigateSignIn: () -> Unit,
navigateSearch: () -> Unit,
- navigateCalendar: () -> Unit
+ navigateCalendar: () -> Unit,
) {
composable(
deepLinks = listOf(
@@ -26,6 +26,7 @@ fun NavGraphBuilder.splashNavGraph(
val args = it.toRoute()
SplashRoute(
redirect = args.redirect,
+ internId = args.internId,
navigateToHome = navigateHome,
navigateToSignIn = navigateSignIn,
navigateToSearch = navigateSearch,
@@ -37,5 +38,7 @@ fun NavGraphBuilder.splashNavGraph(
@Serializable
data class Splash(
@SerialName("redirect")
- val redirect: String?
-) : Route
\ No newline at end of file
+ val redirect: String? = null,
+ @SerialName("internId")
+ val internId: String? = null
+) : Route