Flutter ile Çalışırken Yaygın Platformlar Arası Sorunları Çözme

Yayınlanan: 2022-03-10
Kısa özet ↬ Platformlar arası çerçeveleri kullanırken, insanlar kodlarının üzerinde çalışmasını istedikleri platformların her birinin nüanslarını unutabilirler. Bu makale bunu ele almayı amaçlamaktadır.

Flutter ile Web geliştirme konusunda çevrimiçi olarak çok fazla kafa karışıklığı gördüm ve çoğu zaman ne yazık ki yanlış nedenlerle.

Spesifik olarak, insanlar bazen onu, temelde yalnızca bir sarmalayıcı uygulama içinde çalışan tarayıcılarda çalışan Web sayfaları olan eski Web tabanlı mobil (ve masaüstü) çapraz platform çerçeveleriyle karıştırır.

Bu, arayüzlerin zaten aynı olması anlamında gerçekten çapraz platformdu çünkü yalnızca Web'de normal olarak erişilebilen arayüzlere erişiminiz vardı.

Ancak Flutter öyle değil: her platformda yerel olarak çalışır ve bu, her uygulamanın Java/Kotlin veya Android ve iOS'ta Objective-C/Swift ile yazılmışsa çalışacağı gibi çalıştığı anlamına gelir. Bunu bilmeniz gerekir çünkü bu, bu çok çeşitli platformlar arasındaki birçok farklılığa dikkat etmeniz gerektiği anlamına gelir.

Bu yazıda, bu farklılıklardan bazılarını ve bunların üstesinden nasıl gelineceğini göreceğiz. Daha spesifik olarak, çapraz platform olmak istedikleri Flutter kodunu yazarken geliştiricilerin kafa karışıklığına neden olan depolama ve UI farklılıklarından bahsedeceğiz.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

Örnek 1: Depolama

Kısa süre önce blogumda JWT'leri mobil uygulamalara kıyasla Web uygulamalarında depolamak için farklı bir yaklaşıma duyulan ihtiyaç hakkında yazdım.

Bunun nedeni, platformların depolama seçeneklerinin farklı doğası ve her birini ve kendi yerel geliştirme araçlarını bilme ihtiyacıdır.

Bir Web uygulaması yazdığınızda, sahip olduğunuz depolama seçenekleri şunlardır:

  1. Kullanıcı etkileşimi gerektiren ve bu nedenle yalnızca kullanıcı tarafından okunması veya oluşturulması amaçlanan dosyalar için uygun olan dosyaları diske/diskten indirme/yükleme;
  2. JS'den erişilebilen veya erişilemeyen ( httpOnly olup olmadıklarına bağlı olarak) ve belirli bir etki alanına isteklerle birlikte otomatik olarak gönderilen ve bir yanıtın parçası olarak geldiklerinde kaydedilen çerezleri kullanmak;
  3. JS localStorage ve sessionStorage kullanarak, web sitesindeki herhangi bir JS tarafından erişilebilir, ancak yalnızca o web sitesinin sayfalarının bir parçası olan JS'den erişilebilir.

mobil

Mobil uygulamalar söz konusu olduğunda durum tamamen farklıdır. Depolama seçenekleri şunlardır:

  1. o uygulama tarafından erişilebilen yerel uygulama belgeleri veya önbellek deposu;
  2. kullanıcı tarafından oluşturulan/okunabilir dosyalar için diğer yerel depolama yolları;
  3. Anahtar/değer depolaması için sırasıyla iOS ve Android'de NSUserDefaults ve SharedPreferences ;
  4. Sırasıyla herhangi bir verinin ve şifreleme anahtarının güvenli bir şekilde saklanması için iOS'ta Keychain ve KeyStore .

Bunu bilmiyorsanız, gerçekte hangi depolama çözümünü kullandığınızı ve avantaj ve dezavantajlarının neler olduğunu bilmeniz gerektiğinden, uygulamalarınızı alt üst edeceksiniz.

Platformlar Arası Çözümler: İlk Yaklaşım

Flutter shared_preferences paketini kullanmak Web'de localStorage , Android'de SharedPreferences ve iOS'ta NSUserDefaults kullanır. Bunların uygulamanız için tamamen farklı etkileri vardır, özellikle de oturum belirteçleri gibi hassas bilgileri saklıyorsanız: localStorage istemci tarafından okunabilir, bu nedenle XSS'ye karşı savunmasızsanız bu bir sorundur. Mobil uygulamalar XSS'ye karşı gerçekten savunmasız olmasa da, SharedPreferences ve NSUserDefaults güvenli depolama yöntemleri değildir çünkü güvenli depolama olmadıkları ve şifrelenmedikleri için istemci tarafında tehlikeye atılabilirler. Bunun nedeni, burada iOS durumunda ve burada Android belgelerinde, SharedPreferences sarmalayıcılar sağlamak üzere tasarlanmış Güvenlik kitaplığı hakkında konuşurken, özellikle verileri depolamadan önce şifrelemek için belirtildiği gibi, kullanıcı tercihleri ​​içindir.

Mobilde Güvenli Depolama

Mobil cihazlarda tek güvenli depolama çözümleri sırasıyla iOS ve Android'de Keychain ve KeyStore , oysa Web'de güvenli depolama yoktur .

Keychain ve KeyStore , doğası gereği çok farklıdır: Keychain , genel bir kimlik bilgileri depolama çözümüdür, oysa KeyStore , simetrik anahtarlar veya genel/özel anahtarlar gibi şifreleme anahtarlarını depolamak (ve üretebilir) için kullanılır.

Bu, örneğin, bir oturum jetonunu depolamanız gerekiyorsa, iOS'ta işletim sisteminin şifreleme bölümünü yönetmesine ve jetonunuzu Keychain göndermesine izin verebilirsiniz, oysa Android'de ihtiyacınız olduğu için biraz daha manuel bir deneyimdir. bir anahtar oluşturmak (sabit kod değil, bu kötü) için, belirteci şifrelemek için kullanın, şifrelenmiş belirteci SharedPreferences saklayın ve anahtarı KeyStore .

Güvenlikle ilgili çoğu şey gibi buna da farklı yaklaşımlar vardır, ancak uygulamanız belirteci hem şifrelediğinden hem de şifresini çözdüğünden ortak anahtar şifrelemesine gerek olmadığından en basiti muhtemelen simetrik şifreleme kullanmaktır.

Açıkçası, örneğin hepsini yapan bir Flutter eklentisi olduğu için, bunların hepsini yapan mobil platforma özel kod yazmanıza gerek yok.

Web'de Güvenli Depolamanın Eksikliği

Aslında beni bu yazıyı yazmaya iten sebep de buydu. JWT'yi mobil uygulamalarda depolamak için bu paketi kullanma hakkında yazdım ve insanlar bunun Web sürümünü istediler ama dediğim gibi Web'de güvenli depolama yok . Bu yok.

Bu, JWT'nizin açıkta olması gerektiği anlamına mı geliyor?

Hayır, hiç de değil. httpOnly çerezlerini kullanabilirsiniz, değil mi? Bunlara JS tarafından erişilemez ve yalnızca sunucunuza gönderilir. Bununla ilgili sorun, kullanıcılarınızdan biri başka birinin web sitesindeki bir GET isteği URL'sini tıklasa ve bu GET isteğinin sizin veya kullanıcınızın hoşlanmayacağı yan etkileri olsa bile, her zaman sunucunuza gönderilmeleridir. Bu aslında diğer istek türleri için de geçerlidir, sadece daha karmaşıktır. Buna Siteler Arası İstek Sahteciliği denir ve bunu istemezsiniz. Daha eksiksiz bir açıklama bulabileceğiniz Mozilla'nın MDN belgelerinde bahsedilen web güvenlik tehditleri arasındadır.

Önleme yöntemleri var. En yaygın olanı iki jetona sahip olmaktır, aslında: bunlardan biri istemciye httpOnly çerezi olarak ulaşır, diğeri ise yanıtın bir parçası olarak. İkincisi, sunucuya otomatik olarak gönderilmesini istemediğimiz için çerezlerde değil localStorage saklanmalıdır.

Her ikisini de çözme

Hem mobil uygulamanız hem de Web uygulamanız varsa ne olur?

Bu iki yoldan biriyle halledilebilir:

  1. Aynı arka uç uç noktasını kullanın, ancak tanımlama bilgileriyle ilgili HTTP başlıklarını kullanarak tanımlama bilgilerini manuel olarak alın ve gönderin;
  2. Web uygulaması tarafından kullanılan belirteçlerden farklı belirteç oluşturan ayrı bir Web dışı arka uç uç noktası oluşturun ve ardından istemci yalnızca mobil belirteci sağlayabiliyorsa düzenli JWT yetkilendirmesine izin verin.

Farklı Platformlarda Farklı Kod Çalıştırmak

Şimdi, farklılıkları telafi edebilmek için farklı platformlarda farklı kodları nasıl çalıştırabileceğimizi görelim.

Flutter Eklentisi Oluşturma

Özellikle depolama sorununu çözmek için bunu bir eklenti paketi ile yapabilirsiniz: Eklentiler ortak bir Dart arabirimi sağlar ve yerel platforma özel Kotlin/Java veya Swift/Objective-C kodu dahil olmak üzere farklı platformlarda farklı kodlar çalıştırabilir. . Paketler ve eklentiler geliştirmek oldukça karmaşıktır, ancak resmi Flutter belgeleri de dahil olmak üzere Web'de ve başka yerlerde (örneğin Flutter kitaplarında) birçok yerde açıklanmıştır.

Örneğin, mobil platformlar için zaten bir güvenli depolama eklentisi var ve bu flutter_secure_storage , burada bir kullanım örneğini bulabilirsiniz, ancak bu örneğin Web'de çalışmaz.

Öte yandan, web'de de çalışan basit anahtar/değer depolaması için, NSUserDefaults , SharedPreferences veya localStorage kullanan shared_preferences adlı Web'e özgü bir bileşene sahip olan, shared_preferences_web adlı, Google tarafından geliştirilen, platformlar arası bir birinci taraf eklenti paketi vardır. platforma bağlı olarak.

Flutter'da TargetPlatform

package:flutter/foundation.dart dosyasını içe aktardıktan sonra, Theme.of(context).platform değerlerle karşılaştırabilirsiniz:

  • TargetPlatform.android
  • TargetPlatform.iOS
  • TargetPlatform.linux
  • TargetPlatform.windows
  • TargetPlatform.macOS
  • TargetPlatform.fuchsia

ve desteklemek istediğiniz her platform için uygun olanı yapacak şekilde işlevlerinizi yazın. Bu, özellikle bir sonraki platform farkı örneği için faydalı olacaktır ve bu, widget'ların farklı platformlarda nasıl görüntülendiğine ilişkin farklılıklardır.

Özellikle bu kullanım durumu için, platforma duyarlı widget'ların geliştirilmesini basitleştiren oldukça popüler bir flutter_platform_widgets eklentisi de vardır.

Örnek 2: Aynı Widget'ın Görüntülenme Şeklindeki Farklılıklar

Android ve iOS uygulamanızın bir WebView olmasını ve masaüstü uygulamanızın Electron ile oluşturulmasını istemiyorsanız, yalnızca platformlar arası kod yazıp tarayıcı, telefon, bilgisayar ve akıllı saatin aynı şey olduğunu iddia edemezsiniz. . Bunu yapmamak için pek çok neden var ve bu parçanın amacı, sizi Flutter gibi uygulamanızı yerel tutan, beraberinde gelen tüm performans ve kullanıcı deneyimi avantajlarıyla birlikte yerel tutan ve size izin veren Flutter gibi çerçeveleri kullanmaya ikna etmek değil. çoğu zaman tüm platformlar için aynı olacak kod yazın.

Bu, özen ve dikkat gerektirir ve en azından desteklemek istediğiniz platformlar, gerçek yerel API'leri ve tüm bunlar hakkında temel bilgi gerektirir. React Native kullanıcılarının buna daha da fazla dikkat etmesi gerekiyor çünkü bu çerçeve yerleşik işletim sistemi widget'larını kullanıyor, bu nedenle aslında uygulamanın nasıl göründüğüne, aralarında geçiş yapmaksızın, her iki platformda da kapsamlı bir şekilde test ederek daha fazla dikkat etmeniz gerekiyor. Flutter ile mümkün olduğu gibi anında iOS ve Malzeme widget'ı.

İsteğiniz Olmadan Ne Değişir

Uygulamanızın kullanıcı arayüzünün, platform değiştirdiğinizde otomatik olarak değişen bazı yönleri vardır. Bu bölüm ayrıca Flutter ve React Native arasında bu açıdan nelerin değiştiğinden bahseder.

Android ve iOS Arasında (Flutter)

Flutter, iOS'ta (ve Android'de Cupertino (iOS benzeri) widget'larda) Malzeme widget'ları oluşturma yeteneğine sahiptir, ancak YAPMADIĞI şey, Android ve iOS'ta tamamen aynı şeyi göstermektir: Malzeme teması, özellikle her platformun kurallarına uyarlanır .

Örneğin, gezinme animasyonları ve geçişleri ve varsayılan yazı tipleri farklıdır, ancak bunlar uygulamanızı çok fazla etkilemez.

Estetik veya UX söz konusu olduğunda bazı seçimlerinizi etkileyebilecek şey, bazı statik öğelerin de değişmesidir. Spesifik olarak, bazı simgeler iki platform arasında değişir, uygulama çubuğu başlıkları iOS'ta ortada ve Android'de soldadır (bir geri düğmesi veya bir Çekmece açma düğmesi olması durumunda kullanılabilir alanın solunda (burada açıklanmıştır) Materyal Tasarımı yönergelerinde ve hamburger menüsü olarak da bilinir.) Çekmeceli bir Materyal uygulaması Android'de şöyle görünür:

Flutter Android Material uygulamalarında uygulama çubuğu başlığının nerede göründüğünü gösteren bir Android uygulamasının resmi
Android'de çalışan malzeme uygulaması: AppBar başlığı, kullanılabilir alanın sol tarafındadır. (Büyük önizleme)

Ve aynı, çok basit Material uygulaması iOS'ta nasıl görünüyor:

Flutter iOS Material uygulamalarında uygulama çubuğu başlığının nerede göründüğünü gösteren bir iOS uygulamasının resmi
iOS'ta çalışan malzeme uygulaması: AppBar başlığı ortada. (Büyük önizleme)

Mobil ve Web Arasında ve Ekran Çentikleri ile (Flutter)

Flutter ile Duyarlı Web Geliştirme hakkındaki bu Çarpıcı makalede de belirtildiği gibi, Web'de biraz farklı bir durum var: özellikle, daha büyük ekranlar için optimize etmek ve insanların sitenizde gezinmeyi bekledikleri yolu hesaba katmak zorunda olmanın yanı sıra - bu makalenin ana odak noktası budur - bazen pencere öğelerinin tarayıcı penceresinin dışına yerleştirildiği konusunda endişelenmeniz gerekir. Ayrıca, bazı telefonların ekranlarının üst kısmında çentikler veya bir tür engel nedeniyle uygulamanızın doğru görüntülenmesini engelleyen başka engeller bulunur.

Bu sorunların her ikisi de, widget'larınızı, kullanıcıların görme yeteneğini hiçbir şey engellemeden gerçekten görüntülenebilecekleri bir yere düşmelerini sağlayan belirli bir dolgu widget'ı türü olan bir SafeArea widget'ına sararak önlenebilir, bir donanım veya yazılım kısıtlaması olsun.

React Native'de

React Native, uygulamanızı her iki platformda da test edebilmek için en azından iOS Simulator'ı ve Android Emulator'ı çalıştırmanızı gerektirmenin yanı sıra, her platform hakkında çok daha fazla dikkat ve çok daha derin bir bilgi gerektirir. aynıdır ve JavaScript UI öğelerini platforma özel widget'lara dönüştürür. Başka bir deyişle, React Native uygulamalarınız her zaman iOS gibi görünecek - bazen adlandırıldığı gibi Cupertino UI öğeleriyle - ve Android uygulamalarınız her zaman normal Materyal Tasarımı Android uygulamaları gibi görünecek çünkü platformun widget'larını kullanıyor.

Buradaki fark, Flutter'ın widget'larını kendi düşük seviyeli oluşturma motoruyla oluşturmasıdır; bu, her iki uygulama sürümünü de tek bir platformda test edebileceğiniz anlamına gelir.

Bu Sorunu Çözmek

Çok özel bir şey için gitmiyorsanız, uygulamanızın farklı platformlarda farklı görünmesi gerekiyor, aksi takdirde bazı kullanıcılarınız mutsuz olacaktır.

Tıpkı bir mobil uygulamayı web'e göndermemeniz gerektiği gibi (yukarıda bahsedilen Smashing gönderisinde yazdığım gibi), örneğin Android kullanıcılarına Cupertino widget'larıyla dolu bir uygulama göndermemelisiniz, çünkü bu, kullanıcılar için kafa karıştırıcı olacaktır. çoğu kısmı. Öte yandan, başka bir platforma yönelik widget'lara sahip bir uygulamayı gerçekten çalıştırma şansına sahip olmak, uygulamayı test etmenize ve bunun için iki cihaz kullanmanıza gerek kalmadan her iki sürümde de insanlara göstermenize olanak tanır.

Diğer Taraf: Doğru Nedenlerle Yanlış Widget'ları Kullanmak

Ancak bu aynı zamanda, Flutter geliştirmenizin çoğunu iOS kullanıcılarınızın deneyiminden ödün vermeden bir Linux veya Windows iş istasyonunda yapabileceğiniz ve ardından uygulamayı diğer platform için oluşturabileceğiniz ve kapsamlı bir şekilde test etme konusunda endişelenmenize gerek olmadığı anlamına gelir.

Sonraki adımlar

Platformlar arası çerçeveler harikadır, ancak her bir platformun nasıl çalıştığını ve uygulamanızın kullanıcılarınız için nasıl uyarlanacağını ve kullanımının hoş olduğundan nasıl emin olacağınızı anlama sorumluluğunu geliştiriciye bırakırlar. Göz önünde bulundurulması gereken diğer küçük şeyler, örneğin, farklı platformlarda farklı sözleşmeler varsa, özünde aynı şeyin ne olabileceğine ilişkin farklı açıklamalar kullanmak olabilir.

Farklı diller kullanarak iki (veya daha fazla) uygulamayı ayrı ayrı oluşturmak zorunda kalmamak harika, ancak yine de özünde birden fazla uygulama oluşturduğunuzu ve bu, oluşturduğunuz uygulamaların her biri hakkında düşünmeyi gerektirdiğini unutmayın. .

Diğer Kaynaklar

  • Flutter Galerisi web sitesi ve Android uygulaması, farklı platformlara özgü Flutter widget'larının kullanımını ve platform bilinemezciliğini sergiliyor
  • TargetPlatform'da Flutter API Belgeleri
  • Paketlerin ve eklentilerin oluşturulmasına ilişkin Flutter belgeleri
  • Platform uyarlamaları hakkında Flutter belgeleri
  • Çerezlerle ilgili MDN belgeleri