Örnek-7: Navigation Komponenti ile Deep Links Kullanımı

Android'teki önemli bir kullanım yeri olan deep link'leri Navigation komponenti ile kolaylıkla kullanabilirsiniz. Bu örneğimizde bunu nasıl gerçekleştireceğimizi öğreneceğiz.

Kullanılabilecek iki tip deep links türü vardır, Explicit (Açık) ve Implicit (Üstü Kapalı). Deep Links'in özelliği ise kullanıldığında sizi doğrudan bir uygulamadaki belirli bir hedefe götüren bir bağlantı olmasıdır. Bu kavramları zaten Android Developer'lar intent konusundan yakınen tanıyorlar. Bu yüzden ne olduklarını açıklamaktan öte, Navigation ile kullanımının nasıl olduğunu inceleyeceğiz.

Kullanılabilecek iki tip deep links türü vardır.

Kullanılabilecek iki tip deep links türü vardır, Explicit (Açık) ve Implicit (Üstü Kapalı). Deep Links'in özelliği ise kullanıldığında sizi doğrudan bir uygulamadaki belirli bir hedefe götüren bir bağlantı olmasıdır. Bu kavramları zaten Android Developer'lar intent konusundan yakınen tanıyorlar. Bu yüzden ne olduklarını açıklamaktan öte, Navigation ile kullanımının nasıl olduğunu inceleyeceğiz.

Explicit (Açık) intent, kullanımları arasında en popülerleri olanları uygulama widget'ları ve notification'lar (bildirimler) dır. Biz de Explicit deep link örneğimizde bildirimlerden faydalanacağız.

Öncelikle senaryomuzu belirtelim. Biliyorsunuz devam eden örneğimizde blankFragment4 içerisinde nameField isimli bir argüman alıyoruz. Bu argümanı da blankFragment içerisinden bulunan EditText'i doldurup, parametre olarak blankFragment4'te görüntülüyorduk.

Şimdi ise direkt olarak blankFragment4 sayfasını açıp, o sayfaya yerleştirmiş olduğumuz butona tıklayıp bir notification çıkmasını sağlayacağız. Bu notification'a tıklandığında ise tekrar blankFragment4 sayfasını açacağız ama argümanımız ile birlikte.

İlk olarak blankFragment4'e ait fragment_blank_fragment4.xml dosyasını açıp, içerisini aşağıdaki gibi düzenliyoruz.

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tvMessage"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="@string/hello_blank_fragment4" />

    <Button
        android:id="@+id/btnSendNotificationButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send Notification"
        tools:ignore="HardcodedText"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvMessage" />

</androidx.constraintlayout.widget.ConstraintLayout>

Buna göre görüntümüz de şu şekilde oluşmuş oldu.

Senaryomuza göre "Send Notification" butonuna tıkladığımızda bir notification çıkmasını istiyoruz. Bunun için de BlankFragment4.kt dosyamızı aşağıdaki gibi düzenliyorum.

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    tvMessage.text = "Diğer sayfadan gelen veri: " + arguments?.getString("nameField")

    val notificationButton = view?.findViewById<Button>(R.id.btnSendNotificationButton)
    notificationButton?.setOnClickListener {
        val args = Bundle()
        args.putString("nameField", "Egemen")

        val deeplink = findNavController().createDeepLink()
            .setDestination(R.id.blankFragment4)
            .setArguments(args)
            .createPendingIntent()

        val notificationManager =
            context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notificationManager.createNotificationChannel(
                NotificationChannel(
                "deeplink", "Navigation ile Deep Link", NotificationManager.IMPORTANCE_HIGH)
            )
        }

        val builder = NotificationCompat.Builder(
            context!!, "deeplink")
            .setContentTitle("Navigation Component")
            .setContentText("Bildirimden Android uygulamasına Deep link için tıklayın.")
            .setSmallIcon(android.R.drawable.ic_dialog_alert)
            .setContentIntent(deeplink)
            .setAutoCancel(true)
        notificationManager.notify(0, builder.build())
    }
}

Kodumuzu biraz anlatalım. Biliyorsunuz yukarıda da bahsetmiştik. blankFragment4 için nameField isimli bir argümanımız var. Notification üzerindeki deep link ile bu alanı dolduracağız. Bu sebeble nameField ismi ile bir Bundle oluşturduk ve içerisine Egemen değerini verdik.

Satır 11'den itibaren NavController'a ait createDeepLink metodunu kullanarak hedefimizi blankFragment4 olarak belirleyip, argüman alanına da oluşturduğumuz Bundle'ı almasını sağladık.

Sonrasında standart notification kodlarımızı hazırladıktan sonra 30. Satırdaki setContentIntent'ine hazırladığımız deeplink isimli intenti atadık. Artık "Send Notification" butonuna tıklayarak notification'ı aşağıdaki gibi gönderebiliriz.

Notification'a tıkladığınızda ise uygulamamızda BlankFragment4 sayfası açılacak ve Bundle içerisinde verdiğimiz Egemen değeri sayfa içerisinde aşağıdaki gibi görüntülenecektir.

Yukarıdaki örneğimizdeki Explicit (Açık) deep link kullanımını notificationlar aracılığı ile yapmış olduk.

Aynı kullanım şeklini istersek widget'lar ile de yapabiliriz. Bunun için birkaç yeni dosyaya da ihtiyacımız olacak. Şimdi hızlıca onları hazırlayalım.

Hazırlayacağımız widget'a ait sınıfı oluşturmak için aşağıdaki DeepLinkAppWidget.kt class'ı hazırlıyoruz.

class DeepLinkAppWidget : AppWidgetProvider() {
    override fun onUpdate(
        context: Context?,
        appWidgetManager: AppWidgetManager?,
        appWidgetIds: IntArray?
    ) {
        val remoteViews = RemoteViews(
            context?.packageName,
            R.layout.deep_link_appwidget
        )

        val args = Bundle()
        args.putString("nameField", "Widget'tan gelen veri")

        val pendingIntent = NavDeepLinkBuilder(context!!)
                .setGraph(R.navigation.nav_graph)
                .setDestination(R.id.blankFragment4)
                .setArguments(args)
                .createPendingIntent()

        remoteViews.setOnClickPendingIntent(R.id.btnDeepLinkButton, pendingIntent)

        appWidgetManager?.updateAppWidget(appWidgetIds, remoteViews)
    }
}

Burada görüntülenecek olan widget'ın taşıyacağı değer, nereye tıklanacağı ve hedefin ne olduğu aynı notification örneğimizde olduğu gibi burada hazırlanıyor. Şimdi hazırladığımız bu class'ı AndroidManifest.xml dosyasında application etiketlerinin arasında tanımlayalım.

<receiver android:name=".DeepLinkAppWidget">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>

    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/deep_link_appwidget_info" />
</receiver>

Dikkat ettiyseniz @xml/deep_link_appwidget_info altında bir resource dosyamız bulunuyor. Bunun için res klasörü altında bir xml klasörü oluşturup, içerisinde de deep_link_appwidget_info.xml dosyasını aşağıdaki gibi oluşturalım.

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="120dp"
    android:minHeight="60dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/deep_link_appwidget"/>

Burada da appwidget'ımızı oluşturacak initialLayout'u için @layout/deep_link_appwidget dosyasını aşağıdaki gibi oluşturalım.

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/btnDeepLinkButton"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="Deep Link Button" />

Böylelikle widget'ımız da hazır durumda. Artık uygulamamız için olan widget'ınızı ekranınıza aşağıdaki gibi ekleyebilirsiniz.

Widget'a tıkladığımızda ise aynen notification'da olduğu gibi hedef olarak belirlediğimiz BlankFragment4 sayfasını açacak ve Bundle içerisinde belirttiğimiz veriyi de ekranda gösterecektir.

Buraya kadar olan bölümde hem notification'larla hem de widget'larla Explicit (Açık) deep link kullanımını örneklemiş olduk.

Şimdiki örneğimiz ise Implicit (Üstü Kapalı) deep link kullanımına yönelik olacak.

Implicit deep link'ler web url'leri ve özel uri şemalarını içerir.

Hemen örneğimizi yapmak için hazırlıklara başlayalım. İlk olarak nav_graph.xml içerisinde blankFragment4 içerisinde aşağıdaki bir deep link ekleyelim.

<fragment
    android:id="@+id/blankFragment4"
    android:name="com.etiya.jpnavigation1.BlankFragment4"
    android:label="fragment_blank_fragment4"
    tools:layout="@layout/fragment_blank_fragment4">
    <action
        android:id="@+id/action_blankFragment4_to_blankFragment5"
        app:destination="@id/blankFragment5" />
    <argument
        android:name="nameField"
        app:argType="string" />
    <deepLink
        android:id="@+id/blankFragment4WebDeepLink"
        app:uri="https://www.testurladresim.com/{nameField}" />
</fragment>

Ben ekleme işlemini XML yani kod üzerinden gerçekleştirdim. Ancak önceki örneklerimizden de bildiğiniz gibi bunu nav_graph üzerindeki design bölümünden de yapabilirsiniz. Hangisi kolayınıza geliyorsa..

Bu arada AndroidManifest.xml dosyası içerisinde aşağıdaki gibi nav_graph'ı eklemeyi de unutmayalım. Aksi durumda deeplink'i eklediğimiz bölüm uygulama ve işletim sistemi tarafından tanınmayacaktır.

<activity android:name=".MainActivity" android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <nav-graph android:value="@navigation/nav_graph" />
</activity>

Bu işlemi de gerçekleştirdiğimize göre aşağıdaki gibi test edebiliriz.

nav_graph'ta tanımladığımız gibi bir URL'yi

https://www.testurladresim.com/{nameField}

WhatsApp üzerinden arkadaşımıza aşağıdaki gibi gönderdiğimizi farzedelim.

Arkadaşımız bu linke tıkladığında işletim sistemi, aşağıdaki gibi bu bir URL olduğundan dolayı bir tarayıcı ile mi? yoksa uygulamamızla mı açmak istediğinizi soracaktır.

Uygulamayı seçtiğinizde ise aşağıdaki gibi linkte bulunan parametre uygulamamız tarafından alınacaktır.

Yine aynı şekilde bu işlemi bir URI şeması şeklinde de gerçekleştirebiliriz.

Bunun için nav_graph.xml dosyasını tekrar açıp aşağıdaki gibi URI şemasını kullanacak deeplink'i ekliyorum.

<fragment
    android:id="@+id/blankFragment4"
    android:name="com.etiya.jpnavigation1.BlankFragment4"
    android:label="fragment_blank_fragment4"
    tools:layout="@layout/fragment_blank_fragment4">
    <action
        android:id="@+id/action_blankFragment4_to_blankFragment5"
        app:destination="@id/blankFragment5" />
    <argument
        android:name="nameField"
        app:argType="string" />
    <deepLink
        android:id="@+id/blankFragment4WebDeepLink"
        app:uri="https://www.testurladresim.com/{nameField}" />
    <deepLink
        android:id="@+id/blankFragment4DeepLink"
        app:uri="exampleapp://name/{nameField}" />
</fragment>

Gördüğünüz üzere URI şemamız aşağıdaki gibi tanımladık.

exampleapp://name/{nameField}

Test edebilmek için de Google'ın önerdiği gibi Terminal'i kullanarak yapacağız.

Bunun için terminal'i açıp aşağıdaki komut satırını giriyorum.

adb shell am start -W -a android.intent.action.VIEW -d "exampleapp://name/egemen" com.etiya.jpnavigation1

İşlem gerçekleştiğinde bilgisayarıma bağlı olan cep telefonumda uygulamamız kapalı olduğu halde açıldı ve aşağıdaki gibi deeplink'te belirttiğimiz sayfamıza gönderdiğimiz argüman ile gelmiş oldu.

Last updated