Cross-platform yerine native: iki uygulama, tek sözleşme

iPhone ve Android için uygulama planlayan herkes er ya da geç şu soruyla karşılaşır: Neden bir kez yazıp iki platformda birden yayınlamıyoruz? React Native veya Flutter gibi framework’ler tam olarak bunu vaat ediyor. React Native ve Expo ile biz de çalıştık; seyahat gideri uygulamamız ContoTrip’in erken bir prototipi de bunlardan biriydi. Yine de kendi ürünlerimiz için farklı bir yol seçtik: Her platformu ortak kod kullanmadan, native olarak geliştiriyoruz.

Bizim için „native“ ne anlama geliyor?

iOS tarafında uygulamayı Swift ve SwiftUI ile yazıyoruz; veriler SwiftData’da tutuluyor, eşitleme CloudKit üzerinden yapılıyor. Android tarafında ise yol Kotlin ve Jetpack Compose. İki uygulama birbirinden bağımsızdır. Üçüncü bir dilde yazılmış ortak iş mantığı, bir köprü katmanı ya da iki dünyayı birbirine benzeten bir soyutlama yoktur.

İlk bakışta bu, iki kat iş gibi görünebilir. Pratikte ise karşılığında üç şey kazanıyoruz:

  • Platforma uygun kullanım. Navigasyon, paylaşım menüsü, widget’lar, kısayollar ve sistem pencereleri, kullanıcıların kendi cihazlarından alıştığı şekilde çalışır.
  • Yeni sistem özelliklerine doğrudan erişim. Apple ya da Google yeni bir arayüz sunduğunda, bir framework güncellemesini beklemek zorunda kalmayız.
  • Daha az bağımlılık. Native bir proje, platform üreticisinin araçlarına bağlıdır; bunun yanında ayrıca üçüncü bir sağlayıcıya ve onun eklenti ekosistemine bağlı değildir.

Açık konuşalım: Dual-native projelerimizde iOS tarafı üzerinde çalışıyoruz, Android tarafı ise planlama aşamasında. İki platformun ortak zeminini şimdiden belirlememizin nedeni de tam olarak bu.

Tek temas noktası: veri değişim formatı

Kod paylaşmayan iki uygulamanın da ortak bir dile ihtiyacı vardır. Kullanıcılar kayıtları birbirine WhatsApp, e-posta ya da AirDrop ile gönderir; ileride bir Android uygulamasının da iOS uygulamasıyla aynı dosyaları okuyup yazabilmesi gerekir. Bu değişim formatını bir sözleşme gibi ele alıyoruz. Bir kez gönderilmiş bir dosya, bir yıl sonra da içe aktarılabilmelidir.

Sözleşmenin kuralları

  • Sürümlü bir zarf. Her dosya sürüm, tür ve içerikten oluşan bir yapı taşır; örneğin { "v": 1, "type": "…", "payload": { … } }. Böylece içe aktarma işlemi eski sürümleri tanıyabilir ve bilinçli olarak işleyebilir.
  • ISO 8601 biçiminde tarihler. Ayrıca belirtilmezse Swift tarihleri, Apple’ın 2001 referans tarihinden bu yana geçen saniyeleri gösteren ondalık bir sayı olarak yazar. Apple dünyasının dışında bu değer işe yaramaz.
  • Sabit İngilizce enum değerleri. Bir öncelik dosyada "high" olarak saklanır; asla „Hoch“ ya da „Yüksek“ olarak değil. Çevrilmiş etiketler veriye değil, arayüze aittir.
  • Tutarlar tam sayı olarak, kuruş cinsinden. Ondalık sayılar ve ülkeye özgü biçimlendirme, yuvarlama hatalarına ve ayrıştırma sorunlarına yol açar.
  • UTI’nin yanında MIME türü. iOS dosya türlerini Uniform Type Identifier’lar üzerinden tanır. Tanımda MIME türü eksikse iOS dosyayı application/octet-stream olarak gönderir ve Android dosyanın ne olduğunu anlayamaz.

Dosyayı içeriğinden tanımak

E-posta programları ve mesajlaşma uygulamaları ekleri yeniden adlandırır ya da yanlış tür bilgisi ekler. Bu nedenle içe aktarma işlevimiz dosya uzantısına güvenmez: JSON dosyalarını kabul eder ve zarfın içindeki tür alanını kontrol eder. Buna ek olarak uygulama, uygulamayı yüklememiş alıcılar için okunabilir bir düz metin sürümü de üretir.

Bilinçli olarak aktarılmayanlar

Veritabanı kimlikleri ve cihaza özgü durum bilgileri cihazda kalır. Gönderenin kimlik numarası alıcı için hiçbir anlam taşımaz. Örneğin bir kategoriye yapılan atıflar, içe aktarma sırasında ad üzerinden eşleştirilir. İçe aktarma asla sessizce gerçekleşmez: Alıcı düzenlenebilir bir önizleme görür ve kayıttan önce onay verir.

Cross-platform ne zaman yine de doğru seçim?

Native geliştirme bir inanç meselesi değildir. Bazı projelerde ortak bir kod tabanı daha mantıklıdır:

  • iki platformda hızla test edilmesi gereken bir prototip,
  • ağırlıklı olarak mevcut bir API’den gelen form ve listeleri gösteren bir uygulama,
  • React ve TypeScript konusunda derin deneyime sahip olan ve bu bilgiyi kullanmaya devam etmek isteyen bir ekip.

Bu tür durumlarda React Native ile Expo’yu öneriyor, sınırlarını da açıkça söylüyoruz. Örneğin belge tarayıcı gibi native modüller Expo Go içinde çalışmaz; bunun için özel bir geliştirme derlemesi gerekir.

Sonuç

Uzun ömürlü olması, işletim sisteminin derinliklerine erişmesi ve her platformda doğal hissettirmesi gereken ürünleri native olarak geliştiriyoruz. Ek iş yükünü net bir mimari ve özenle tanımlanmış bir değişim formatıyla dengeliyoruz. Bu format, uygulamalar arasındaki asıl bağdır. Onu erkenden belirleyen, ileride en zor geçişten kurtulur: kullanıcıların cihazlarında zaten bulunan verilerin taşınmasından.

Bir uygulama planlıyor ve hangi yolun projenize uygun olduğundan emin değil misiniz? İlk satır kod yazılmadan önce bunu sizinle memnuniyetle konuşuruz.

Yukarı çık