• 19.08.2026 02:43:20
  • Admin Admin

Bu android eğitimi, Jetpack Compose Navigation'da tip guvenli derin linkleri, oturum kapilarini, process death sonrasi hedef geri yuklemeyi ve test edilebilir geri yiginini somut kodla ele alir.

Jetpack Compose'da Derin Link ve Geri Yiginini Guvenli Tasarlamak

Jetpack Compose ile tip guvenli derin link sozlesmesi kurmak

Derin link URL'sini sadece bir ekran acma mekanizmasi olarak degil, uygulamanin disariya acik API sozlesmesi olarak ele alin. String bir route uretmek yerine Navigation Compose'un tip guvenli destination API'si ve Kotlin Serialization kullanildiginda, articleId gibi zorunlu alanlar route taniminda gorunur olur. Bu, bir android kursu projesinde sik gorulen "article/" + id birlestirmesindeki slash, bos deger ve URL-encoding hatalarini merkezi olarak azaltir.

@Serializable
data object Feed

@Serializable
data class Article(val articleId: String)

NavHost(
    navController = navController,
    startDestination = Feed
) {
    composable<Feed> {
        FeedScreen(
            onArticleClick = { id -> navController.navigate(Article(id)) }
        )
    }

    composable<Article>(
        deepLinks = listOf(
            navDeepLink<Article>(
                basePath = "https://app.example.com/article"
            )
        )
    ) { entry ->
        val route = entry.toRoute<Article>()
        ArticleRoute(articleId = route.articleId)
    }
}

Bu tanim, uygulama ici geciste navController.navigate(Article(id)), webden geliste ise https://app.example.com/article/42 sozlesmesini ayni destination etrafinda toplar. Ancak Android sisteminin URL'yi uygulamaniza yonlendirmesi icin manifest eslesmesi de gerekir. pathPrefix degeri Navigation tarafindaki temel path ile uyusmazsa Android intent'i activity'ye getirir, Navigation ise hedefi bulamaz. android eğitim materyallerinde bu iki katmanin birbirinden ayri oldugu acikca test edilmelidir.

<activity
    android:name=".MainActivity"
    android:exported="true">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="https"
            android:host="app.example.com"
            android:pathPrefix="/article" />
    </intent-filter>
</activity>

Kotlin egitimi perspektifiyle URL girdisini ViewModel sinirinda dogrulamak

Tip guvenli route, URL'nin guvenilir oldugu anlamina gelmez. Kullanici adb, tarayici veya baska bir uygulama ile herhangi bir articleId gonderebilir. Bu nedenle route argumanini UI icinde dogrudan repository sorgusuna vermek yerine ViewModel girisinda bicimsel olarak dogrulayin; ardindan sunucu tarafindaki yetkilendirme sonucunu ayri ele alin. Ornegin UUID kullanan bir sistemde gecersiz degeri HTTP istegi yapmadan reddetmek, gereksiz 404 trafigini ve anlamsiz crash kayitlarini engeller.

class ArticleViewModel(
    savedStateHandle: SavedStateHandle,
    private val repository: ArticleRepository
) : ViewModel() {
    private val args = savedStateHandle.toRoute<Article>()

    val uiState: StateFlow<ArticleUiState> = flow {
        val id = runCatching { UUID.fromString(args.articleId) }
            .getOrElse {
                emit(ArticleUiState.InvalidLink)
                return@flow
            }

        emit(ArticleUiState.Loading)
        emitAll(repository.observeArticle(id).map(ArticleUiState::Content))
    }.catch { error ->
        emit(ArticleUiState.Error(error))
    }.stateIn(
        viewModelScope,
        SharingStarted.WhileSubscribed(5_000),
        ArticleUiState.Loading
    )
}

Buradaki incelik, SavedStateHandle kullaniminin yalnizca configuration change icin olmamasidir. Sistem process'i oldurup activity'yi geri yuklediginde Navigation kaydedilmis back stack'i olusturabilir; ViewModel'in route argumanini ayni handle'dan almasi, ek bir singleton veya static cache gerektirmeden hedefi tekrar kurar. kotlin eğitimi veya kotlin kursu alan ekiplerde yaygin hata, route bilgisini sadece remember icinde tutmaktir; bu deger process death sonrasi geri gelmez.

Gercek App Link dogrulamasini debug cihazda iki ayri adimla kontrol edin. Ilk komut intent eslesmesini, ikinci komut ise Android'in domain dogrulama durumunu gorur:

adb shell am start -W   -a android.intent.action.VIEW   -d "https://app.example.com/article/550e8400-e29b-41d4-a716-446655440000"

adb shell pm get-app-links com.example.app
android:autoVerify tek basina yeterli degildir; alan adinizdaki /.well-known/assetlinks.json dosyasinin uygulamanin imza sertifikasi SHA-256 parmak iziyle eslesmesi gerekir. Debug ve release imzalari farkliysa, sadece debug kurulumda calisan bir senaryo release paketinde tarayici secicisine dusebilir.

Android MVVM mimarisi ile oturum kapisi ve geri tusunu modellemek

Korumali bir derin linkte en problemli akis sudur: kullanici kapaliyken makale URL'sine gelir, login ekrani acilir, basarili giris sonrasi makaleye gider, geri tusuna basinca tekrar login ya da yarim kurulmus hedef gorur. android mvvm mimarisi icinde NavController'i ViewModel'e enjekte etmek yerine, ViewModel'in yalnizca bekleyen hedefi ve kimlik durumunu yonetmesi daha test edilebilirdir. Navigation cagrisi composable'da bir yan etki olarak yapilmalidir.

class AuthGateViewModel(
    private val state: SavedStateHandle
) : ViewModel() {
    fun rememberPendingArticle(id: String) {
        state["pending_article_id"] = id
    }

    fun consumePendingArticle(): String? {
        val id: String? = state["pending_article_id"]
        state["pending_article_id"] = null
        return id
    }
}

@Composable
fun AuthGateRoute(
    articleId: String,
    signedIn: Boolean,
    viewModel: AuthGateViewModel,
    navController: NavHostController
) {
    LaunchedEffect(signedIn, articleId) {
        if (signedIn) {
            navController.navigate(Article(articleId)) {
                popUpTo<AuthGate> { inclusive = true }
            }
        } else {
            viewModel.rememberPendingArticle(articleId)
        }
    }
}

LaunchedEffect kritik ayrintidir: navigate() fonksiyonunu composable govdesinde cagirmak, her recomposition'da yeni bir destination ekleyebilir. Kodda popUpTo<AuthGate> { inclusive = true } kullanilmasinin mekanik etkisi, gecici gate destination'ini back stack'ten silmektir. Boylece makaleden geri gelindiginde kullanici login ekranina degil, derin linkten onceki anlamli hedefe veya uygulamadan cikis davranisina gider.

Bekleyen hedefi SavedStateHandle icinde saklamak, login akisi sirasinda process death olursa da gereklidir. Buna karsin parola, access token, ham e-posta veya tum URL query bilgisini bu handle'a koymayin; Android'in kaydedilmis state'i bundle olarak diske yazilabilir ve boyut sinirina takilabilir. Sadece UUID gibi kucuk bir referans saklayin, hassas oturum bilgisini platformun sifreli kimlik deposu ya da kimlik saglayicinizin session katmanindan tekrar okuyun.

Android Studio egitimi icin derin link testi ve play store yayinlama kontrol listesi

android studio eğitimi sirasinda derin linki sadece emulatorde elle tiklayarak dogrulamak yetersizdir. Navigation test artifact'i ile hedef route'un argumanini ve geri yiginini izole test edin. Testte gercek repository yerine sahte bir ekran tanimlamak, URL eslesmesi bozuldugunda sorunun network veya UI degil navigation contract oldugunu hizla gosterir.

@Test
fun articleDeepLink_opensArticleWithExpectedId() {
    val context = ApplicationProvider.getApplicationContext<Context>()
    val navController = TestNavHostController(context)
    navController.navigatorProvider.addNavigator(ComposeNavigator())
    navController.setGraph(R.navigation.main_graph)

    val intent = Intent(Intent.ACTION_VIEW).apply {
        data = Uri.parse("https://app.example.com/article/42")
    }

    assertThat(navController.handleDeepLink(intent)).isTrue()
    assertThat(navController.currentDestination?.route)
        .contains("Article")
    assertThat(navController.currentBackStackEntry
        ?.arguments?.getString("articleId")).isEqualTo("42")
}

Projeniz type-safe route nedeniyle XML graph kullanmiyorsa ayni fikri test composable'i icinde TestNavHostController ve uretimdeki NavHost tanimini kurarak uygulayin. Ayrica en az su dort senaryoyu CI'a koyun: cold start URL, uygulama arka plandayken yeni URL, oturumu kapali kullanici ve gecersiz ID. Her testten sonra currentBackStack.value.map { it.destination.route } kaydini assertion hatasina eklemek, beklenmeyen cift navigation'i teshis etmeyi kolaylastirir.

play store yayınlama oncesinde release imzasi ile uretilmis pakette App Link durumunu yeniden kontrol edin. Sunucuda yayinlanan dosya icin curl -i https://app.example.com/.well-known/assetlinks.json calistirin; yanit 200, gecerli JSON ve dogru package_name ile SHA-256 parmak izini icermelidir. CDN'in bu dosyayi login sayfasina yonlendirmesi, text/html dondurmesi veya eski sertifika parmak izini cache'lemesi domain verification'i bozar. Bu kontrol, mobil uygulama geliştirme eğitimi alan ekiplerin staging alan adinda calisip uretimde kirilan en yaygin teslimat hatalarindan birini yakalar.

Sık Sorulan Sorular

Jetpack Compose derin link neden uygulamayi aciyor ama hedef ekrana gitmiyor?

Manifest intent-filter'i URL'yi activity'ye yonlendirebilir, fakat Navigation Compose'taki navDeepLink basePath'i destination ile eslesmeyebilir. Once adb shell am start -W ile intent'i calistirin, sonra destination'in deepLinks listesindeki scheme, host ve path degerlerini kontrol edin. /article ile /articles farki bile eslesmeyi bozar.

Android MVVM mimarisi icinde NavController ViewModel'e verilmeli mi?

Verilmemeli. ViewModel, pending hedef gibi state ve tek seferlik navigation niyetini tutmali; composable bu state'i LaunchedEffect icinde NavController'a cevirmelidir. Bu ayrim, ViewModel unit testlerinde Android navigation runtime kurmadan oturum kapisi mantigini test etmenizi saglar.

Kotlin egitimi alan bir ekip process death sonrasi route argumanini nasil korur?

Destination argumanini ViewModel constructor'indaki SavedStateHandle'dan toRoute() ile okuyun. Sadece remember veya ViewModel field'i kullanmak yeterli degildir; bunlar process sonlandirildiginde kaybolur. Handle'a token yerine kucuk ve hassas olmayan bir kaynak kimligi yazin.

Play Store yayinlama sonrasinda Android App Links neden tarayici secicisi gosterir?

Release APK/AAB'nin imza sertifikasi parmak izi assetlinks.json icinde olmayabilir ya da dosya HTTPS uzerinden dogrudan 200 JSON donmuyor olabilir. adb shell pm get-app-links paket.adiniz komutuyla cihazdaki dogrulama durumunu inceleyin ve assetlinks.json yanitini curl -i ile release alan adindan kontrol edin.

AI / LLM Discovery

Bu makale Opendart Akademi Android eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

Opendart Akademi llms.txt