pushlio_flutter 0.1.11 copy "pushlio_flutter: ^0.1.11" to clipboard
pushlio_flutter: ^0.1.11 copied to clipboard

Pushlio push notification SDK — device registration, rich notifications, delivered/opened receipts, deep links, feature flags and in-app messages.

Changelog #

0.1.11 #

register: 8 saatlik TTL — ama SADECE payload değişmediyse #

Canlıda register her cold start'ta koşulsuzca ağa gidiyordu; ingest trafiğinin en büyük payı buydu. Artık son gönderilen cihaz bilgisi (token/versiyon/dil/izin/kimlik — hepsi) BİREBİR AYNIYSA ve son gönderimden bu yana 8 saat geçmediyse ağa hiç gidilmiyor.

Kritik nokta: bu bir "8 saatte bir gönder" değil, "değişmediyse VE 8 saat içindeyse atla" mantığı. Push token rotasyonu, versiyon güncellemesi, dil/ saat dilimi değişikliği gibi GERÇEK bir fark varsa TTL tamamen görmezden gelinip hemen gönderiliyor — özellikle token değişince sunucuda ölü bir token'ın saatlerce kalmaması için bu şart. 404 device_not_found kurtarma yolu da force: true ile bu korumayı atlıyor (yerel önbellek "gönderildi" sansa bile sunucudaki satır silinmiş olabilir).

Panel etkisi: Cihaz listesindeki "son görülme" artık dakika değil, en fazla 8 saat hassasiyetinde — aynı cihaz bilgisiyle art arda açılan bir kullanıcı için last_seen bu pencere içinde tazelenmeyebilir. Bilinçli bir denge: ürün kararı, hassasiyeti trafik tasarrufuna feda etti.

0.1.10 #

Remote config artık Pro plana özel #

syncConfig() her cihazda (Free dahil) ağa gidiyordu — flag/A-B testi sistemi zaten ürün olarak Pro'ya özel niyetlenmişti ama SDK bunu hiç zorlamıyordu. register yanıtı artık config_enabled (org planı) da taşıyor; SDK bunu yerelde saklayıp Free planda syncConfig()'i ağa hiç göndermeden atlıyor. Alan okunamazsa (eski sunucu, ayrıştırma sorunu) güvenli varsayılan true — bir ayrıştırma hatası yüzünden Pro bir müşterinin flag'leri sessizce kesilmez.

PushlioApi.register() artık bool yerine RegisterResult({ok, configEnabled}) dönüyor — bu tamamen iç bir sınıf (host uygulamalar hiç görmez), Pushlio sınıfının genel API'sinde bir değişiklik yok.

0.1.9 #

syncConfig: 12 saatlik TTL cache #

Canlı log analizinde /ingest/config, register'dan sonra ingest'in en sık çağrılan ikinci ucu çıktı — her cold start'ta (_warmup() içinde) koşulsuzca ağa gidiyordu. Aynı gün art arda açılıp kapanan bir uygulamada bu, flag'ler hiç değişmese bile her seferinde tam bir istek demekti.

Artık syncConfig() son başarılı çekimden bu yana 12 saat geçmediyse ağa hiç gitmiyor, mevcut önbelleği kullanıyor (otomasyonlardaki "N saattir aktif olmayan kullanıcı" eşikleriyle aynı mertebe; Firebase Remote Config'in prod varsayılanı da 12 saat). Anında tazelik gerekiyorsa (örn. bir "yenile" butonu) syncConfig(force: true) bu korumayı atlar. Varsayılan davranış (parametresiz çağrı) geriye dönük uyumlu — sadece artık gereksiz ağ isteği atmıyor.

0.1.8 #

login/logout: aynı kimlikle tekrar çağrılınca ağa gitmiyor #

Pushlio.login(id) koşulsuzca /ingest/user'a POST atıyordu — host uygulama bunu her resume'da ya da her auth-state event'inde (örn. Firebase Auth'un authStateChanges() akışı token yenilenince de tetikleniyor, sadece gerçek login/logout'ta değil) aynı id ile çağırırsa, her seferinde gereksiz bir istek gidiyordu. Canlıda bunun etkisini görmek kolay oldu: /ingest/user tek başına registerden bile daha sık çağrılan uç oldu.

Artık login/logout idempotent: istenen kimlik zaten sunucuya ulaşmışsa (PushlioIdentity.desired() == verilen id VE synced() true) ağ isteği hiç atılmıyor. Kimlik gerçekten değiştiğinde ya da önceki senkron başarısız kaldığında davranış aynı — sadece tekrarlanan no-op çağrılar artık bedelsiz.

0.1.7 #

Eşzamanlı 404'te sessiz veri kaybı düzeltildi #

0.1.6'nın özyineleme koruması (_recovering bayrağı) yan etki getirmişti: kurtarma sürerken 404 alan İKİNCİ çağrı beklemeden false dönüyordu. setTags/setSubscribed kuyruksuz olduğundan bu kalıcı kayıptı — init warmup'ı bitmeden login + setTags çağıran host'ta tag yutuluyordu.

Şimdi eşzamanlı 404'ler tek kurtarma Future'ını paylaşıyor: ikinci çağrı kurtarmayı bekleyip kendi isteğini bir kez tekrar deniyor. Özyineleme koruması bayraktan yapısal çözüme taşındı: kurtarma içindeki uzlaştırma recover: false ile düz yola iner, kancaya dönecek yol hiç kalmaz.

0.1.7 #

androidLargeIcon: bildirim panelinde uygulama ikonu #

Durum çubuğu ikonu Android kuralı gereği tek renk siluet olmak zorunda — SystemUI siluet olmayan her şeyi düz gri lekeye çevirir. Markayı taşıyan RENKLİ uygulama ikonunun yeri panelin sağındaki BÜYÜK ikondur ve SDK bunu hiç desteklemiyordu: kampanya bildirimleri yalnızca soluk küçük ikonla çiziliyordu.

Pushlio.init(androidLargeIcon: '@mipmap/ic_launcher') bunu açar. Varsayılan null'dur (davranış değişmez). Kampanya görseli olan bildirimde görselin küçük hali kazanmaya devam eder — orada bilgi taşıyan odur. Değer kalıcı konfigürasyona yazılır; uygulama kapalıyken arka plan isolate'inin çizdiği bildirim de büyük ikonu alır.

0.1.6 #

Kurtarma yolunda sonsuz özyineleme kapatıldı #

0.1.5'te eklenen 404 kurtarması karşılıklı özyinelemeye açıktı: onDeviceMissing_register → bekleyen logout varsa setExternalUserId(null) → o da _post'tan geçtiği için 404'te kancayı YENİDEN tetikliyordu. register_rawe bağlamak bu yolu kapatmıyordu. Artık yeniden giriş bayrağı var.

0.1.5 #

Kullanıcı kimliği yarışı kapatıldı #

0.1.4'te init ağı beklemeyi bıraktı (açılışta 10-30 sn donmayı bu çözdü). Ama kayıt arka plana alınınca şu yarış açıldı:

await Pushlio.init(...);   // kayıt ARKA PLANDA başlar
await Pushlio.login(uid);  // POST /user — cihaz satırı HENÜZ YOK

Sunucudaki ingest_set_external düz bir UPDATE'tir; satır yoksa 0 satır günceller ve uç nokta 404 device_not_found döner. Bu hata yutuluyor, kimlik hiçbir yere yazılmıyor ve kayıt onu göndermiyordu — yani cihaz-kullanıcı bağlantısı KALICI olarak kayboluyordu. Oturumu açık kullanıcı her açılışta aynı yarışı kaybettiği için cihaz hiçbir zaman bağlanmıyordu.

İki savunma hattı eklendi:

  1. Kimlik yerelde saklanır ve KAYIT PAYLOAD'UNDA taşınır. Sunucudaki upsert external_user_id = coalesce(excluded.external_user_id, devices.external_user_id) olduğu için sıra artık önemsiz: kayıt önce biterse POST /user zaten başarılı olur, login önce olursa kaydın kendisi kimliği taşır. Zamanlama hilesi değil, yapısal çözüm.
  2. 404 device_not_found alan istek kaydı zorlayıp BİR KEZ tekrar dener. Bu yarışın dışındaki sebepleri de toparlar (ör. cihaz panelden silinmiş). Ağ hatasıyla karıştırılmaz; kayıt da başarısızsa döngüye girilmez.

logout de artık kalıcı: ağ yoksa niyet saklanır ve bir sonraki başarılı kayıttan sonra iletilir (kayıt payload'u null göndererek bağlantıyı kaldıramaz — coalesce eskisini korur).

Aynı sorun setTag, trackEvent ve setSubscription çağrılarını da vuruyordu; 404 kurtarması hepsini kapsıyor.

Soğuk açılışta çift ekran açılması giderildi #

onOtherNotificationTap artık SOĞUK AÇILIŞ dokunuşlarını host'a iletmiyor.

Yalnız KIRDIĞIMIZI telafi ederiz:

  • sıcak yol (onNewIntent → tap handler): initialize() çağrımız host'un handler'ını EZER → geri vermek zorundayız. Değişmedi.
  • soğuk yol (getNotificationAppLaunchDetails): pull API'dir, initialize'dan bağımsızdır — host'tan hiçbir şey almadık.

Soğuk yolda da iletmek, kendi getNotificationAppLaunchDetails() okumasını yapan host'ta aynı dokunuşun İKİ kez işlenmesine yol açıyordu: hedef ekran üst üste iki kez açılıyordu. O çağrı intent'i tüketmediği (saf okuma) için SDK içinde dedupe yapmak imkânsız — host'un kendi okumasını bastıramayız.

getNotificationAppLaunchDetails() ÇAĞIRMAYAN uygulamalar bir yetenek kaybetmez: flutter_local_notifications cold-start dokunuşunu zaten onDidReceiveNotificationResponse'a hiç göndermez (eklentinin kendi README'si: "This callback cannot be used to handle when a notification launched an app"). O dokunuşa erişmenin tek yolu her zaman getNotificationAppLaunchDetails() olmuştur.

test/host_isolation_test.dart bu ayrımı çiviliyor (SICAK iletilir, SOĞUK iletilmez), test/identity_race_test.dart ise kimlik yarışının iki hattını.

0.1.4 #

Bu sürüm iki şeyi birden getiriyor: paketin kurulabilir olması ve host izolasyonu. İkincisi 0.1.4 olarak hazırlanmıştı ama hiç yayınlanmadı — çünkü paket o haliyle kurulamıyordu.

Kurulum engeli kaldırıldı (0.1.0-0.1.3'ün hepsini etkiliyordu) #

  • environment.sdk ^3.11.3 idi — bu, paketi geliştirme makinesinin Dart sürümüne kilitliyordu (flutter create damgası olduğu gibi kalmıştı). Mart 2026'dan eski her Flutter'da flutter pub add pushlio_flutter ÇÖZÜMLEME aşamasında reddediyordu: müşteri paketi kuramıyordu bile. Artık >=3.8.0 <4.0.0 — alt uçtaki en katı bağımlılığın gerçek gereği (flutter_local_notifications 20.0.0 → ^3.8.0).
  • Tabanı düşürmek körlemesine yapılamazdı: 6 yerde null-aware element ('k': ?x) kullanılıyordu ve o bir Dart 3.9 özelliği — tabanı tek başına yukarı çeken buydu. Klasik if (x != null) 'k': x biçimine çevrildi. use_null_aware_elements lint'i bilinçli olarak kapatıldı (gerekçe analysis_options.yaml içinde yazılı).
  • device_info_plus tabanı >=10.0.0>=10.1.1. 10.0.0 pub.dev'de GERİ ÇEKİLMİŞ; ayrıca 10.0.x web <=0.6.0 isteyip firebase_core ile çakışıyor — yani ilan edilen taban gerçekte hiç ulaşılamıyordu.
  • path_provider >=2.1.4, shared_preferences >=2.3.0, http >=1.2.2: tabanlar birbiriyle tutarlı bir sete çekildi.

Host izolasyonu — Pushlio artık hiçbir koşulda host uygulamayı etkilemez #

Entegrasyon kütüphanesi olarak asıl sözleşmemiz bu; bu sürüm onu baştan sona uyguluyor.

  • init artık fırlatmaz. Önceden gövdesi korumasızdı: Firebase yapılandırılmamışsa, google-services.json eksikse ya da bir platform eklentisi hazır değilse await Pushlio.init(...) istisna atıyordu. runApp()'ten önce çağıran uygulamalar hiç açılmıyordu.
  • init artık ağ beklemez. Cihaz kaydı, makbuz kuyruğu ve flag tazeleme arka plana alındı. Önceden sunucu yavaşsa/erişilemezse açılış ~10-30 sn donabiliyordu (istek başına 10 sn timeout).
  • Hiçbir genel çağrı fırlatmaz. login, logout, setTag(s), removeTag(s), trackEvent, setSubscription, requestPermission, inAppMessages, markInAppSeen, syncConfig, getDeviceUid, getToken — hepsi hata durumunda makul varsayılana döner.
  • Paylaşılan eklenti çakışması giderildi. FlutterLocalNotificationsPlugin bir SINGLETON'dır: initialize() çağrımız host'un tap handler'ını eziyordu. Uygulaman flutter_local_notifications kullanıyorsa kendi yerel bildirim dokunuşların sessizce çalışmaz oluyordu. Yeni init(onOtherNotificationTap:) parametresiyle bize ait olmayan her dokunuş sana geri veriliyor (arka plan isolate'inde de çalışır).
  • Disk hataları izole edildi. SharedPreferences erişimi (makbuz/olay kuyruğu, bekleyen tıklama, flag önbelleği) korumalı; patlarsa makbuz kaybolur, uygulama etkilenmez.
  • Sahipsiz async hata bırakılmıyor. storePendingClick'teki .then() zincirine catchError eklendi; FCM dinleyicileri ve token rotasyonu korumalı sarmalayıcıdan geçiyor.
  • Arka plan mesaj handler'ı korumalı. Yabancı mesajın host handler'ına iletilmesi artık her şeyden önce yapılır: bizim tarafımızdaki bir arıza, senin kendi FCM mesajlarını almanı engelleyemez.
  • Host callback'leri izole. onClick handler'ın patlarsa Pushlio yutar (stream ölmez, uygulama çökmez).
  • Yeni: Pushlio.onError((e, st) {...}) — yutulan hataları kendi crash raporlamana bağlamak için (opsiyonel).
  • Yeni: Pushlio.isReady — yerel kurulum tamamlandı mı (yalnız teşhis).
  • Düzeltme: enableLogs: true iken init log'u değişken yerine literal $deviceUidSync basıyordu (kaçırılmış $).

Yeni: bildirim vurgu rengi #

Pushlio.init(androidAccentColor: 0xFF4CAF50)

  • Renk ARGB int olarak verilir ve AndroidNotificationDetails.color üzerinden Notification.color'a gider. Android bunu bildirim gölgesindeki KÜÇÜK İKONA uygular; durum çubuğundaki ikon her koşulda monokrom kalır, bu yüzden küçük ikon beyaz siluet olmaya devam etmeli.
  • OneSignal'den geçenler için: bu, NotificationAccentColor.DEFAULT meta-data'sının beslediği slotun aynısıdır.
  • Renk PushlioConfig'e kalıcı yazılır, yani uygulama TAMAMEN KAPALIYKEN gelen ve arka plan isolate'inin çizdiği bildirimlerde de uygulanır.
  • Verilmezse davranış değişmez. Eski sürümün yazdığı config okunmaya devam eder (yeni anahtar yoksa renk null).

Test ve korumalar #

  • test/host_isolation_test.dart — hiçbir platform eklentisinin olmadığı ve ağın kapalı olduğu ortamda tüm API'nin sorunsuz tamamlandığını doğrular. Koruma kaldırılırsa test kırmızıya döner.
  • test/config_persistence_test.dart — ensure→load turu, kaldırma, eski config uyumu ve applyConfig aktarımı.
  • scripts/check-flutter-floors.sh yeniden yazıldı: ^ biçimini de görüyor, Dart tabanını denetliyor, geri çekilmiş sürüm arıyor ve en-kötü senaryoyu pub downgrade ile test ediyor (doğru yöntem bu; tek tek tam sürüm sabitlemek sahte hata üretiyordu).
  • Tüm korumalar artık CI'da koşuyor (.github/workflows/sdk-checks.yml), ayrıca en eski desteklenen Flutter'da (3.32 / Dart 3.8) tam test.

0.1.3 #

Fixes a broken dependency floor — upgrade if you saw a build error.

  • flutter_local_notifications lower bound raised to >=20.0.0. 0.1.2 declared >=19.0.0, but the SDK calls the named-parameter API (initialize(settings: …), show(notificationDetails: …)) that only exists from 20.0.0 — apps resolving to 19.x failed to compile with "Too few positional arguments". Reported from a real integration.
  • Added scripts/check-flutter-floors.sh (repo): compiles the package against each declared minimum so a wrong floor can't ship again — flutter analyze alone can't catch it, since it always resolves the newest compatible versions.

0.1.2 #

  • Pushlio.onForegroundMessage(handler) — intercept pushes while the app is in the foreground; return false to suppress the notification and show your own UI (custom dialog etc.). Delivered receipts still flow.
  • Pushlio.reportOpened(n) — count an "opened" when the user acts on your custom foreground UI.
  • init(iosForegroundPresentation:) — set to false to stop the system from showing foreground alerts on iOS (pair with the handler above).

0.1.1 #

Compatibility release driven by real-world integration feedback.

  • Widened dependency ranges so the SDK installs next to existing Firebase/OneSignal setups: firebase_core >=3.6 <5, firebase_messaging >=15.1 <17, flutter_local_notifications >=19 <23, and friends. (0.1.0 pinned the newest majors and broke resolution in older host apps.)
  • init(onBackgroundMessage:) — firebase_messaging allows a single background handler; Pushlio now forwards every non-Pushlio message to your own top-level handler, so both systems coexist.
  • init(androidSmallIcon:) — dedicated status-bar icon resource (launcher icons render as a flat square when tinted).
  • init(androidChannelId/Name/Importance:) — channel is configurable (Android creates channels once; pick importance up front).
  • init(enableLogs:) + Pushlio.deviceId getter for support matching.
  • Tests: foreign (non-ph) messages are proven side-effect-free.
  • Server-side: device country now comes from the request IP (GeoIP at the ingest edge), not the device locale — no SDK change required.

0.1.0 #

Initial release.

  • Push notifications: automatic device registration, rich notifications (big image + up to 3 action buttons), deep links with cold-start delivery, delivered/opened receipts with an offline-safe idempotent queue
  • Identify & segment: external user id, tags, custom events, opt-out
  • Feature flags & remote config with persistent cache
  • In-app messages: fetch + seen-once marking
0
likes
150
points
565
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Pushlio push notification SDK — device registration, rich notifications, delivered/opened receipts, deep links, feature flags and in-app messages.

Homepage
Repository (GitHub)
View/report issues

License

(pending) (license)

Dependencies

device_info_plus, firebase_core, firebase_messaging, flutter, flutter_local_notifications, http, package_info_plus, path_provider, shared_preferences

More

Packages that depend on pushlio_flutter