fix(deeplink): 딥링크 포그라운드 라우팅을 정비한다
This commit is contained in:
@@ -85,6 +85,7 @@ object Constants {
|
|||||||
const val LIVE_SERVICE_NOTIFICATION_ID: Int = 2
|
const val LIVE_SERVICE_NOTIFICATION_ID: Int = 2
|
||||||
const val ACTION_AUDIO_CONTENT_RECEIVER = "soda_live_action_content_receiver"
|
const val ACTION_AUDIO_CONTENT_RECEIVER = "soda_live_action_content_receiver"
|
||||||
const val ACTION_MAIN_AUDIO_CONTENT_RECEIVER = "soda_live_action_main_content_receiver"
|
const val ACTION_MAIN_AUDIO_CONTENT_RECEIVER = "soda_live_action_main_content_receiver"
|
||||||
|
const val ACTION_LIVE_ROOM_DEEPLINK_CONFIRM = "soda_live_action_live_room_deeplink_confirm"
|
||||||
|
|
||||||
const val EXTRA_COMMUNITY_POST_ID = "community_post_id"
|
const val EXTRA_COMMUNITY_POST_ID = "community_post_id"
|
||||||
const val EXTRA_COMMUNITY_CREATOR_ID = "community_creator_id"
|
const val EXTRA_COMMUNITY_CREATOR_ID = "community_creator_id"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import kr.co.vividnext.sodalive.R
|
|||||||
import kr.co.vividnext.sodalive.app.SodaLiveApp
|
import kr.co.vividnext.sodalive.app.SodaLiveApp
|
||||||
import kr.co.vividnext.sodalive.common.Constants
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.splash.SplashActivity
|
import kr.co.vividnext.sodalive.main.DeepLinkActivity
|
||||||
|
|
||||||
class SodaFirebaseMessagingService : FirebaseMessagingService() {
|
class SodaFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
||||||
@@ -62,33 +62,22 @@ class SodaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
notificationManager.createNotificationChannel(channel)
|
notificationManager.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
val intent = Intent(this, SplashActivity::class.java)
|
val intent = Intent(this, DeepLinkActivity::class.java)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
|
||||||
val roomId = messageData["room_id"]
|
val deepLinkExtras = android.os.Bundle().apply {
|
||||||
if (roomId != null) {
|
messageData["room_id"]?.let { putString("room_id", it) }
|
||||||
intent.putExtra(Constants.EXTRA_ROOM_ID, roomId.toLong())
|
messageData["message_id"]?.let { putString("message_id", it) }
|
||||||
|
messageData["content_id"]?.let { putString("content_id", it) }
|
||||||
|
messageData["channel_id"]?.let { putString("channel_id", it) }
|
||||||
|
messageData["audition_id"]?.let { putString("audition_id", it) }
|
||||||
|
messageData["deep_link_value"]?.let { putString("deep_link_value", it) }
|
||||||
|
messageData["deep_link_sub5"]?.let { putString("deep_link_sub5", it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val messageId = messageData["message_id"]
|
if (!deepLinkExtras.isEmpty) {
|
||||||
if (messageId != null) {
|
intent.putExtra(Constants.EXTRA_DATA, deepLinkExtras)
|
||||||
intent.putExtra(Constants.EXTRA_MESSAGE_ID, messageId.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
val audioContentId = messageData["content_id"]
|
|
||||||
if (audioContentId != null) {
|
|
||||||
intent.putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
val channelId = messageData["channel_id"]
|
|
||||||
if (channelId != null) {
|
|
||||||
intent.putExtra(Constants.EXTRA_USER_ID, channelId.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
val auditionId = messageData["audition_id"]
|
|
||||||
if (auditionId != null) {
|
|
||||||
intent.putExtra(Constants.EXTRA_AUDITION_ID, auditionId.toLong())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val pendingIntent =
|
val pendingIntent =
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import android.content.ClipData
|
|||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
@@ -18,6 +22,7 @@ import android.graphics.Path
|
|||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.CountDownTimer
|
import android.os.CountDownTimer
|
||||||
@@ -51,6 +56,7 @@ import androidx.core.graphics.withTranslation
|
|||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
@@ -109,6 +115,8 @@ import kr.co.vividnext.sodalive.live.room.update.LiveRoomInfoEditDialog
|
|||||||
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
|
||||||
import kr.co.vividnext.sodalive.live.roulette.RouletteSpinDialog
|
import kr.co.vividnext.sodalive.live.roulette.RouletteSpinDialog
|
||||||
import kr.co.vividnext.sodalive.live.roulette.config.RouletteConfigActivity
|
import kr.co.vividnext.sodalive.live.roulette.config.RouletteConfigActivity
|
||||||
|
import kr.co.vividnext.sodalive.main.DeepLinkActivity
|
||||||
|
import kr.co.vividnext.sodalive.main.MainActivity
|
||||||
import kr.co.vividnext.sodalive.report.ProfileReportDialog
|
import kr.co.vividnext.sodalive.report.ProfileReportDialog
|
||||||
import kr.co.vividnext.sodalive.report.ReportType
|
import kr.co.vividnext.sodalive.report.ReportType
|
||||||
import kr.co.vividnext.sodalive.report.UserReportDialog
|
import kr.co.vividnext.sodalive.report.UserReportDialog
|
||||||
@@ -116,6 +124,7 @@ import kr.co.vividnext.sodalive.settings.language.LanguageManager
|
|||||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
@@ -242,6 +251,22 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val deepLinkConfirmReceiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
val bundle = intent?.getBundleExtra(Constants.EXTRA_DATA) ?: return
|
||||||
|
val destinationPageName = resolveDestinationPageName(bundle)
|
||||||
|
|
||||||
|
showDeepLinkNavigationDialog(destinationPageName) {
|
||||||
|
val nextIntent = Intent(applicationContext, MainActivity::class.java).apply {
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
putExtra(Constants.EXTRA_DATA, bundle)
|
||||||
|
}
|
||||||
|
startActivity(nextIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// region lifecycle
|
// region lifecycle
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
initAgora()
|
initAgora()
|
||||||
@@ -265,6 +290,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
|
isForeground = true
|
||||||
|
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||||
|
deepLinkConfirmReceiver,
|
||||||
|
IntentFilter(Constants.ACTION_LIVE_ROOM_DEEPLINK_CONFIRM)
|
||||||
|
)
|
||||||
|
|
||||||
if (this::layoutManager.isInitialized) {
|
if (this::layoutManager.isInitialized) {
|
||||||
layoutManager.scrollToPosition(chatAdapter.itemCount - 1)
|
layoutManager.scrollToPosition(chatAdapter.itemCount - 1)
|
||||||
@@ -284,6 +314,12 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(deepLinkConfirmReceiver)
|
||||||
|
isForeground = false
|
||||||
|
super.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
cropper.cleanup()
|
cropper.cleanup()
|
||||||
hideKeyboard {
|
hideKeyboard {
|
||||||
@@ -297,6 +333,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
countDownTimer.cancel()
|
countDownTimer.cancel()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region setupView
|
// region setupView
|
||||||
@@ -1177,7 +1214,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
val clickableSpan = object : ClickableSpan() {
|
val clickableSpan = object : ClickableSpan() {
|
||||||
override fun onClick(widget: View) {
|
override fun onClick(widget: View) {
|
||||||
val url = spannable.subSequence(start, end).toString()
|
val url = spannable.subSequence(start, end).toString()
|
||||||
startActivity(Intent(Intent.ACTION_VIEW, url.toUri()))
|
handleNoticeUrlClick(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spannable.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
spannable.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
@@ -1187,6 +1224,135 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
textView.movementMethod = LinkMovementMethod.getInstance()
|
textView.movementMethod = LinkMovementMethod.getInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleNoticeUrlClick(url: String) {
|
||||||
|
val viewIntent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||||
|
if (isInAppDeepLinkIntent(viewIntent)) {
|
||||||
|
val deepLinkExtras = buildDeepLinkExtrasFromUri(viewIntent.data)
|
||||||
|
val destinationPageName = resolveDestinationPageName(deepLinkExtras)
|
||||||
|
|
||||||
|
showDeepLinkNavigationDialog(destinationPageName) {
|
||||||
|
startActivity(viewIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivity(viewIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isInAppDeepLinkIntent(intent: Intent): Boolean {
|
||||||
|
val handlers = queryIntentActivitiesCompat(intent)
|
||||||
|
return handlers.any { resolveInfo ->
|
||||||
|
resolveInfo.activityInfo.packageName == packageName &&
|
||||||
|
resolveInfo.activityInfo.name == DeepLinkActivity::class.java.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
private fun queryIntentActivitiesCompat(intent: Intent): List<ResolveInfo> {
|
||||||
|
val flags = PackageManager.MATCH_DEFAULT_ONLY
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
packageManager.queryIntentActivities(
|
||||||
|
intent,
|
||||||
|
PackageManager.ResolveInfoFlags.of(flags.toLong())
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
packageManager.queryIntentActivities(intent, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDeepLinkExtrasFromUri(data: Uri?): Bundle {
|
||||||
|
val extras = Bundle()
|
||||||
|
if (data == null) {
|
||||||
|
return extras
|
||||||
|
}
|
||||||
|
|
||||||
|
fun putQuery(key: String) {
|
||||||
|
val value = data.getQueryParameter(key)
|
||||||
|
if (!value.isNullOrBlank()) {
|
||||||
|
extras.putString(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
putQuery("room_id")
|
||||||
|
putQuery("channel_id")
|
||||||
|
putQuery("message_id")
|
||||||
|
putQuery("audition_id")
|
||||||
|
putQuery("content_id")
|
||||||
|
putQuery("deep_link_value")
|
||||||
|
putQuery("deep_link_sub5")
|
||||||
|
|
||||||
|
val deepLinkValue = extras.getString("deep_link_value")
|
||||||
|
val deepLinkValueId = extras.getString("deep_link_sub5")
|
||||||
|
|
||||||
|
if (!deepLinkValue.isNullOrBlank() && !deepLinkValueId.isNullOrBlank()) {
|
||||||
|
when (deepLinkValue.lowercase(Locale.ROOT)) {
|
||||||
|
"live" -> if (!extras.containsKey("room_id")) {
|
||||||
|
extras.putString("room_id", deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
"channel" -> if (!extras.containsKey("channel_id")) {
|
||||||
|
extras.putString("channel_id", deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
"content" -> if (!extras.containsKey("content_id")) {
|
||||||
|
extras.putString("content_id", deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
"audition" -> if (!extras.containsKey("audition_id")) {
|
||||||
|
extras.putString("audition_id", deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return extras
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveDestinationPageName(bundle: Bundle): String {
|
||||||
|
val roomId = bundle.getString("room_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_ROOM_ID).takeIf { it > 0 }
|
||||||
|
val channelId = bundle.getString("channel_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_USER_ID).takeIf { it > 0 }
|
||||||
|
val messageId = bundle.getString("message_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_MESSAGE_ID).takeIf { it > 0 }
|
||||||
|
val contentId = bundle.getString("content_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_AUDIO_CONTENT_ID).takeIf { it > 0 }
|
||||||
|
|
||||||
|
return when {
|
||||||
|
roomId != null && roomId > 0 -> getString(R.string.screen_live_room_deeplink_target_live_room)
|
||||||
|
channelId != null && channelId > 0 -> getString(R.string.screen_live_room_deeplink_target_channel_profile)
|
||||||
|
contentId != null && contentId > 0 -> getString(R.string.screen_live_room_deeplink_target_content_detail)
|
||||||
|
messageId != null && messageId > 0 -> getString(R.string.screen_live_room_deeplink_target_message)
|
||||||
|
else -> {
|
||||||
|
when (bundle.getString("deep_link_value")?.lowercase(Locale.ROOT)) {
|
||||||
|
"live" -> getString(R.string.screen_live_room_deeplink_target_live_room)
|
||||||
|
"channel" -> getString(R.string.screen_live_room_deeplink_target_channel_profile)
|
||||||
|
"content" -> getString(R.string.screen_live_room_deeplink_target_content_detail)
|
||||||
|
"series" -> getString(R.string.screen_live_room_deeplink_target_series_detail)
|
||||||
|
"audition" -> getString(R.string.screen_live_room_deeplink_target_audition)
|
||||||
|
else -> getString(R.string.screen_live_room_deeplink_target_default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showDeepLinkNavigationDialog(destinationPageName: String, onConfirm: () -> Unit) {
|
||||||
|
SodaDialog(
|
||||||
|
activity = this,
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = getString(R.string.screen_live_room_deeplink_move_title),
|
||||||
|
desc = getString(R.string.screen_live_room_deeplink_move_message, destinationPageName),
|
||||||
|
confirmButtonTitle = getString(R.string.screen_live_room_yes),
|
||||||
|
confirmButtonClick = {
|
||||||
|
onConfirm()
|
||||||
|
},
|
||||||
|
cancelButtonTitle = getString(R.string.cancel),
|
||||||
|
cancelButtonClick = {}
|
||||||
|
).show(screenWidth)
|
||||||
|
}
|
||||||
|
|
||||||
private fun onClickQuit() {
|
private fun onClickQuit() {
|
||||||
hideKeyboard {
|
hideKeyboard {
|
||||||
if (viewModel.isEqualToHostId(SharedPreferenceManager.userId.toInt())) {
|
if (viewModel.isEqualToHostId(SharedPreferenceManager.userId.toInt())) {
|
||||||
@@ -3583,5 +3749,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val NO_CHATTING_TIME = 180L
|
private const val NO_CHATTING_TIME = 180L
|
||||||
|
var isForeground: Boolean = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package kr.co.vividnext.sodalive.main
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
|
import kr.co.vividnext.sodalive.app.SodaLiveApp
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
|
||||||
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentActivity
|
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentActivity
|
||||||
import kr.co.vividnext.sodalive.splash.SplashActivity
|
import kr.co.vividnext.sodalive.splash.SplashActivity
|
||||||
|
|
||||||
@@ -14,6 +16,8 @@ class DeepLinkActivity : AppCompatActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val data: Uri? = intent?.data
|
val data: Uri? = intent?.data
|
||||||
|
val deepLinkExtras = buildDeepLinkExtras(intent)
|
||||||
|
|
||||||
if (data != null && data.scheme != null) {
|
if (data != null && data.scheme != null) {
|
||||||
val host = data.host
|
val host = data.host
|
||||||
val path = data.path
|
val path = data.path
|
||||||
@@ -30,15 +34,136 @@ class DeepLinkActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 그 외 일반 딥링크는 기존처럼 Splash로 위임
|
if (SodaLiveApp.isAppInForeground && LiveRoomActivity.isForeground && deepLinkExtras != null) {
|
||||||
startActivity(
|
LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(
|
||||||
Intent(applicationContext, SplashActivity::class.java).apply {
|
Intent(Constants.ACTION_LIVE_ROOM_DEEPLINK_CONFIRM).apply {
|
||||||
setData(intent.data)
|
putExtra(Constants.EXTRA_DATA, deepLinkExtras)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
|
||||||
finish()
|
finish()
|
||||||
}, 1000)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SodaLiveApp.isAppInForeground) {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, MainActivity::class.java).apply {
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
deepLinkExtras?.let { putExtra(Constants.EXTRA_DATA, it) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, SplashActivity::class.java).apply {
|
||||||
|
setData(data)
|
||||||
|
deepLinkExtras?.let { putExtra(Constants.EXTRA_DATA, it) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDeepLinkExtras(intent: Intent): Bundle? {
|
||||||
|
val extras = Bundle()
|
||||||
|
|
||||||
|
val data = intent.data
|
||||||
|
|
||||||
|
if (data != null) {
|
||||||
|
fun putQuery(key: String) {
|
||||||
|
val value = data.getQueryParameter(key)
|
||||||
|
if (!value.isNullOrBlank()) {
|
||||||
|
extras.putString(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
putQuery("room_id")
|
||||||
|
putQuery("channel_id")
|
||||||
|
putQuery("message_id")
|
||||||
|
putQuery("audition_id")
|
||||||
|
putQuery("content_id")
|
||||||
|
putQuery("deep_link_value")
|
||||||
|
putQuery("deep_link_sub5")
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.getBundleExtra(Constants.EXTRA_DATA)?.let { source ->
|
||||||
|
fun copyString(key: String) {
|
||||||
|
val value = source.getString(key)
|
||||||
|
if (!value.isNullOrBlank()) {
|
||||||
|
extras.putString(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
copyString("room_id")
|
||||||
|
copyString("channel_id")
|
||||||
|
copyString("message_id")
|
||||||
|
copyString("audition_id")
|
||||||
|
copyString("content_id")
|
||||||
|
copyString("deep_link_value")
|
||||||
|
copyString("deep_link_sub5")
|
||||||
|
|
||||||
|
source.getLong(Constants.EXTRA_ROOM_ID).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("room_id", it.toString())
|
||||||
|
}
|
||||||
|
source.getLong(Constants.EXTRA_USER_ID).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("channel_id", it.toString())
|
||||||
|
}
|
||||||
|
source.getLong(Constants.EXTRA_MESSAGE_ID).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("message_id", it.toString())
|
||||||
|
}
|
||||||
|
source.getLong(Constants.EXTRA_AUDITION_ID).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("audition_id", it.toString())
|
||||||
|
}
|
||||||
|
source.getLong(Constants.EXTRA_AUDIO_CONTENT_ID).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("content_id", it.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.getLongExtra(Constants.EXTRA_ROOM_ID, 0).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("room_id", it.toString())
|
||||||
|
}
|
||||||
|
intent.getLongExtra(Constants.EXTRA_USER_ID, 0).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("channel_id", it.toString())
|
||||||
|
}
|
||||||
|
intent.getLongExtra(Constants.EXTRA_MESSAGE_ID, 0).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("message_id", it.toString())
|
||||||
|
}
|
||||||
|
intent.getLongExtra(Constants.EXTRA_AUDITION_ID, 0).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("audition_id", it.toString())
|
||||||
|
}
|
||||||
|
intent.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0).takeIf { it > 0 }?.let {
|
||||||
|
extras.putString("content_id", it.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
val deepLinkValue = extras.getString("deep_link_value")
|
||||||
|
val deepLinkValueId = extras.getString("deep_link_sub5")
|
||||||
|
|
||||||
|
if (!deepLinkValue.isNullOrBlank() && !deepLinkValueId.isNullOrBlank()) {
|
||||||
|
when (deepLinkValue.lowercase()) {
|
||||||
|
"live" -> if (!extras.containsKey("room_id")) {
|
||||||
|
extras.putString("room_id", deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
"channel" -> if (!extras.containsKey("channel_id")) {
|
||||||
|
extras.putString("channel_id", deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
"content" -> if (!extras.containsKey("content_id")) {
|
||||||
|
extras.putString("content_id", deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
"audition" -> if (!extras.containsKey("audition_id")) {
|
||||||
|
extras.putString("audition_id", deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (extras.isEmpty) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
extras
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
|
|||||||
import kr.co.vividnext.sodalive.settings.notification.NotificationSettingsDialog
|
import kr.co.vividnext.sodalive.settings.notification.NotificationSettingsDialog
|
||||||
import kr.co.vividnext.sodalive.user.login.LoginActivity
|
import kr.co.vividnext.sodalive.user.login.LoginActivity
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::inflate) {
|
class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::inflate) {
|
||||||
@@ -267,26 +268,45 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun executeDeeplink(intent: Intent) {
|
private fun executeDeeplink(intent: Intent) {
|
||||||
|
val isLoggedIn =
|
||||||
|
SharedPreferenceManager.token.isNotBlank() && SharedPreferenceManager.token.length > 10
|
||||||
|
if (!isLoggedIn) {
|
||||||
|
executeOneLink()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA)
|
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA)
|
||||||
if (
|
val isHandledFromBundle = if (bundle != null) {
|
||||||
SharedPreferenceManager.token.isNotBlank() &&
|
|
||||||
SharedPreferenceManager.token.length > 10 &&
|
|
||||||
bundle != null
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
val roomId = bundle.getString("room_id")?.toLong()
|
executeBundleDeeplink(bundle)
|
||||||
?: bundle.getLong(Constants.EXTRA_ROOM_ID)
|
} catch (_: IllegalStateException) {
|
||||||
val channelId = bundle.getString("channel_id")?.toLong()
|
false
|
||||||
?: bundle.getLong(Constants.EXTRA_USER_ID)
|
}
|
||||||
val messageId = bundle.getString("message_id")?.toLong()
|
} else {
|
||||||
?: bundle.getLong(Constants.EXTRA_MESSAGE_ID)
|
false
|
||||||
val auditionId = bundle.getString("audition_id")?.toLong()
|
}
|
||||||
?: bundle.getLong(Constants.EXTRA_AUDITION_ID)
|
|
||||||
val contentId = bundle.getString("content_id")?.toLong()
|
if (isHandledFromBundle) {
|
||||||
?: bundle.getLong(Constants.EXTRA_AUDIO_CONTENT_ID)
|
clearDeferredDeepLink()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
executeOneLink()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeBundleDeeplink(bundle: Bundle): Boolean {
|
||||||
|
val roomId = bundle.getString("room_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_ROOM_ID).takeIf { it > 0 }
|
||||||
|
val channelId = bundle.getString("channel_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_USER_ID).takeIf { it > 0 }
|
||||||
|
val messageId = bundle.getString("message_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_MESSAGE_ID).takeIf { it > 0 }
|
||||||
|
val contentId = bundle.getString("content_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_AUDIO_CONTENT_ID).takeIf { it > 0 }
|
||||||
val isLiveReservation = bundle.getBoolean(Constants.EXTRA_LIVE_RESERVATION_RESPONSE)
|
val isLiveReservation = bundle.getBoolean(Constants.EXTRA_LIVE_RESERVATION_RESPONSE)
|
||||||
|
|
||||||
if (roomId > 0) {
|
when {
|
||||||
|
roomId != null && roomId > 0 -> {
|
||||||
viewModel.clickTab(MainViewModel.CurrentTab.LIVE)
|
viewModel.clickTab(MainViewModel.CurrentTab.LIVE)
|
||||||
|
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
@@ -296,26 +316,40 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||||||
liveFragment.enterLiveRoom(roomId)
|
liveFragment.enterLiveRoom(roomId)
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
} else if (channelId > 0) {
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
channelId != null && channelId > 0 -> {
|
||||||
val nextIntent = Intent(applicationContext, UserProfileActivity::class.java)
|
val nextIntent = Intent(applicationContext, UserProfileActivity::class.java)
|
||||||
nextIntent.putExtra(Constants.EXTRA_USER_ID, channelId)
|
nextIntent.putExtra(Constants.EXTRA_USER_ID, channelId)
|
||||||
startActivity(nextIntent)
|
startActivity(nextIntent)
|
||||||
} else if (contentId > 0) {
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
contentId != null && contentId > 0 -> {
|
||||||
val nextIntent = Intent(
|
val nextIntent = Intent(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
AudioContentDetailActivity::class.java
|
AudioContentDetailActivity::class.java
|
||||||
)
|
)
|
||||||
nextIntent.putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId)
|
nextIntent.putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId)
|
||||||
startActivity(nextIntent)
|
startActivity(nextIntent)
|
||||||
} else if (messageId > 0) {
|
return true
|
||||||
startActivity(Intent(applicationContext, MessageActivity::class.java))
|
|
||||||
} else if (auditionId > 0) {
|
|
||||||
}
|
}
|
||||||
} catch (_: IllegalStateException) {
|
|
||||||
|
messageId != null && messageId > 0 -> {
|
||||||
|
startActivity(Intent(applicationContext, MessageActivity::class.java))
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
executeOneLink()
|
val deepLinkValue = bundle.getString("deep_link_value")
|
||||||
|
val deepLinkValueId = bundle.getString("deep_link_sub5")?.toLongOrNull()
|
||||||
|
|
||||||
|
if (!deepLinkValue.isNullOrBlank() && deepLinkValueId != null && deepLinkValueId > 0) {
|
||||||
|
return routeByDeepLinkValue(deepLinkValue = deepLinkValue, deepLinkValueId = deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeOneLink() {
|
private fun executeOneLink() {
|
||||||
@@ -323,13 +357,21 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||||||
val deepLinkValueId = SharedPreferenceManager.marketingLinkValueId
|
val deepLinkValueId = SharedPreferenceManager.marketingLinkValueId
|
||||||
|
|
||||||
if (deepLinkValue.isNotBlank() && deepLinkValueId > 0) {
|
if (deepLinkValue.isNotBlank() && deepLinkValueId > 0) {
|
||||||
when (deepLinkValue) {
|
routeByDeepLinkValue(deepLinkValue = deepLinkValue, deepLinkValueId = deepLinkValueId)
|
||||||
|
}
|
||||||
|
|
||||||
|
clearDeferredDeepLink()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun routeByDeepLinkValue(deepLinkValue: String, deepLinkValueId: Long): Boolean {
|
||||||
|
return when (deepLinkValue.lowercase(Locale.ROOT)) {
|
||||||
"series" -> {
|
"series" -> {
|
||||||
startActivity(
|
startActivity(
|
||||||
Intent(applicationContext, SeriesDetailActivity::class.java).apply {
|
Intent(applicationContext, SeriesDetailActivity::class.java).apply {
|
||||||
putExtra(Constants.EXTRA_SERIES_ID, deepLinkValueId)
|
putExtra(Constants.EXTRA_SERIES_ID, deepLinkValueId)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
"content" -> {
|
"content" -> {
|
||||||
@@ -341,6 +383,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, deepLinkValueId)
|
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, deepLinkValueId)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
"channel" -> {
|
"channel" -> {
|
||||||
@@ -349,6 +392,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||||||
putExtra(Constants.EXTRA_USER_ID, deepLinkValueId)
|
putExtra(Constants.EXTRA_USER_ID, deepLinkValueId)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
"live" -> {
|
"live" -> {
|
||||||
@@ -357,15 +401,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
liveFragment.enterLiveRoom(deepLinkValueId)
|
liveFragment.enterLiveRoom(deepLinkValueId)
|
||||||
}, 500)
|
}, 500)
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {}
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearDeferredDeepLink()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearDeferredDeepLink() {
|
private fun clearDeferredDeepLink() {
|
||||||
SharedPreferenceManager.marketingUtmSource = ""
|
SharedPreferenceManager.marketingUtmSource = ""
|
||||||
SharedPreferenceManager.marketingUtmMedium = ""
|
SharedPreferenceManager.marketingUtmMedium = ""
|
||||||
|
|||||||
@@ -429,6 +429,15 @@
|
|||||||
<string name="screen_live_room_end_message">End this live?\nChat history will not be saved and will disappear.\nParticipants will also be removed when the live ends.</string>
|
<string name="screen_live_room_end_message">End this live?\nChat history will not be saved and will disappear.\nParticipants will also be removed when the live ends.</string>
|
||||||
<string name="screen_live_room_exit_title">Leave live</string>
|
<string name="screen_live_room_exit_title">Leave live</string>
|
||||||
<string name="screen_live_room_exit_message">Leave this live room?</string>
|
<string name="screen_live_room_exit_message">Leave this live room?</string>
|
||||||
|
<string name="screen_live_room_deeplink_move_title">Open deep link</string>
|
||||||
|
<string name="screen_live_room_deeplink_move_message">Close this page and move to %1$s?</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_live_room">Live room page</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_channel_profile">Channel profile page</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_content_detail">Content detail page</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_message">Message page</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_series_detail">Series detail page</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_audition">Audition page</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_default">requested page</string>
|
||||||
<string name="screen_live_room_yes">Yes</string>
|
<string name="screen_live_room_yes">Yes</string>
|
||||||
<string name="screen_live_room_no">No</string>
|
<string name="screen_live_room_no">No</string>
|
||||||
<string name="screen_live_room_request_speaker">Speaker request sent.\nwait a moment.</string>
|
<string name="screen_live_room_request_speaker">Speaker request sent.\nwait a moment.</string>
|
||||||
|
|||||||
@@ -428,6 +428,15 @@
|
|||||||
<string name="screen_live_room_end_message">ライブを終了しますか?\n終了するとチャット内容は保存されず消えます。\nリスナーもライブ終了と共に\n強制退出となります。</string>
|
<string name="screen_live_room_end_message">ライブを終了しますか?\n終了するとチャット内容は保存されず消えます。\nリスナーもライブ終了と共に\n強制退出となります。</string>
|
||||||
<string name="screen_live_room_exit_title">ライブ退出</string>
|
<string name="screen_live_room_exit_title">ライブ退出</string>
|
||||||
<string name="screen_live_room_exit_message">ライブから退出しますか?</string>
|
<string name="screen_live_room_exit_message">ライブから退出しますか?</string>
|
||||||
|
<string name="screen_live_room_deeplink_move_title">ディープリンク移動</string>
|
||||||
|
<string name="screen_live_room_deeplink_move_message">現在のページを終了して%1$sへ移動しますか?</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_live_room">ライブルームページ</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_channel_profile">チャンネルプロフィールページ</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_content_detail">コンテンツ詳細ページ</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_message">メッセージページ</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_series_detail">シリーズ詳細ページ</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_audition">オーディションページ</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_default">リクエストされたページ</string>
|
||||||
<string name="screen_live_room_yes">はい</string>
|
<string name="screen_live_room_yes">はい</string>
|
||||||
<string name="screen_live_room_no">いいえ</string>
|
<string name="screen_live_room_no">いいえ</string>
|
||||||
<string name="screen_live_room_request_speaker">スピーカーリクエストを送りました。\n少々お待ちください。</string>
|
<string name="screen_live_room_request_speaker">スピーカーリクエストを送りました。\n少々お待ちください。</string>
|
||||||
|
|||||||
@@ -428,6 +428,15 @@
|
|||||||
<string name="screen_live_room_end_message">라이브를 종료하시겠습니까?\n라이브를 종료하면 대화내용은\n저장되지 않고 사라집니다.\n참여자들 또한 라이브가 종료되어\n강제퇴장 됩니다.</string>
|
<string name="screen_live_room_end_message">라이브를 종료하시겠습니까?\n라이브를 종료하면 대화내용은\n저장되지 않고 사라집니다.\n참여자들 또한 라이브가 종료되어\n강제퇴장 됩니다.</string>
|
||||||
<string name="screen_live_room_exit_title">라이브 나가기</string>
|
<string name="screen_live_room_exit_title">라이브 나가기</string>
|
||||||
<string name="screen_live_room_exit_message">라이브에서 나가시겠습니까?</string>
|
<string name="screen_live_room_exit_message">라이브에서 나가시겠습니까?</string>
|
||||||
|
<string name="screen_live_room_deeplink_move_title">딥링크 이동</string>
|
||||||
|
<string name="screen_live_room_deeplink_move_message">현재 페이지를 종료하고 %1$s로 이동하시겠습니까?</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_live_room">라이브룸 페이지</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_channel_profile">채널 프로필 페이지</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_content_detail">콘텐츠 상세 페이지</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_message">메시지 페이지</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_series_detail">시리즈 상세 페이지</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_audition">오디션 페이지</string>
|
||||||
|
<string name="screen_live_room_deeplink_target_default">요청한 페이지</string>
|
||||||
<string name="screen_live_room_yes">예</string>
|
<string name="screen_live_room_yes">예</string>
|
||||||
<string name="screen_live_room_no">아니오</string>
|
<string name="screen_live_room_no">아니오</string>
|
||||||
<string name="screen_live_room_request_speaker">스피커 요청을 보냈습니다.\n잠시만 기다려 주세요.</string>
|
<string name="screen_live_room_request_speaker">스피커 요청을 보냈습니다.\n잠시만 기다려 주세요.</string>
|
||||||
|
|||||||
87
docs/20260306_딥링크스플래시우회및라이브룸확인다이얼로그.md
Normal file
87
docs/20260306_딥링크스플래시우회및라이브룸확인다이얼로그.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# 딥링크 실행 시 Splash 우회 및 LiveRoom 이동 확인 다이얼로그 구현
|
||||||
|
|
||||||
|
- [x] 요구사항 정리 및 영향 범위 확정 (`DeepLinkActivity`, `MainActivity`, `LiveRoomActivity`, `AndroidManifest.xml`, 문자열 리소스)
|
||||||
|
- [x] 딥링크 진입/라우팅 및 기존 다이얼로그 패턴 전수 탐색 (내부 검색 + 백그라운드 에이전트 병렬 탐색)
|
||||||
|
- [x] 앱 실행 중 딥링크 진입 시 `SplashActivity`를 거치지 않고 `MainActivity`로 직접 라우팅하도록 구현
|
||||||
|
- [x] 딥링크 파라미터를 `MainActivity.executeDeeplink`에서 즉시 처리할 수 있도록 전달/파싱 보강
|
||||||
|
- [x] `LiveRoomActivity`에서 앱 딥링크 실행 시 "현재 페이지 종료 후 이동" 확인 다이얼로그 추가 (확인 시 이동+현재 화면 종료, 취소 시 유지)
|
||||||
|
- [x] 신규 다이얼로그 문구 다국어 문자열(`values`, `values-en`, `values-ja`) 추가
|
||||||
|
- [x] 푸시 메시지 클릭 진입도 딥링크와 동일 라우팅 규칙 적용 (실행 중 Splash 우회)
|
||||||
|
- [x] 정적 진단/테스트/빌드 실행 후 결과를 검증 기록에 누적
|
||||||
|
|
||||||
|
## 검증 기록
|
||||||
|
|
||||||
|
### 2026-03-06 14:54 (KST)
|
||||||
|
- 무엇/왜/어떻게: 구현 착수 전 요구사항을 작업 단위로 분해하고, 딥링크 진입 경로와 현재 라우팅 구조를 기준으로 변경 포인트를 계획 문서에 확정했다.
|
||||||
|
- 전수 탐색: `explore` 3건 + `librarian` 2건 병렬 실행, `grep`/`ast-grep` 수행, `rg`는 로컬 미설치(`command not found`) 확인.
|
||||||
|
- 실행 명령 및 결과:
|
||||||
|
- `rg -n --hidden --glob '!**/build/**' "..." app/src/main` -> `command not found`
|
||||||
|
- 나머지 구현 검증 명령은 구현 완료 후 본 문서에 누적 기록 예정
|
||||||
|
|
||||||
|
### 2026-03-06 15:08 (KST)
|
||||||
|
- 무엇/왜/어떻게: `DeepLinkActivity`에서 앱 foreground 시 `MainActivity`로 직접 전달하도록 분기하고, URL query(`deep_link_value`, `deep_link_sub5`)를 `Constants.EXTRA_DATA`로 매핑해 `MainActivity.executeDeeplink`에서 즉시 처리되게 보강했다. 또한 `LiveRoomActivity` 공지 URL 클릭 시 앱 딥링크인 경우 `LiveDialog` 확인 후 이동/종료하도록 처리했다.
|
||||||
|
- 수정 파일:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/main/DeepLinkActivity.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/main/MainActivity.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt`
|
||||||
|
- `app/src/main/res/values/strings.xml`
|
||||||
|
- `app/src/main/res/values-en/strings.xml`
|
||||||
|
- `app/src/main/res/values-ja/strings.xml`
|
||||||
|
- 실행 명령 및 결과:
|
||||||
|
- `lsp_diagnostics` (`DeepLinkActivity.kt`, `MainActivity.kt`, `LiveRoomActivity.kt`) -> `.kt` 확장자 LSP 서버 미구성으로 실행 불가
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug :app:ktlintCheck` -> `:app:ktlintMainSourceSetCheck FAILED` (기존 누적 ktlint 위반 다수 + 기존 파일 이슈 포함)
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug` -> `BUILD SUCCESSFUL`
|
||||||
|
|
||||||
|
### 2026-03-06 15:21 (KST)
|
||||||
|
- 무엇/왜/어떻게: 푸시 클릭 진입도 딥링크와 동일하게 처리하기 위해 `SodaFirebaseMessagingService`의 PendingIntent 타깃을 `DeepLinkActivity`로 통일하고, 푸시 payload를 `Constants.EXTRA_DATA` 번들(`room_id`, `channel_id`, `message_id`, `audition_id`, `content_id`)로 전달했다. 동시에 `DeepLinkActivity`에서 URI query + `EXTRA_DATA` + 레거시 long extras를 모두 병합 파싱하도록 보강해 warm 상태 Splash 우회 규칙을 푸시에도 적용했다.
|
||||||
|
- 수정 파일:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/fcm/SodaFirebaseMessagingService.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/main/DeepLinkActivity.kt`
|
||||||
|
- 실행 명령 및 결과:
|
||||||
|
- `lsp_diagnostics` (`SodaFirebaseMessagingService.kt`, `DeepLinkActivity.kt`) -> `.kt` 확장자 LSP 서버 미구성으로 실행 불가
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug` -> `BUILD SUCCESSFUL`
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug` (최종 수정 후 재실행) -> `BUILD SUCCESSFUL`
|
||||||
|
|
||||||
|
### 2026-03-06 15:29 (KST)
|
||||||
|
- 무엇/왜/어떻게: LiveRoom 화면 체류 중 외부 딥링크/푸시 탭 시 즉시 이동하지 않도록 `DeepLinkActivity`에서 `LiveRoomActivity.isForeground`를 확인해 확인 요청 브로드캐스트를 보내고 종료하도록 변경했다. `LiveRoomActivity`는 브로드캐스트 수신 시 `LiveDialog` 확인/취소를 표시하며, 확인 시 현재 화면을 종료하고 `MainActivity`로 딥링크 번들(`Constants.EXTRA_DATA`)을 전달해 목적지로 이동하고 취소 시 이동하지 않는다.
|
||||||
|
- 수정 파일:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/common/Constants.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/main/DeepLinkActivity.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt`
|
||||||
|
|
||||||
|
### 2026-03-06 15:34 (KST)
|
||||||
|
- 실행 명령 및 결과:
|
||||||
|
- `lsp_diagnostics` (`Constants.kt`, `DeepLinkActivity.kt`, `LiveRoomActivity.kt`) -> `.kt` 확장자 LSP 서버 미구성으로 실행 불가
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug` -> 1차 컴파일 실패(`LiveRoomActivity` companion object 중복)
|
||||||
|
- companion 중복 선언 정리 후 `./gradlew :app:testDebugUnitTest :app:assembleDebug` 재실행 -> `BUILD SUCCESSFUL`
|
||||||
|
|
||||||
|
### 2026-03-06 15:43 (KST)
|
||||||
|
- 무엇/왜/어떻게: LiveRoom 체류 상태에서 다이얼로그가 누락되는 문제를 수정하기 위해, 브로드캐스트 방식 대신 `DeepLinkActivity`에서 직접 확인 다이얼로그(`AlertDialog`)를 표시하도록 전환했다. 조건은 `SodaLiveApp.isAppInForeground && LiveRoomActivity.isForeground`이며, 확인 시 `MainActivity`로 `Constants.EXTRA_DATA`를 전달해 이동하고, 취소/백키/바깥영역 dismiss 시 `DeepLinkActivity`만 종료되어 이동하지 않는다. 또한 `LiveRoomActivity.isForeground` 판단을 `onStart/onStop` 기준으로 조정해 전환 순간에도 상태가 유지되도록 보강했다.
|
||||||
|
- 수정 파일:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/main/DeepLinkActivity.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/common/Constants.kt`
|
||||||
|
- 실행 명령 및 결과:
|
||||||
|
- `lsp_diagnostics` (`DeepLinkActivity.kt`, `LiveRoomActivity.kt`, `Constants.kt`) -> `.kt` 확장자 LSP 서버 미구성으로 실행 불가
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug` -> `BUILD SUCCESSFUL`
|
||||||
|
|
||||||
|
### 2026-03-06 15:50 (KST)
|
||||||
|
- 무엇/왜/어떻게: 사용자 피드백(검은 배경 노출) 반영으로 `AlertDialog` 경유를 제거하고, LiveRoom 화면에서 직접 `SodaDialog`가 뜨도록 플로우를 조정했다. `DeepLinkActivity`는 LiveRoom 활성 시 `Constants.ACTION_LIVE_ROOM_DEEPLINK_CONFIRM` 브로드캐스트만 전송하고 종료하며, `LiveRoomActivity`는 이를 수신해 `SodaDialog`를 표시한다. 확인 시 `MainActivity`로 이동+현재 화면 종료, 취소 시 이동하지 않는다.
|
||||||
|
- 수정 파일:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/common/Constants.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/main/DeepLinkActivity.kt`
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt`
|
||||||
|
- 실행 명령 및 결과:
|
||||||
|
- `lsp_diagnostics` (`DeepLinkActivity.kt`, `LiveRoomActivity.kt`, `Constants.kt`) -> `.kt` 확장자 LSP 서버 미구성으로 실행 불가
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug` -> `BUILD SUCCESSFUL`
|
||||||
|
|
||||||
|
### 2026-03-06 15:57 (KST)
|
||||||
|
- 무엇/왜/어떻게: LiveRoom 확인 다이얼로그 문구를 정적으로 `딥링크 목적지`라고 표시하던 방식에서, 실제 이동 대상 페이지명을 삽입하는 방식으로 변경했다. `LiveRoomActivity.resolveDestinationPageName`에서 `room_id/channel_id/content_id/message_id` 및 `deep_link_value`를 기반으로 목적지명을 결정하고, `SodaDialog` 설명에 `screen_live_room_deeplink_move_message(%1$s)` 포맷으로 주입한다. 예: 콘텐츠 등록 푸시 탭 시 `콘텐츠 상세 페이지`로 이동 문구 표시.
|
||||||
|
- 수정 파일:
|
||||||
|
- `app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt`
|
||||||
|
- `app/src/main/res/values/strings.xml`
|
||||||
|
- `app/src/main/res/values-en/strings.xml`
|
||||||
|
- `app/src/main/res/values-ja/strings.xml`
|
||||||
|
- 실행 명령 및 결과:
|
||||||
|
- `lsp_diagnostics` (`LiveRoomActivity.kt`, `DeepLinkActivity.kt`) -> `.kt` 확장자 LSP 서버 미구성으로 실행 불가
|
||||||
|
- `./gradlew :app:testDebugUnitTest :app:assembleDebug` -> `BUILD SUCCESSFUL`
|
||||||
Reference in New Issue
Block a user