From b2a7cd2f09cfc097b680bf49e5b3bdf1387d81b1 Mon Sep 17 00:00:00 2001 From: unam Date: Thu, 15 Feb 2024 22:02:34 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[FIX]=20#228=20interceptor=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20clear=20logic=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runnect/data/service/TokenAuthenticator.kt | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/app/src/main/java/com/runnect/runnect/data/service/TokenAuthenticator.kt b/app/src/main/java/com/runnect/runnect/data/service/TokenAuthenticator.kt index ee2b0c43d..843851b64 100644 --- a/app/src/main/java/com/runnect/runnect/data/service/TokenAuthenticator.kt +++ b/app/src/main/java/com/runnect/runnect/data/service/TokenAuthenticator.kt @@ -6,7 +6,6 @@ import android.os.Handler import android.os.Looper import android.widget.Toast import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory -import com.runnect.runnect.BuildConfig import com.runnect.runnect.R import com.runnect.runnect.application.ApplicationClass import com.runnect.runnect.application.PreferenceManager @@ -41,17 +40,6 @@ class TokenAuthenticator(val context: Context) : Authenticator { return null } - private fun clearToken() { - PreferenceManager.setString( - context, - TOKEN_KEY_ACCESS, "none" - ) - PreferenceManager.setString( - context, - TOKEN_KEY_REFRESH, "none" - ) - } - private suspend inline fun getNewDeviceToken(): Boolean { return withContext(Dispatchers.IO) { //토큰 재발급 @@ -69,10 +57,9 @@ class TokenAuthenticator(val context: Context) : Authenticator { return true }.onFailure { Timber.tag("test").d("callRefresh-onFailure") - //이 부분을 onSuccess 안에 추가해야 하는 것인지, onFailure에 두는 것이 맞는지 헷갈립니다. if (it.message == "Unauthorized") { Timber.tag("test").d("callRefresh-onFailure-inner-if") - clearToken() + PreferenceManager.clear(context) Handler(Looper.getMainLooper()).post { Toast.makeText( context, From d1f38530dd6efa4c2991be58208909553238e8f6 Mon Sep 17 00:00:00 2001 From: unam Date: Thu, 15 Feb 2024 22:07:02 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[FEAT]=20#228=20=ED=8C=8C=EC=9D=B4=EC=96=B4?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EB=8F=99=EC=A0=81=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=EB=A1=9C=20=EC=BD=94=EC=8A=A4=20=EA=B3=B5=EC=9C=A0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - iOS 호환 테스트 완료 --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 5 +- .../detail/CourseDetailActivity.kt | 156 ++++++++---------- 3 files changed, 72 insertions(+), 90 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d57d88054..1c86a120f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -78,6 +78,7 @@ dependencies { implementation 'androidx.core:core:1.9.0' implementation 'com.google.firebase:firebase-common-ktx:20.1.0' implementation 'androidx.preference:preference-ktx:1.2.1' + implementation 'com.google.firebase:firebase-dynamic-links-ktx:21.2.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 337e58fb3..68a843e69 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -118,10 +118,9 @@ - + android:host="rnnt.page.link" + android:scheme="https" /> diff --git a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt index 3e889dd36..e47fdaba6 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt @@ -4,6 +4,7 @@ import android.app.Activity import android.content.ActivityNotFoundException import android.content.Intent import android.graphics.Rect +import android.net.Uri import android.os.Bundle import android.view.Gravity import android.view.MotionEvent @@ -14,6 +15,8 @@ import androidx.activity.OnBackPressedCallback import androidx.activity.viewModels import androidx.core.view.isVisible import coil.load +import com.google.firebase.dynamiclinks.DynamicLink +import com.google.firebase.dynamiclinks.FirebaseDynamicLinks import com.gun0912.tedpermission.provider.TedPermissionProvider.context import com.kakao.sdk.common.util.KakaoCustomTabsClient import com.kakao.sdk.link.LinkClient @@ -90,33 +93,44 @@ class CourseDetailActivity : Analytics.logClickedItemEvent(VIEW_COURSE_DETAIL) - initIntentExtraData() - updatePublicCourseIdFromDeepLink() - getCourseDetail() - - addListener() - addObserver() - registerBackPressedCallback() + updatePublicCourseIdFromDynamicLink { dynamicLinkHandled -> + if (!dynamicLinkHandled) { + initIntentExtraData() + } + addListener() + addObserver() + registerBackPressedCallback() + getCourseDetail() + } } private fun initIntentExtraData() { intent.getCompatibleSerializableExtra(EXTRA_ROOT_SCREEN)?.let { rootScreen = it } - publicCourseId = intent.getIntExtra(EXTRA_PUBLIC_COURSE_ID, 0) - } - - private fun updatePublicCourseIdFromDeepLink() { - // 딥링크를 통해 열린 경우 - if (Intent.ACTION_VIEW == intent.action) { - isFromDeepLink = true - val uri = intent.data - if (uri != null) { - // 여기서 androidExecutionParams 값들을 받아와 어떠한 상세 페이지를 띄울지 결정할 수 있음. - publicCourseId = uri.getQueryParameter("publicCourseId")!!.toInt() - Timber.tag("deeplink-publicCourseId").d("$publicCourseId") + publicCourseId = intent.getIntExtra(EXTRA_PUBLIC_COURSE_ID, -1) + Timber.tag("intent-publicCourseId").d("$publicCourseId") + } + + private fun updatePublicCourseIdFromDynamicLink(completion: (Boolean) -> Unit) { + FirebaseDynamicLinks.getInstance().getDynamicLink(intent) + .addOnSuccessListener(this) { pendingDynamicLinkData -> + val deepLink: Uri? = pendingDynamicLinkData?.link + if (deepLink != null) { + isFromDeepLink = true + publicCourseId = deepLink.getQueryParameter("courseId")?.toInt() ?: -1 + if (publicCourseId != -1) { + Timber.tag("deeplink-publicCourseId").d("$publicCourseId") + completion(true) + return@addOnSuccessListener + } + } + completion(false) + } + .addOnFailureListener(this) { e -> + Timber.e("getDynamicLink:onFailure", e) + completion(false) } - } } private fun getCourseDetail() { @@ -163,7 +177,7 @@ class CourseDetailActivity : intent?.let { newIntent -> newIntent.getCompatibleSerializableExtra(EXTRA_ROOT_SCREEN) ?.let { rootScreen = it } - publicCourseId = newIntent.getIntExtra(EXTRA_PUBLIC_COURSE_ID, 0) + publicCourseId = newIntent.getIntExtra(EXTRA_PUBLIC_COURSE_ID, -1) getCourseDetail() } } @@ -238,9 +252,42 @@ class CourseDetailActivity : } } + private fun sendFirebaseDynamicLink(title: String, desc: String, image: String) { + val link = "https://rnnt.page.link/?courseId=$publicCourseId" + + FirebaseDynamicLinks.getInstance().createDynamicLink() + .setLink(Uri.parse(link)) + .setDomainUriPrefix("https://rnnt.page.link") + // Set parameters + .setAndroidParameters(DynamicLink.AndroidParameters.Builder().build()) + .setIosParameters(DynamicLink.IosParameters.Builder("com.runnect.Runnect-iOS").build()) + .setSocialMetaTagParameters( + DynamicLink.SocialMetaTagParameters.Builder() + .setTitle(title) + .setDescription(desc) + .setImageUrl(Uri.parse(image)) + .build()) + .buildShortDynamicLink() + .addOnSuccessListener { result -> + val shortLink = result.shortLink + shareLink(shortLink.toString()) + } + .addOnFailureListener { + it.printStackTrace() + } + } + + private fun shareLink(url: String) { + val intent = Intent(Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(Intent.EXTRA_TEXT, url) + } + startActivity(Intent.createChooser(intent, "Share Link")) + } + private fun initShareButtonClickListener() { binding.btnShare.setOnClickListener { - sendKakaoLink( + sendFirebaseDynamicLink( title = courseDetail.title, desc = courseDetail.description, image = courseDetail.image @@ -255,71 +302,6 @@ class CourseDetailActivity : } } - // todo: 함수를 더 작게 분리하는 게 좋을 거 같아요! @우남 - private fun sendKakaoLink(title: String, desc: String, image: String) { - // 메시지 템플릿 만들기 (피드형) - val defaultFeed = FeedTemplate( - content = Content( - title = title, - description = desc, - imageUrl = image, - link = Link( - mobileWebUrl = "https://play.google.com/store/apps/details?id=com.runnect.runnect" - ) - ), - buttons = listOf( - Button( - "자세히 보기", - Link( - //이 부분을 사용해서 어떤 상세페이지를 띄울지 결정할수 있다 - androidExecutionParams = mapOf( - "publicCourseId" to publicCourseId.toString(), - ) - ), - ) - ) - ) - - // 피드 메시지 보내기 - if (context?.let { LinkClient.instance.isKakaoLinkAvailable(it) } == true) { - // 카카오톡으로 카카오링크 공유 가능 - context?.let { - LinkClient.instance.defaultTemplate(it, defaultFeed) { linkResult, error -> - if (error != null) { - Timber.tag("kakao_link").d("카카오링크 보내기 실패: $error") - } else if (linkResult != null) { - Timber.tag("kakao_link").d("카카오링크 보내기 성공: ${linkResult.intent}") - - startActivity(linkResult.intent) //카카오톡이 깔려있을 경우 카카오톡으로 넘기기 - - // 카카오링크 보내기에 성공했지만 아래 경고 메시지가 존재할 경우 일부 컨텐츠가 정상 동작하지 않음 - Timber.tag("kakao_link").d("Warning Msg: ${linkResult.warningMsg}") - Timber.tag("kakao_link").d("Argument Msg: ${linkResult.argumentMsg}") - } - } - } - } else { // 카카오톡 미설치: 웹 공유 사용 권장 - // 웹 공유 예시 코드 - val sharerUrl = WebSharerClient.instance.defaultTemplateUri(defaultFeed) - - // 1. CustomTabs으로 Chrome 브라우저 열기 - try { - context?.let { KakaoCustomTabsClient.openWithDefault(it, sharerUrl) } - } catch (e: UnsupportedOperationException) { - // Chrome 브라우저가 없을 때 - Toast.makeText(context, "chrome 또는 인터넷 브라우저를 설치해주세요", Toast.LENGTH_SHORT).show() - } - - // 2. CustomTabs으로 디바이스 기본 브라우저 열기 - try { - context?.let { KakaoCustomTabsClient.open(it, sharerUrl) } - } catch (e: ActivityNotFoundException) { - // 인터넷 브라우저가 없을 때 - Toast.makeText(context, "chrome 또는 인터넷 브라우저를 설치해주세요", Toast.LENGTH_SHORT).show() - } - } - } - private fun initStartRunButtonClickListener() { binding.btnCourseDetailStartRun.setOnClickListener { if (isVisitorMode) { From 1cd2c950cea3c14941d2ff0fc08bb4d7c5839736 Mon Sep 17 00:00:00 2001 From: unam Date: Thu, 15 Feb 2024 22:15:38 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[CHORE}=20#228=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20import=EB=AC=B8=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/detail/CourseDetailActivity.kt | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt index e47fdaba6..1233bd972 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt @@ -1,7 +1,6 @@ package com.runnect.runnect.presentation.detail import android.app.Activity -import android.content.ActivityNotFoundException import android.content.Intent import android.graphics.Rect import android.net.Uri @@ -10,21 +9,12 @@ import android.view.Gravity import android.view.MotionEvent import android.view.View import android.widget.EditText -import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.activity.viewModels import androidx.core.view.isVisible import coil.load import com.google.firebase.dynamiclinks.DynamicLink import com.google.firebase.dynamiclinks.FirebaseDynamicLinks -import com.gun0912.tedpermission.provider.TedPermissionProvider.context -import com.kakao.sdk.common.util.KakaoCustomTabsClient -import com.kakao.sdk.link.LinkClient -import com.kakao.sdk.link.WebSharerClient -import com.kakao.sdk.template.model.Button -import com.kakao.sdk.template.model.Content -import com.kakao.sdk.template.model.FeedTemplate -import com.kakao.sdk.template.model.Link import com.naver.maps.geometry.LatLng import com.runnect.runnect.R import com.runnect.runnect.binding.BindingActivity @@ -258,7 +248,6 @@ class CourseDetailActivity : FirebaseDynamicLinks.getInstance().createDynamicLink() .setLink(Uri.parse(link)) .setDomainUriPrefix("https://rnnt.page.link") - // Set parameters .setAndroidParameters(DynamicLink.AndroidParameters.Builder().build()) .setIosParameters(DynamicLink.IosParameters.Builder("com.runnect.Runnect-iOS").build()) .setSocialMetaTagParameters( @@ -266,7 +255,8 @@ class CourseDetailActivity : .setTitle(title) .setDescription(desc) .setImageUrl(Uri.parse(image)) - .build()) + .build() + ) .buildShortDynamicLink() .addOnSuccessListener { result -> val shortLink = result.shortLink