İçeriğe geç

SwiftUI Uygulamamı 2 Saatte VisionOS'a Taşımak

SwiftUI uygulamam CrossCraft'ı Apple Vision Pro'nun ilk gün lansmanına yetiştirmek için visionOS desteğini nasıl ekledim. Toplamda yaklaşık 2 saat sürdü, bu yazıda yol boyunca edindiğim temel dersleri özetliyorum.

SwiftUI Uygulamamı 2 Saatte VisionOS'a Taşımak

Sadece birkaç ay önce, tamamen SwiftUI ile yazılmış ve iOS, iPadOS ve macOS’ta kullanılabilen CrossCraft: Custom Crosswords uygulamasını yayınladım. Vision Pro’nun lansmanı için kendime uygulamayı yeni visionOS platformuna taşıma hedefi koydum — ama geçişe lansman gününden sadece 3 gün önce başladım!

Soru şuydu: bu kadar kısa sürede başarabilir miydim? Neyse ki yeterince kolay olduğu ortaya çıktı ve uygulamam ilk günden hazırdı! 👇

The official email from Apple, thanking Day 1 app developers.

Apple’dan gelen resmi e-posta, ilk gün geliştiricilerine teşekkür ediyor.

Aşağıda, senin de uygulamalarını taşırken faydalanabileceğin tüm öğrendiklerim var!

3. Parti Framework’ler

Projeme “Apple Vision” hedefini ekledikten sonra yaptığım ilk şey “Apple Vision Pro” simülatörünü seçip derlemeyi başlatmak oldu.

Step 2: Adjusting the Package.swift file is the most important step.

Beklediğim gibi derleme başarısız oldu. Çünkü tüm framework’ler henüz visionOS platformunu desteklemiyordu. Ama temel destek eklemek kolaydı. İşte 4 adım:

Step 2: Adjusting the Package.swift file is the most important step.

Adım 2: Package.swift dosyasını düzenlemek en önemli adım.

  1. Bağımlılığı fork’la, projenden kaldır ve fork’unu main branch’i ile ekle.

  2. Fork’taki Package.swift dosyasını aç, dosyanın başındaki Swift tools sürümünü 5.9’a yükselt ve desteklenen platforms dizisine .visionOS(.v1) ekle.

  3. #if os(iOS) geçen yerleri ara ve macOS yolundan kaçınmak için #if os(iOS) || os(visionOS) olarak değiştir, iOS yolunu tercih et.

  4. “Apple Vision Pro” simülatörünü seç ve projeyi derleyerek doğrula.

Eksik API’ler nedeniyle hata alırsan, doğru yerlere #if !os(visionOS) kontrolleri eklediğinden emin ol. Çoğu API mevcut olmalı çünkü Apple’ın resmi olarak doğruladığı gibi visionOS, iPadOS’un bir çatalı. Bir özellik yoksa ya yakında gelecektir ya da platformda zaten mantıklı değildir.

Benim durumumda sadece kendi ReviewKit kütüphanem için visionOS’ta henüz mevcut olmayan SKReviewController etrafındaki bazı kodları devre dışı bırakmam gerekti. Yani kütüphanem visionOS için derlendiğinde fiilen hiçbir şey yapmıyor, ama iOS ve Mac uygulamalarım kullanıcılardan değerlendirme istemeye devam ediyor. Bunu özel bir arayüzle çözebilirdim ama bu yılki WWDC’yi beklemeye karar verdim — belki orada zaten gelir diye.

Eğer fork’ladıysan orijinal repoya Pull Request göndermeyi unutma, böylece topluluktaki diğerleri de düzeltmenden faydalansın. Ne kadar çok kişi bunu yaparsa, o kadar az bağımlılığa kendin platform desteği eklemen gerekir. 💪

Uygulamayı Simülatörde Test Etmek

Tüm bağımlılıkları düzelttikten sonra uygulamayı derledim ve başarılı oldu! 🥳

Xcodes preview of your app icon.

Ne yazık ki henüz işim bitmemişti. İlk olarak, uygulama açılırken projemde olmasına rağmen uygulama ikonunun gösterilmediğini gördüm. Ayrıca açıldıktan sonra hemen bir sürü başka sorun keşfettim. İşte bir genel bakış:

  • Uygulama İkonu eksikti

  • İmleci (= bakışı) hareket ettirirken bazı yerlerde Hover Şekli yanlıştı

  • Birçok pencere, modal ve UI elemanının Düzen ve Boyutları bozuktu

  • Vurgu Rengim cam arka plan üzerinde okunaklı bir kontrasta sahip değildi

Bu noktaların hepsi visionOS’a geçiş yapan her uygulamayı etkileyecek. Benim için küçük ayarlamalar bunları düzeltmeye yetti. Öğrendiklerimi tek tek paylaşayım.

Uygulama İkonu

Görünüşe göre visionOS’un kendine özgü bir uygulama ikonu stili var. watchOS’taki gibi yuvarlaklar, ama tvOS’taki gibi derinlik hissi yaratmak için birden fazla katmandan oluşuyorlar. + butonuna basıp “visionOS App Icon” seçerek visionOS uygulama ikonu eklersin. Sonra en az 1024 x 1024 boyutunda bir “Front” ve “Back” katman görseli sağlaman gerekiyor. “Middle” katman isteğe bağlı.

Xcodes preview of your app icon.

Benim durumumda uygulama ikonum zaten bir arka plan katmanı ve ön plandaki bir ikondan oluşuyordu, bu yüzden bunları ayrı ayrı dışa aktarmak büyük bir iş değildi. Sadece sağ paneldeki “Middle” katmanı kaldırmam gerekti. Ama ön plan ikonuma gölge uyguladığım için ve Human Interface Guidelines arka plan dışındaki katmanlarda “yumuşak veya bulanık kenarlardan kaçınmamız” gerektiğini belirttiği için gölgeyi kaldırmam gerekti. Sistem, hover sırasında otomatik olarak hafif bir gölge ekleyecek.

Hover’dan bahsetmişken, Xcode üst kısımda uygulama ikonunun nasıl görüneceğinin bir önizlemesini sunuyor ve fareyi üzerine getirdiğinde kullanıcıların Vision Pro’da uygulama ikonuna baktığında oluşacak 3D hover efektini simüle ediyor — gerçekten çok kullanışlı!

Xcodes preview of your app icon.

Xcode’un uygulama ikonu önizlemesi.

Hover Efektleri

visionOS’ta simülatörde gözden kaçırması kolay ama cihazı gerçekten kullanırken son derece önemli olan şeylerden biri düzgün hover efektleri. Cihazda elemanları gözlerinle seçtiğin için, uygulamanın hangi elemanın seçili olduğu hakkında geri bildirim vermesi önemli. Bu, SwiftUI’deki String tabanlı kontrol API’leriyle kutudan çıktığı gibi harika çalışıyor — örneğin Button("Click me") { ... }.

Ama bir butona özel bir label parametresi verdiğinde veya tamamen kendi kontrollerini kullandığında, kontrolünün tam şeklini sisteme sağlaman gerekecek. Örneğin, sadece 2-4 seçenek olduğunda varsayılan açılır Picker yerine kullandığım HPicker adlı özel bir kontrolüm var. Bir seçeneğin üzerine geldiğinde şöyle görünüyordu:

My custom HPicker view without any Hover Effect adjustments.

Hiçbir Hover Efekti ayarı yapılmamış özel HPicker görünümüm.

Seçeneklerin şeklini takip edecek şekilde ayarlamak yeterince kolaydı:

Button {
   // ...
} label: {
   Label(option.description, systemImage: option.symbolSystemName)
      // ...
      .clipShape(.rect(cornerRadius: 12.5))
      #if !os(macOS)
      .contentShape(.hoverEffect, .rect(cornerRadius: 12.5))
      .hoverEffect()
      #endif
}

HPicker bileşenimdeki butonların basitleştirilmiş versiyonu.

.contentShape ve .hoverEffect modifier’ları düzgün bir hover efekti için eklediklerim. .rect(cornerRadius: 12.5) kısmını kendi özel kontrolünün şekliyle değiştir. Bunları #if !os(macOS) kontrolüne sardığıma dikkat et çünkü uygulamam macOS’u destekliyor ama .hoverEffect macOS’ta mevcut değil. Ayrıca bu modifier’ları Button’ın dışına koymak bende işe yaramadı, düzgün çalışması için label tanımının içine yerleştirilmeleri gerekiyor.

Bazı durumlarda beklemediğin yerde hover efekti olduğunu fark edebilirsin. Benim için bu, zaten kontrol olarak tanınan başka bir view’ın içinde bir Button sağladığım durumlarda oldu — şu DisclosureGroup gibi:

The entire

Tüm “Show Clues” satırı bir buton, ama içindeki buton başka bir buton.

Hover efektini sadece .hoverEffectDisabled() modifier’ını ekleyerek kapatabilirsin. Yukarıdaki durumumda, iç buton sadece macOS için eklenmişti (çünkü DisclosureGroup o platformda etikete basıldığında değişmiyor). Bu yüzden çözümüm, sadece macOS’ta Button kullanmak, diğerlerinde ise basit bir Label kullanmak oldu.

Tüm kontrollerin düzgün hover efektine sahip olmasını sağlamak aslında geçişin en çok zaman alan kısmıydı ve yaklaşık 40 dakika sürdü. Projemde SwiftUI önizlemeleri çalışsaydı muhtemelen çok daha hızlı olurdu, ama nedense bende derlenmiyorlardı ve denediğimde Mac’im donmaya başlıyordu. 🤷‍♂️

Yerleşim Sistemi

visionOS, iPadOS tabanlı olduğu için Form view’ları gibi şeyleri iPad’e benzer şekilde render etse de, iOS/iPadOS’a kıyasla yerleşim sisteminde aslında önemli bir fark olduğunu anlamak gerekiyor:

A person’s field of view inside the Apple Vision Pro. Source: HIG

Apple Vision Pro içindeki bir kişinin görüş alanı. Kaynak: HIG

Apple Vision uygulamalarında sonsuz bir tuval üzerinde açılıyor, view’larının boyutunu türetebileceği sabit bir ekran genişliği veya yüksekliği yok. Bu, anlamanı gereken önemli bir fark. macOS için uygulama geliştirdiysen bu farkı zaten biliyorsundur. Birçok açıdan yerleşim sistemi, monitörlerin farklı boyutlara sahip olabildiği ve pencerelerin iOS ve iPadOS’taki gibi nadiren tam ekran açıldığı macOS’unkine çok daha yakın.

Yani uygulamanız zaten macOS’u destekliyorsa, boyutlandırma veya pencere yönetimi söz konusu olduğunda muhtemelen zaten çok sayıda olan #if os(macOS) dallarını tercih edebilirsin. Sadece #if os(macOS) || os(visionOS) ile değiştir.

macOS’a kıyasla bile temel fark, pencerelerin büyük köşe yarıçapına sahip yuvarlatılmış köşeleri olması. Bu yüzden pencere kök view’larıma ekstra padding eklemem gerektiğini fark ettim — örneğin .padding(.vertical, 10) kullanarak.

Uygulamanı henüz macOS için optimize etmediysen, işte bazı önemli öğrenimler:

  • View’lerin için her yerde .frame(minWidth: 400, minHeight: 300) sağlaman gerekiyor, aksi takdirde pencerelerin veya modalların arayüzün için çalışmayan boyutlarda olabilir. Hepsini kontrol et ve uygun değerleri sağla.

  • View’lerin için minWidth ve minHeight belirlemen gerekirken — böylece kullanıcılar bunları içeriğin için çok küçük olacak şekilde yeniden boyutlandıramasın — ek olarak WindowGroup sahnesinde minimumdan daha büyük bir varsayılan boyut için .defaultSize(width: 800, height: 600) sağlamak isteyebilirsin.

  • Tüm ekranı kaplayan ve bu alana ihtiyaç duyan modal view’lerin varsa, bu modalları kendi pencerelerine taşımayı düşünmelisin. visionOS’ta (ve macOS’ta) yeni pencereler açmak için @Environment(\.openWindow) var openWindow property’sini kullan ve ek WindowGroup view’ları belirt. Daha fazla bilgi için SwiftUI 4’te pencere yönetimi hakkındaki yazıma bak.

  • İlk geçişin için harici pencereler yerine — ki bu doğru çözüm olurdu — modalları korumayı tercih edebilirsin. Ama macOS’tan farklı olarak, visionOS’ta modal sheet’ler yeniden boyutlandırılabilir değil. Bu yüzden en azından modalda gösterilecek her türlü dinamik veri için iyi çalışacak bir boyut sağladığından emin ol. CrossCraft’ta “bulmaca oynama” için ben bunu yaptım.

Renkler

Beyaz arka planlı kontrollerin hover efektiyle iyi çalışmayacağını unutma, çünkü efekt beyaz bir kaplama kullanıyor. Beyaz üzerine beyaz görünmez. Bulmaca oyun modumda bununla karşılaştım — kullanıcılar karakter girmek için karolara basıyor. İmlecin bir karonun üzerinde olduğuna ama hover’ın görünmediğine dikkat et:

Hovers are not visible on white background buttons.

Hover’lar beyaz arka planlı butonlarda görünmüyor.

Hızlı çözümüm beyaz arka planlarıma .opacity(0.85) modifier’ını ekleyerek %15 şeffaf yapmak oldu — bu bile yetti. Daha fazlası daha iyi olurdu ama beyaz beklenen bir “bulmaca” rengi olduğu için mümkün olduğunca beyaz tutmaya çalıştım.

Colors that are legible on iOS might not work on visionOS.

iOS’ta okunaklı olan renkler visionOS’ta çalışmayabilir.

Ayrıca sistem varsayılanı olan “mavi” vurgu rengi dahil birçok orta kontrastlı rengin, varsayılan pencere cam arka planı üzerinde gerçekten kötü bir kontrasta sahip olduğunu fark ettim. Bu renkleri visionOS için daha parlak yaptığından emin ol. Attributes inspector’da bir renk seçiliyken “Apple Vision” için özel bir varyant ekleyebilirsin.

Colors

💡 HSB sistemi ile bir rengi daha parlak yapmak için doygunluğu biraz azaltman ve parlaklığı önemli ölçüde artırman gerekiyor. Ek olarak tonu en yakın parlak RGB değerine doğru biraz kaydırabilirsin. HSB kullanarak renkleri düzgün şekilde daha parlak/koyu yapmak hakkında daha fazla bilgi için bu makaleye bak.

Sonuç

Uygulamanız zaten iPadOS ve macOS’taysa, visionOS desteği eklemek için çok iyi bir konumdasın. Tüm SwiftUI kodunu yeniden kullanabilirsin. Pencere yönetimi söz konusu olduğunda macOS versiyonunu tercih et. Diğer her şey için iPadOS versiyonunu tercih et. Sonra tüm özel kontrollerinin düzgün bir hover efektine sahip olduğundan emin ol. Padding eklemek, renkleri daha parlak yapmak veya uygulama ikonunu ön ve arka parçalara bölmek gibi bazı düzen ve arayüz ayarlamaları yap.

Tüm süreç benim için toplamda 2 saat sürdü. Tüm süreci canlı yayınladım, “derleme bekleme” ve “sohbet” kısımları çıkarılmış kayıtlarımı aşağıdaki iki YouTube videosunda bulabilirsin — her biri yaklaşık bir saat uzunluğunda. Yukarıda belirtilen farklı adımlar için zaman kodları eklediğimi de belirteyim, böylece belirli konulara dalabilirsin:

Bu yazıyı beğendin mi? Swift ipuçları ve indie geliştirici güncellemeleri için Bluesky ve Mastodon üzerinden takip et.