— Ruby on Rails, Turbolinks, Android — 2 min read
Turbolinks, web'de gezinmeyi hızlandıran bir javascript kütüphanesidir. Bunu, yeni bir linke gidildiğinde sadece body ve title'ı güncelleyerek yapar. Rails ekosistemi için oldukça önemli bir yere sahiptir.
Turbolinks'in bu davranışı sadece web'de değil, mobil uygulamalarda da performans artışı sağlar. Web uygulama geliştiricileri, halihazırda geliştirmiş oldukları web sitelerini turbolinks adaptörleri sayesinde mobil cihazlara da uygulayabilirler.
Yani burda gelişmiş bir şekikde webview kullanan, hibrit uygulamalardan söz ediyoruz.
Şimdilik sadece turbolinks-ios ve turbolinks-android adaptörleri bulunmaktadır.
Turbolinks android adaptörü şu an geliştırilmemektedir. Geliştiricileri ise 2.0 versiyonunu hazırlamakta. bknz.
Şu an deprecate olması, işlevsel olmadığı anlamına gelmemekte bilakis Basecamp 3 uygulaması hala turbolinks-android ile çalışmaktadır.
Konumuz rails olmadığı için bu kısmı fazla detay vermeden geçiyorum. Rails 5 veya 6 kullanıyorsanız zaten turbolinks kullanıyorsunuz demektir (özellikle kaldırmadıysanız). Onun haricinde, gerekli kurulum bilgilerini turbolinks reposunda bulabilirsiniz. Ben bu yazıda MIT lisansıyla geliştirmekte olduğum basit groupath isimli projemi kullanacağım, çünkü işimiz sadece android tarafında olacak.
İşe Empty Activity
'i seçerek bir android projesi oluşturmakla başlayalım.
Projeyi oluştururken isim vermeyi ve Minimum API Levelini 19 yapmayı unutmayalım. Turbolinks android adaptörü, android 4.4 öncesine destek vermemektedir.
Ayrıca benim tavsiyem, eğer bu teknolojiyi seçecekseniz, min api sevyiesini 23 yapmanız olacaktır.
Şimdi, yapılması oldukça basit olan aşağıdaki adımları, birer birer uygulayalım:
En büyük sıkıntıyı çektiğimiz kısım burası. Çünkü zaman geçtikçe bağımlı uygulamalar değişiyor, farklı paketlere geçiyor veya siliniyor. Bu yüzden bu adımın güncel olması gerekiyor. Bu yazıyı yayımladığım 2019-08-17 tarihi ile tüm bağımlılıklar çalışır halde ve günceldir. Ayrıca güncel tutmaya çalışacağım.
build.gradle
dosyamızdaki (uygulamanın, projenin değil!) bağımlılıklara (dependencies) eklememiz gereken üç implementasyon var:
1implementation 'com.basecamp:turbolinks:1.0.9' // Turbolinks2implementation 'com.google.code.gson:gson:2.8.2' // Important addition 13implementation 'org.apache.commons:commons-lang3:3.1' // Important addition 2
Dosyanın tam haline bu gist üzerinden ulaşabilirsiniz.
Bundan sonra Build > Rebuild Project
diyip Build completed successfully şeklinde bir çıktı almamız gerekiyor.
Bu dosyayı direkt orijinal turbolinks-android reposundaki örnek uygulamadan alabiliriz.
1<?xml version="1.0" encoding="utf-8"?>2<LinearLayout3 xmlns:android="http://schemas.android.com/apk/res/android"4 android:layout_width="match_parent"5 android:layout_height="match_parent"6 android:orientation="vertical">78 <com.basecamp.turbolinks.TurbolinksView9 android:id="@+id/turbolinks_view"10 android:layout_width="match_parent"11 android:layout_height="match_parent"/>1213</LinearLayout>
Bunun için AndroidManifest.xml
dosyasında, manifest tagının içine aşağıdaki satırı eklememiz yeterlidir.
1<uses-permission android:name="android.permission.INTERNET" />
Bunun için de turbolinks-android reposundaki örnek uygulamayı baz alabiliriz.
app/ java/ com.example.turbolinksapp/ MainActivity.java
(com.example.turbolinksapp kısmı uygulamaya verdiğiniz isime göre değişebilir.)
En üstte bulunan
package com.example.turbolinksapp;
tarzı kodu, proje package isminiz farklıysa sizinkiyle değiştirin.
118 satırlık kodu buraya yazmak mantıksız olacağından, kodu sadece örnek oluşturması amacıyla kırparak veriyorum. Lütfen buradan kopyalayarak kodunuzu düzenleyin.
1package com.example.turbolinksapp;23import android.content.Intent;4import android.os.Bundle;5// ...67public class MainActivity extends AppCompatActivity implements TurbolinksAdapter {8 9 private static final String BASE_URL = "http://10.0.1.100:9292";10 private static final String INTENT_URL = "intentUrl";1112 private String location;13 private TurbolinksView turbolinksView;1415 @Override16 protected void onCreate(Bundle savedInstanceState) {17 // ...18 }1920 // ...21 22}
Kısaca MainActivity classının BASE_URL değişkeninin değerini, uygulamanızın adresiyle değiştirin.
1public class MainActivity extends AppCompatActivity implements TurbolinksAdapter {2 // Change the BASE_URL to an address that your VM or device can hit.3 private static final String BASE_URL = "https://groupathx.herokuapp.com";4 private static final String INTENT_URL = "intentUrl";5 // ...6}
Başlangıçtada bahsettiğim gibi groupath
uygulamamın adresini verdim.
Ve Sonuç :)
Turbolinks Android bize webviewin tam kontrolünü vermektedir. Bu webview'a TurbolinksSession.getDefault(this).getWebView()
şeklinde ulaşabiliriz.
Uygulamamıza özel user-agent setleyerek, daha farklı viewlar göstermek gibi uygulamaya özel işlemler yapabiliriz. Buna en yaygın örnek, websitesinin navbarını render etmeyip, uygulama içinde native bir navigasyon göstermek olabilir.
1// Set UserAgent2TurbolinksSession.getDefault(this).getWebView().getSettings().setUserAgentString("MyAndroidApp");
Sayfalar arası geçiş için gelen ProgressView ekranını özelleştirebiliyoruz. Bunun için aşağıdaki adımları takip edebilirsiniz:
1<?xml version="1.0" encoding="utf-8"?>2<LinearLayout3 xmlns:android="http://schemas.android.com/apk/res/android"4 android:layout_width="match_parent"5 android:layout_height="match_parent"6 android:orientation="vertical">78 <FrameLayout9 android:id="@+id/frameLayout"10 android:layout_width="fill_parent"11 android:layout_height="fill_parent"12 android:background="#fff">1314 <ProgressBar15 android:id="@+id/indeterminateBar"16 />17 </FrameLayout>1819 <com.basecamp.turbolinks.TurbolinksView20 android:id="@+id/turbolinks_view"21 android:layout_width="match_parent"22 android:layout_height="match_parent"/>232425</LinearLayout>
Artık burada kullandığımız ProgressBar'ı istediğimiz gibi değiştirebiliriz.
1// ...23import android.view.View; // Add this line45public class MainActivity extends AppCompatActivity implements TurbolinksAdapter {6 // ...78 @Override9 protected void onCreate(Bundle savedInstanceState) {10 super.onCreate(savedInstanceState);11 12 // ...1314 View progressView = (View) findViewById(R.id.frameLayout); // Add this line15 TurbolinksSession.getDefault(this)16 .activity(this)17 .adapter(this)18 .view(turbolinksView)19 .progressView(progressView, R.id.indeterminateBar, 500) // Add this line20 .visit(location);21 }2223 // ...24}
Kullandığımız progressView methodundaki 500 parametresi, ms biçiminden progressBar'ın aktive edilme süresidir.
MainActivity'deki handleError methodu ile hataları handle edebiliriz. Hata oluştuğnda bu method, hata kodu ile birlite tetiklenir. Örnek olarak internet yokken istek atıldığında bu method 0 koduyla tetiklenir. Biz de kullanıcıya "internet bağlı değil" gibi native bir çıktı sunabiliriz.
Sayfada turbolinks'i aktif bir linke tıkladığımızda tetiklenen method visitProposedToLocationWithAction
dır.
Artık biz de burada yeni bir intent üretip, gidilecek konumu vererek intenti başlatırız.
Ayrıca burada, gidilecek konumu kontrol etmek veya farklı bir aktiviteyi açmak gibi şeyler yapabiliriz.
Android 9'da ngrok gibi bir servisle lokalden geliştirme yapmak isterken
Cleartext HTTP traffic not permitted
gibi çirkin bi hata ile karşılaşabilirsiniz. Bunu çözmek için AndroidManifest.xml dosyasındaki application tagınaandroid:usesCleartextTraffic="true"
attribute'ünü ekleyebilirsiniz. Production'da kullanmak tehlikeli olabileceği için işiniz bittiğinde silmeyi unutmayın.
Daha komplike bir örnek için, kendi hazırladığım groupath-android projesine bakabilirsiniz. Yeni şeyler öğrendikçe geliştiriyor olacağım.