OneSignal'den Pushizo'ya göç
Pushizo, OneSignal'in kavram modelini (app, abonelik, kullanıcı/alias, tag, segment, şablon, journey) ve SDK yüzeyini (initialize → login → User.addTags → Notifications.requestPermission → Session.sendEvent) bilinçli…
Pushizo, OneSignal'in kavram modelini (app, abonelik, kullanıcı/alias, tag, segment, şablon, journey) ve SDK yüzeyini (initialize → login → User.addTags → Notifications.requestPermission → Session.sendEvent) bilinçli olarak korur. Bu rehber mevcut bir OneSignal uygulamasını kesintisiz taşımanın adımlarını, alan/uç eşlemelerini ve SDK değişikliklerini anlatır.
Araçlar: npm run migrate:onesignal (scripts/migrate-onesignal.ts), CSV içe aktarıcı (packages/db/src/data-transfer.ts → mapOneSignalRow), Postman koleksiyonu (api/postman_collection.json).
1. Genel plan
| Adım | Süre | Çıktı |
|---|---|---|
| 1. Hesap, organizasyon ve app oluşturma | 10 dk | app_… kimliği |
2. Kanal kimlik bilgileri (APNs .p8, FCM servis hesabı, VAPID, e-posta/SMS) | 30 dk | Kanallar active |
3. Player/abonelik göçü (migrate:onesignal → CSV → içe aktarma) | dosya boyutuna göre | Kullanıcılar, tag'ler, iOS/Android/e-posta/SMS abonelikleri |
| 4. Sunucu entegrasyonu (REST → Pushizo public API / sunucu SDK'ları) | 1–3 gün | Bildirim, kullanıcı, olay çağrıları |
| 5. İstemci SDK değişimi (Web/iOS/Android/Flutter, React Native/Capacitor/Cordova/.NET MAUI/Unity) | 1–2 gün | Yeni sürüm yayını |
| 6. Çift yazma dönemi ve kesinti | 2–4 hafta | OneSignal kapatılır |
2. Hesap ve app oluşturma
- Dashboard'da kayıt olun (
/register), e-posta doğrulaması ve isteğe bağlı MFA'yı tamamlayın. Her hesap bir organizasyon altında çalışır; organizasyon OneSignal'deki "hesap", app ise OneSignal app'inin karşılığıdır. - Başlangıç sihirbazı (
/<org>/getting-started) ile app'i oluşturun ya da public API'den:POST /v1/apps(org geneliadminanahtarı gerekir). - Organizasyon → API anahtarları'ndan bir sunucu anahtarı (
hs_live_…) üretin. Kapsamlar OneSignal REST API anahtarından daha incedir:notifications:write,users:read,users:write,events:write,segments:read,analytics:read,admin. Göç içinadminkapsamlı, IP izin listeli ve bitiş tarihli bir anahtar önerilir. - Kanallar sayfasında OneSignal'de kullandığınız kimlik bilgilerini aynen girin:
| OneSignal ayarı | Pushizo kanalı | Notlar |
|---|---|---|
Apple → .p8 anahtarı, Key ID, Team ID, Bundle ID | iOS Push (ios_push) | Ortam sandbox / production; aynı .p8 her iki tarafta çalışır. |
| Google → Firebase servis hesabı JSON | Android Push (android_push) | Aynı Firebase projesi kullanılır; cihaz token'ları geçerliliğini korur. |
| Web → Safari/Chrome ayarları | Web Push (web_push) | Pushizo kendi VAPID çiftini üretir; mevcut tarayıcı abonelikleri taşınamaz (bkz. §4.3). |
| E-posta (SendGrid vb.) | E-posta (email) | SMTP / Amazon SES / Resend; gönderici alan adını yeniden doğrulayın (SPF/DKIM/DMARC). |
| SMS (Twilio) | SMS (sms) | Twilio hesap bilgileri aynen; Netgsm de desteklenir. |
Her kanalda Doğrula düğmesi (POST /v1/apps/{app_id}/channels/{channel}/validate) sağlayıcıya test bağlantısı yapar.
3. Player (abonelik) göçü
3.1 npm run migrate:onesignal
Araç OneSignal "View devices" API'sinden (GET /players, 300'lük sayfalar) ya da büyük uygulamalar için POST /players/csv_export ile cihazları çeker, Pushizo'nun onesignal_players CSV biçimine yazar ve istenirse doğrudan içe aktarmayı başlatıp tamamlanana kadar izler.
# Yalnızca CSV üret
npm run migrate:onesignal -- --onesignal-app-id <ONESIGNAL_APP_ID> --onesignal-key <REST_API_KEY> --out players.csv
# Büyük uygulama: OneSignal csv_export (gz) kullan
npm run migrate:onesignal -- --onesignal-app-id <id> --onesignal-key <key> --csv-export --out players.csv
# CSV üret ve Pushizo'ya içe aktar (iş tamamlanana kadar bekler)
npm run migrate:onesignal -- --onesignal-app-id <id> --onesignal-key <key> \
--hs-api-url https://api.pushizo.com --hs-api-key hs_live_… --hs-app-id app_…Ortam değişkenleri de kabul edilir: ONESIGNAL_APP_ID, ONESIGNAL_REST_API_KEY, HS_API_URL, HS_API_KEY, HS_APP_ID. Çıktı stdout'a JSON olarak yazılır: { players, file, importId, importStatus, stats }.
CSV başlıkları OneSignal'in dışa aktarma biçimiyle aynıdır (id, identifier, session_count, language, timezone, game_version, device_os, device_type, device_model, ad_id, tags, last_active, playtime, amount_spent, created_at, invalid_identifier, badge_count, external_user_id, notification_types). OneSignal panelinden indirdiğiniz "Export" dosyasını da aracı kullanmadan doğrudan yükleyebilirsiniz.
3.2 CSV'yi elle içe aktarma
curl -X POST "https://api.example.com/v1/apps/app_…/imports" \
-H "Authorization: Bearer hs_live_…" \
-F type=onesignal_players -F file=@players.csv
# → { "id": "imp_…", "status": "queued" }
curl "https://api.example.com/v1/apps/app_…/imports/imp_…" -H "Authorization: Bearer hs_live_…"
# → { "status": "completed", "stats": { "processed", "created_users", "updated_users", "created_subscriptions", "skipped", "errors" }, "error_report_url": "…" }Dashboard eşdeğeri: Kitle → Dışa / İçe Aktarım. Dosya sınırı 50 MB ve 500.000 satırdır; daha büyük dosyaları bölün. İçe aktarma idempotenttir: aynı dosya ikinci kez yüklendiğinde kullanıcı ve abonelik yinelenmez.
3.3 Alan eşleme tablosu (mapOneSignalRow)
| OneSignal sütunu | Pushizo alanı | Kural |
|---|---|---|
external_user_id | external_id | Boşsa ve identifier varsa anonim kullanıcı oluşturulur; ikisi de boşsa satır hata raporuna düşer. |
identifier | abonelik token | Push token / e-posta / telefon. E-posta küçük harfe, telefon E.164'e normalize edilir; geçersizse satır atlanır. |
device_type | abonelik channel | 0 → ios_push; 1, 2, 13 → android_push; 11 → email; 14 → sms; 5, 7, 8, 9, 10 (web) → yalnızca kullanıcı oluşturulur (bkz. aşağı). Diğer değerler: abonelik yok. |
invalid_identifier = t | abonelik status: invalid | |
notification_types < 0 | abonelik status: unsubscribed | Aksi halde subscribed. |
tags (JSON) | kullanıcı tags | Değerler metne çevrilir (nesne/dizi JSON metni olur, null atlanır). Geçersiz JSON → satır hatası. |
language | properties.language, device.locale | |
timezone (UTC'den saniye) | device.timezone | Tam saat ise Etc/GMT∓h (UTC+3 → Etc/GMT-3), değilse boş. |
device_model, device_os, game_version | device.model, device.os_version, device.app_version | |
session_count, created_at, last_active | session_count, first_seen_at, last_active_at | |
id, ad_id, playtime, amount_spent, badge_count | — | Aktarılmaz. |
Web push abonelikleri CSV ile taşınamaz: OneSignal dışa aktarımı p256dh/auth anahtarlarını içermez ve VAPID anahtar çifti değiştiği için tarayıcı abonelikleri yeniden oluşturulmalıdır. Web ziyaretçileri Pushizo Web SDK'sı yüklendiğinde (autoResubscribe: true varsayılanıyla) izin zaten verilmişse sessizce yeniden abone olur; bu yüzden web için çift yazma dönemini uzun tutun.
3.4 Göç sonrası kontrol
- Abonelikler sayfasında kanal dağılımını OneSignal "Audience" sayılarıyla karşılaştırın.
- Bir cihazı Test cihazı yapıp Mesajlar → Test push gönder ile gerçek teslimatı doğrulayın (OneSignal'den gelen APNs/FCM token'ları Pushizo'dan de çalışır).
error_report_urldosyasındaki satırları inceleyin (line, error, row).
4. API eşleme tablosu
Kimlik doğrulama: OneSignal Authorization: Basic <REST_API_KEY> → Pushizo Authorization: Bearer hs_live_…. Hata zarfı { "error": { "code": "HS_…", "message", "details", "request_id" } } (hata kataloğu). Sayfalama OneSignal'deki offset/limit yerine cursor/limit (next_cursor, has_more).
4.1 Uçlar
| OneSignal REST | Pushizo public API | Fark |
|---|---|---|
POST /notifications | POST /v1/notifications | Gövdede app_id; yanıt 202 { id, status, recipients_estimate }. Idempotency için Idempotency-Key başlığı ya da idempotency_key alanı (OneSignal external_id). |
GET /notifications?app_id= | GET /v1/notifications?app_id= | Cursor sayfalama, status filtresi. |
GET /notifications/{id} | GET /v1/notifications/{message_id} | counts nesnesi (queued, sent, delivered, failed, opened, clicked, suppressed…). |
DELETE /notifications/{id} | DELETE /v1/notifications/{message_id} | Yalnızca zamanlanmış/kuyruktaki mesaj iptal edilir. |
GET /notifications/{id}/history | GET /v1/notifications/{message_id}/history | CSV işi; tamamlanınca download_url. |
POST /notifications/{id}/export_events | POST /v1/notifications/{message_id}/export_events | CSV işi; download_url. |
GET /players (view devices) | GET /v1/apps/{app_id}/users + GET /v1/apps/{app_id}/subscriptions/{id} | Cihaz kavramı yerine kullanıcı ve abonelik; aboneliğin sahibi GET …/subscriptions/{id}/user/identity. |
GET /players/{id} | GET /v1/apps/{app_id}/subscriptions/{subscription_id} | Alanlar: channel, status, token_masked, device, user_id. |
POST /players / PUT /players/{id} | POST /v1/apps/{app_id}/users (aboneliklerle) / PATCH …/subscriptions/{id} | Sunucu tarafı cihaz kaydı için users.upsert + subscriptions[]. |
PUT /players/{id} (tag güncelleme) | PATCH /v1/apps/{app_id}/users/by/{label}/{value} | Merge-patch tags, properties, deltas. null değer tag'i siler. |
POST /players/csv_export | POST /v1/apps/{app_id}/exports (type: users | subscriptions | events | deliveries) | GET …/exports/{id} → download_url. |
GET /users/by/{alias_label}/{alias_id} | GET /v1/apps/{app_id}/users/by/{label}/{value} | Aynı yol; hs_id OneSignal onesignal_id'nin karşılığıdır. |
POST /users | POST /v1/apps/{app_id}/users | external_id, tags, properties, language, subscriptions[]. |
PATCH /users/by/{label}/{value} | PATCH /v1/apps/{app_id}/users/by/{label}/{value} | |
DELETE /users/by/{label}/{value} | DELETE /v1/apps/{app_id}/users/by/{label}/{value} | Abonelikler silinir, olaylar anonimleşir. |
GET/PATCH /users/by/{label}/{value}/identity | GET/PATCH /v1/apps/{app_id}/users/by/{label}/{value}/identity | Alias ekleme; DELETE …/identity/{alias_label} kaldırır. |
POST /users/by/{label}/{value}/subscriptions | POST /v1/apps/{app_id}/users/by/{label}/{value}/subscriptions | { channel, token, device? }. |
PATCH /subscriptions/{id} | PATCH /v1/apps/{app_id}/subscriptions/{subscription_id} | opted_in, device, test_device. |
DELETE /subscriptions/{id} | DELETE /v1/apps/{app_id}/subscriptions/{subscription_id} | |
PATCH /subscriptions_by_token/{token_type}/{token} | PATCH /v1/apps/{app_id}/subscriptions_by_token/{token_type}/{token} | OneSignal tür adları (iOSPush, AndroidPush, ChromePush, FirefoxPush, SafariPush, Email, SMS) da kabul edilir. |
POST /subscriptions/{id}/owner | POST /v1/apps/{app_id}/subscriptions/{subscription_id}/owner | { external_id }. |
GET /subscriptions/{id}/user/identity | GET /v1/apps/{app_id}/subscriptions/{subscription_id}/user/identity | |
POST /apps/{app_id}/custom_events | POST /v1/apps/{app_id}/events | [{ external_id | subscription_id, name, properties, value, occurred_at }], en fazla 500. |
GET /apps/{app_id}/outcomes | GET /v1/apps/{app_id}/analytics/conversions | Dönüşüm olayı event_definitions.is_conversion ile işaretlenir (PATCH …/events/definitions/{name}). |
GET/POST /apps/{app_id}/segments, DELETE …/segments/{id} | GET/POST /v1/apps/{app_id}/segments, PATCH/DELETE …/{id} | Filtre AST ({ field, op, value } koşulları, all/any/none grupları; ör. tags.plan, properties.city, language, event); POST …/segments/preview sayım + örnek kullanıcılar. |
GET/POST /templates | GET/POST /v1/apps/{app_id}/templates, PATCH/DELETE …/{id}, POST …/{id}/render | Liquid; sürüm geçmişi …/versions, başka app'e kopya …/copy_to_app. |
GET /apps, GET /apps/{id} | GET /v1/apps, GET /v1/apps/{app_id} | PATCH /v1/apps/{app_id} ayarları günceller. |
POST /apps | POST /v1/apps | Org geneli admin anahtarı. |
| Journeys (yalnızca panel) | GET/POST /v1/apps/{app_id}/journeys, …/draft, …/publish, …/runs | API ile tasarlanabilir ve tetiklenebilir (journey'ler). |
| In-App Messages (yalnızca panel) | GET/POST /v1/apps/{app_id}/in-app-messages | Blok tabanlı; HTML yok. |
| Live Activities | — | v2 kapsamı (ADR-0017). |
Postman koleksiyonu (api/postman_collection.json) tüm bu uçları {{baseUrl}}, {{apiKey}}, {{appId}} değişkenleriyle içerir.
4.2 POST /notifications gövdesi
Hedefleme alanları Pushizo'da target nesnesi altında toplanır; içerik alanlarının çoğu aynı adı taşır.
| OneSignal | Pushizo | Not |
|---|---|---|
included_segments / excluded_segments | target.included_segments / target.excluded_segments | Segment kimlikleri (seg_…) ya da adları. |
include_aliases: { external_id: [] } | target.include_aliases veya target.include_external_ids | En fazla 2000. |
include_subscription_ids (eski include_player_ids) | target.include_subscription_ids | |
include_email_tokens | target.email_to | Aboneliği olmayan adres için anonim kullanıcı + abonelik oluşturulur. |
include_phone_numbers | target.include_phone_numbers | E.164. |
filters | target.filters | Segment AST (OneSignal field/relation/value yerine { field: "tags.plan", op: "eq", value: "pro" } ve all/any/none grupları). |
target_channel: "push" | "email" | "sms" | target.channels: ["ios_push", "android_push", "web_push", "email", "sms"] | Verilmezse içerikten çıkarılır; SMS yalnızca açıkça. |
isIos, isAndroid, isAnyWeb | target.channels | |
headings, contents, subtitle, url, app_url, data, buttons, big_picture, ios_attachments, ios_sound, ios_category, thread_id, ios_relevance_score, target_content_identifier, android_channel_id, android_group, android_sound, small_icon, large_icon, android_accent_color, android_visibility, chrome_web_icon, chrome_web_image, chrome_web_badge, web_push_topic, web_buttons, content_available, mutable_content, template_id, custom_data, send_after, delayed_option, delivery_time_of_day, ttl, priority, collapse_id, email_subject, email_body, email_preheader, email_from_name, email_from_address, email_reply_to_address, disable_email_click_tracking, sms_from, sms_media_urls, include_unsubscribed, name | aynı ad | priority OneSignal'deki gibi 5 (normal) ya da 10 (yüksek); ttl saniye. |
ios_badgeType, ios_badgeCount | ios_badge_type, ios_badge_count | snake_case. |
ios_interruption_level | ios_interruption_level | passive, active, time-sensitive, critical (critical alert rehberi). |
external_id (idempotency) | idempotency_key ya da Idempotency-Key başlığı | Aynı anahtar + aynı gövde aynı yanıtı döndürür; farklı gövde 409 HS_IDEMPOTENCY_CONFLICT. |
send_after + delayed_option: "timezone" | aynı | delivery_time_of_day: "09:00". |
throttle_rate_per_minute | throttle_rate_per_minute | |
email_mjml | email_mjml | OneSignal'de yok; MJML derlemesi Pushizo'ya özgüdür. |
| — | add_to_inbox, inbox_ttl, category, labels, one_per_user, frequency_cap_exempt, quiet_hours_exempt, require_interaction | Pushizo ek alanları. |
Örnek (Node sunucu SDK'sı):
import { Pushizo } from '@pushizo/node';
const hs = new Pushizo({ apiKey: process.env.HS_API_KEY!, appId: process.env.HS_APP_ID, baseUrl: 'https://api.example.com' });
await hs.notifications.create({
idempotency_key: `order-${order.id}`,
target: { include_aliases: { external_id: [userId] } },
headings: { tr: 'Siparişiniz yola çıktı', en: 'Your order has shipped' },
contents: { tr: 'Kargo takip bağlantısı içeride', en: 'Tracking link inside' },
url: `https://example.com/orders/${order.id}`,
data: { order_id: order.id },
});4.3 Webhook'lar
OneSignal "Event Streams" yerine Pushizo webhook endpoint'leri (/v1/apps/{app_id}/webhooks) HMAC imzalı (Pushizo-Signature: t=…,v1=…) olaylar gönderir: delivery.*, subscription.*, user.*, event.received, conversion.created, campaign.*, journey.*, in_app.*. İmza doğrulama ve yeniden deneme planı için webhook'lar.
5. SDK değişim rehberi
Tüm istemci SDK'larında gizli anahtar yoktur; yalnızca App ID (ve kendi API adresiniz) kullanılır. identity verification zorunluysa login ikinci parametre olarak sunucunuzun ürettiği identity_hash = HMAC-SHA256(sdk_secret, external_id) değerini alır (OneSignal'deki JWT yerine).
5.1 Web
| OneSignal v16 (Web) | Pushizo Web SDK (@pushizo/web) |
|---|---|
<script src="https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js"> + OneSignalDeferred.push(async (OneSignal) => { await OneSignal.init({ appId }) }) | <script src="https://api.example.com/sdk-web/PushizoSDK.js" async> + PushizoDeferred.push(async (Pushizo) => { await Pushizo.init({ appId: 'app_…', apiUrl: 'https://api.example.com' }) }) |
OneSignalSDKWorker.js site kökünde | PushizoSDKWorker.js site kökünde (importScripts(apiUrl + '/sdk-web/PushizoSDKWorker.js')); serviceWorkerPath / serviceWorkerScope seçenekleri aynı anlamda |
OneSignal.login(externalId, jwtToken?) | Pushizo.login(externalId, identityHash?) |
OneSignal.logout() | Pushizo.logout() |
OneSignal.User.addTag / addTags / removeTag / removeTags / getTags | aynı adlar: Pushizo.User.addTag / addTags / removeTag / removeTags / getTags |
OneSignal.User.addAlias / addAliases / removeAlias | aynı adlar |
OneSignal.User.addEmail / removeEmail / addSms / removeSms | aynı adlar (adres istemcide normalize edilir) |
OneSignal.User.setLanguage | Pushizo.User.setLanguage |
OneSignal.User.PushSubscription.optIn / optOut / id / token / optedIn + addEventListener('change') | Pushizo.User.pushSubscription.optIn / optOut / id / optedIn / state + addObserver(cb) (geri dönen fonksiyon dinleyiciyi kaldırır) |
OneSignal.Notifications.requestPermission() / permission | Pushizo.Notifications.requestPermission() / permission ('default' | 'granted' | 'denied' | 'unsupported') |
OneSignal.Notifications.addEventListener('click', cb) | Pushizo.Notifications.addClickListener(({ notification, result }) => …) |
OneSignal.Notifications.addEventListener('foregroundWillDisplay', cb) | Pushizo.Notifications.addForegroundLifecycleListener((e) => e.preventDefault()) |
OneSignal.Slidedown.promptPush / promptEmail / promptSms / promptPushCategories | Pushizo.Slidedown.promptPush / promptEmail / promptSms / promptEmailAndSms (kategori tercihleri için User.setPreferences) |
promptOptions.slidedown, welcomeNotification, notificationClickHandlerMatch/Action, notifyButton | slidedown, welcomeNotification, notificationClickHandlerMatch / notificationClickHandlerAction, bell (init seçenekleri) |
OneSignal.Session.sendOutcome / sendUniqueOutcome / sendOutcomeWithValue | Pushizo.Session.sendEvent(name, properties?, value?) |
OneSignal.User.PushSubscription bildirim kutusu yok | Pushizo.Inbox.list / markRead / markAllRead / archive / unreadCount / addObserver |
| In-app (yalnızca mobil) | Pushizo.InAppMessages.addTrigger / addTriggers / removeTrigger / clearTriggers / setScreen / paused / addClickListener / addLifecycleListener (web dahil) |
OneSignal.setConsentRequired(true) + setConsentGiven(true) | init({ requiresPrivacyConsent: true }) + Pushizo.setConsentGiven(true) |
OneSignal.Debug.setLogLevel | Pushizo.Debug.setLogLevel('debug') |
Ayrıntı: Web SDK, çatı entegrasyonları: React, Vue, Angular, iOS Safari PWA: iOS web push.
5.2 iOS
| OneSignal iOS SDK 5 | Pushizo iOS SDK (Pushizo, PushizoExtension) |
|---|---|
OneSignal.initialize("APP_ID", withLaunchOptions:) | Pushizo.initialize("app_…", launchOptions:) { options in options.apiUrl = "https://api.example.com" } |
| Swizzling ile token | Swizzling yok: didRegisterForRemoteNotificationsWithDeviceToken içinde Pushizo.setDeviceToken(deviceToken), hata durumunda Pushizo.setDeviceTokenError(error) |
OneSignal.login("id") / logout() | Pushizo.login("id", identityHash: nil) / Pushizo.logout() |
OneSignal.User.addTag/addTags/removeTag/getTags/setLanguage | aynı adlar |
OneSignal.User.addEmail/addSms/removeEmail/removeSms | aynı adlar |
OneSignal.User.pushSubscription.optIn()/optOut()/id/token/optedIn + addObserver | Pushizo.User.pushSubscription.optIn()/optOut()/id/token, await state(), addObserver { state in } |
OneSignal.Notifications.requestPermission(_:fallbackToSettings:) | Pushizo.Notifications.requestPermission { granted in } (await permission() ile okuma) |
OneSignal.Notifications.addPermissionObserver | addPermissionObserver { granted in } → HSListenerToken; removePermissionObserver(token) |
addClickListener / addForegroundLifecycleListener | aynı adlar; belirteç döndürür (removeClickListener(token)) |
OneSignalNotificationServiceExtension | PushizoNotificationServiceExtension(appId:apiUrl:appGroup:) → didReceive, serviceExtensionTimeWillExpire |
OneSignal.InAppMessages.addTrigger/removeTrigger/clearTriggers/paused | aynı adlar + setScreen, addClickListener, addLifecycleListener |
OneSignal.Session.sendOutcome(_:) | Pushizo.Session.sendEvent("name", properties:, value:) |
OneSignal.setConsentRequired/setConsentGiven | options.requiresPrivacyConsent = true + Pushizo.setConsentGiven(true) |
OneSignal.Notifications.clearAll() | Pushizo.Notifications.clearAll(), removeGroupedNotifications, removeNotification(identifier:) |
| Live Activities | v2 |
Aynı APNs .p8 anahtarı kullanıldığından mevcut cihaz token'ları Pushizo'dan de teslim alır; SDK ilk açılışta token'ı POST /subscriptions ile kaydeder (göçte aktarılmış abonelikle (app, channel, token) üzerinden birleşir). Ayrıntı: iOS SDK.
5.3 Android
| OneSignal Android SDK 5 | Pushizo Android SDK (com.pushizo:pushizo-android) |
|---|---|
OneSignal.initWithContext(this, "APP_ID") | Pushizo.initialize(this, "app_…", Pushizo.Options(apiUrl = "https://api.example.com")) (Application onCreate) |
OneSignal.login("id") / logout() | Pushizo.login("id", identityHash = null) / Pushizo.logout() |
OneSignal.User.addTag/addTags/removeTag/getTags/setLanguage | aynı adlar |
OneSignal.User.addEmail/addSms/removeEmail/removeSms | aynı adlar (emails, smsNumbers listeleri) |
OneSignal.User.pushSubscription.optIn()/optOut()/id/token/optedIn + addObserver | aynı adlar (state ek) |
OneSignal.Notifications.requestPermission(fallbackToSettings) (coroutine) | Pushizo.Notifications.requestPermission(activity) + onRequestPermissionsResult içinde Pushizo.Notifications.onPermissionResult() (PERMISSION_REQUEST_CODE) |
addPermissionObserver | addPermissionObserver(observer) / removePermissionObserver(observer) |
addClickListener / addForegroundLifecycleListener | aynı adlar |
OneSignal.InAppMessages.addTrigger/…/paused | aynı adlar + setScreen, addClickListener, addLifecycleListener |
OneSignal.Session.sendOutcome | Pushizo.Session.sendEvent("name", mapOf(...), value) |
OneSignal.consentRequired = true / consentGiven = true | Options(requiresPrivacyConsent = true) + Pushizo.setConsentGiven(true) |
OneSignal.Notifications.clearAllNotifications() | Pushizo.Notifications.clearAll(), removeNotification, removeGroupedNotifications |
| Bildirim kanalları (panelden) | Dashboard → Ayarlar → Android bildirim kategorileri (android_channels); android_channel_id ile seçilir |
Aynı Firebase projesi kullanıldığı sürece FCM token'ları değişmez. Ayrıntı: Android SDK.
5.4 Flutter
onesignal_flutter | pushizo_flutter |
|---|---|
OneSignal.initialize("APP_ID") | await Pushizo.initialize('app_…', apiUrl: 'https://api.example.com') |
OneSignal.login/logout | Pushizo.login(externalId, identityHash: null) / Pushizo.logout() |
OneSignal.User.addTags/removeTag/getTags/setLanguage | aynı adlar (hepsi Future) |
OneSignal.User.addEmail/addSms/removeEmail/removeSms | aynı adlar |
OneSignal.User.pushSubscription.optIn/optOut/id/token/optedIn + addObserver | Pushizo.User.pushSubscription.optIn()/optOut(), await state, changes.listen(...) |
OneSignal.Notifications.requestPermission(true) | await Pushizo.Notifications.requestPermission() |
OneSignal.Notifications.addPermissionObserver | Pushizo.Notifications.addPermissionObserver(fn) ya da permissionStream.listen(...) |
addClickListener / addForegroundWillDisplayListener | Pushizo.Notifications.clickStream.listen(...) / foregroundStream.listen(...) |
OneSignal.InAppMessages.addTrigger/…/paused(bool) | aynı adlar + setScreen, setPaused(bool), clickStream, lifecycleStream, setNavigatorKey |
OneSignal.Session.sendOutcome | Pushizo.Session.sendEvent(name, properties:, value:) |
OneSignal.consentRequired(true) / consentGiven(true) | initialize(..., requiresPrivacyConsent: true) + Pushizo.setConsentGiven(true) |
| — | Pushizo.Inbox.list/markRead/markAllRead/archive/unreadCount, Pushizo.User.getPreferences/setPreferences |
Ayrıntı: Flutter SDK.
5.5 Köprü SDK'ları için ortak notlar
Aşağıdaki tablolarda OneSignal sütunu ilgili paketin v5 API adlarını esas alır; daha eski (v3/v4) bir OneSignal sürümünden geçiyorsanız önce çağrıları v5 karşılıklarına eşleyin. Tüm köprü SDK'larında:
- Paket değişimi tek seferdedir: OneSignal paketini (ve Expo için
onesignal-expo-plugin) kaldırıp Pushizo paketini ekleyin, yerel projeyi yeniden üretin (pod install,npx cap sync,cordova prepare,expo prebuild). Pushizo iOS'taUNUserNotificationCenterdelegesini üstlendiğinden aynı sürümde iki push SDK'sı birlikte bulunmamalıdır. initializeApp ID'nin yanında kendi API adresinizi (apiUrl) alır; REST API anahtarı istemciye gömülmez.- OneSignal "outcome" çağrıları (
addOutcome,addUniqueOutcome,addOutcomeWithValueve C# karşılıkları) tek birSession.sendEvent(name, properties?, value?)çağrısına dönüşür; aynı ad in-appeventtetiklerini de çalıştırır. Tekillik (unique) gerekiyorsa uygulamada ya da journey/segment koşulunda sağlayın. - Bildirim kutusu (
Inbox) ve kategori tercihleri (User.getPreferences/setPreferences) OneSignal'de karşılığı olmayan eklemelerdir (bkz. 5.11).
5.6 React Native
react-native-onesignal 5 | @pushizo/react-native |
|---|---|
Expo: ["onesignal-expo-plugin", { "mode": "development" }] | ["@pushizo/react-native", { "mode": "development", "appId": "app_…" }] (plugin pakete dahildir; NSE hedefi PushizoNotificationServiceExtension) |
| Bare iOS: token swizzling ile alınır | Swizzling yok: AppDelegate içinde Pushizo.setDeviceToken(deviceToken) / Pushizo.setDeviceTokenError(error) (Expo plugin otomatik ekler) |
OneSignal.initialize('APP_ID') | await Pushizo.initialize('app_…', { apiUrl: 'https://api.example.com' }) |
OneSignal.login(externalId) / OneSignal.logout() | Pushizo.login(externalId, identityHash?) / Pushizo.logout() |
OneSignal.User.addTag / addTags / removeTag / removeTags / getTags | aynı adlar |
OneSignal.User.addAlias / addAliases / removeAlias | aynı adlar |
OneSignal.User.addEmail / removeEmail / addSms / removeSms, setLanguage | aynı adlar |
OneSignal.User.getExternalId() / getOnesignalId() | Pushizo.User.getExternalId() / getPushizoId() |
OneSignal.User.pushSubscription.getIdAsync / getTokenAsync / getOptedInAsync / optIn / optOut + addEventListener('change', …) | aynı adlar ({ previous, current }) |
OneSignal.Notifications.requestPermission(fallbackToSettings) | Pushizo.Notifications.requestPermission() |
OneSignal.Notifications.getPermissionAsync() | Pushizo.Notifications.getPermissionAsync() (eşzamanlı son değer: permission) |
OneSignal.Notifications.addEventListener('click' | 'foregroundWillDisplay' | 'permissionChange', …) | aynı olay adları; e.preventDefault() ve e.getNotification().display() aynı |
OneSignal.Notifications.clearAll() | Pushizo.Notifications.clearAll() |
OneSignal.InAppMessages.addTrigger / addTriggers / removeTrigger / removeTriggers / clearTriggers / setPaused / getPaused | aynı adlar + getTriggers, setScreen |
OneSignal.InAppMessages.addEventListener('click' | 'willDisplay' | 'didDisplay' | 'willDismiss' | 'didDismiss', …) | aynı olay adları; olay gövdesi { messageId, actionId, url } / { messageId } |
OneSignal.Session.addOutcome / addUniqueOutcome / addOutcomeWithValue | Pushizo.Session.sendEvent(name, properties?, value?) |
OneSignal.setConsentRequired(true) + setConsentGiven(true) | initialize(…, { requiresPrivacyConsent: true }) + Pushizo.setConsentGiven(true) |
OneSignal.Debug.setLogLevel(LogLevel.Verbose) | Pushizo.Debug.setLogLevel(LogLevel.Debug) |
| — | Pushizo.Inbox.*, Pushizo.User.getPreferences / setPreferences |
Ayrıntı: React Native SDK.
5.7 Capacitor (Ionic)
OneSignal Ionic/Capacitor uygulamalarında onesignal-cordova-plugin paketini kullanır; Pushizo'da ayrı bir Capacitor eklentisi vardır (web'de @pushizo/web'e devreder).
onesignal-cordova-plugin 5 (Capacitor) | @pushizo/capacitor |
|---|---|
npm install onesignal-cordova-plugin | npm install @pushizo/capacitor (+ web için @pushizo/web), npx cap sync |
| iOS token swizzling ile alınır | AppDelegate.swift içinde capacitorDidRegisterForRemoteNotifications / capacitorDidFailToRegisterForRemoteNotifications bildirimlerini gönderin |
OneSignal.initialize('APP_ID') | await Pushizo.initialize('app_…', { apiUrl: 'https://api.example.com' }) |
OneSignal.login / logout | Pushizo.login(externalId, identityHash?) / Pushizo.logout() (Promise) |
OneSignal.User.addTag / addTags / removeTag / removeTags / getTags, addAlias / addAliases / removeAlias, addEmail / removeEmail / addSms / removeSms, setLanguage | aynı adlar (hepsi Promise) |
OneSignal.User.pushSubscription.getIdAsync / getTokenAsync / getOptedInAsync / optIn / optOut | Pushizo.User.pushSubscription.getId / getToken / getOptedIn / getState / optIn / optOut |
OneSignal.User.pushSubscription.addEventListener('change', cb) | Pushizo.User.pushSubscription.addObserver((state) => …) (dönen fonksiyon aboneliği kaldırır) |
OneSignal.Notifications.requestPermission(true) | await Pushizo.Notifications.requestPermission() |
OneSignal.Notifications.addEventListener('click', cb) | Pushizo.Notifications.addClickListener(({ notification, result }) => …) |
OneSignal.Notifications.addEventListener('foregroundWillDisplay', cb) | Pushizo.Notifications.addForegroundLifecycleListener((e) => e.preventDefault()); erteleyip göstermek için await e.display() |
OneSignal.Notifications.addEventListener('permissionChange', cb) | Pushizo.Notifications.addPermissionObserver(({ permission }) => …) |
OneSignal.Notifications.clearAll() | Pushizo.Notifications.clearAll(), removeGroupedNotifications, removeNotification (yalnızca Android) |
OneSignal.InAppMessages.addTrigger / addTriggers / removeTrigger / removeTriggers / clearTriggers / setPaused / getPaused | aynı adlar + getTriggers, setScreen |
OneSignal.InAppMessages.addEventListener('click' | 'willDisplay' | …, cb) | Pushizo.InAppMessages.addClickListener(cb) / addLifecycleListener({ willDisplay, didDisplay, willDismiss, didDismiss }) |
OneSignal.Session.addOutcome / addUniqueOutcome / addOutcomeWithValue | Pushizo.Session.sendEvent(name, properties?, value?) |
OneSignal.setConsentRequired(true) + setConsentGiven(true) | initialize(…, { requiresPrivacyConsent: true }) + await Pushizo.setConsentGiven(true) |
OneSignal.Debug.setLogLevel(…) | await Pushizo.Debug.setLogLevel('debug') |
Ayrıntı: Capacitor SDK.
5.8 Cordova
onesignal-cordova-plugin 5 | cordova-plugin-pushizo |
|---|---|
cordova plugin add onesignal-cordova-plugin, window.plugins.OneSignal | cordova plugin add cordova-plugin-pushizo, window.Pushizo (ve window.plugins.Pushizo) |
| Android Gradle ayarı gerekmez | config.xml → GradlePluginKotlinEnabled ve GradlePluginGoogleServicesEnabled (köprü Kotlin'dir) |
OneSignal.initialize('APP_ID') (deviceready içinde) | await Pushizo.initialize('app_…', { apiUrl: 'https://api.example.com' }) |
| Diğer tüm çağrılar | Capacitor tablosuyla (5.7) birebir aynı; tüm metotlar Promise döndürür, hatalar PushizoError (code) |
iOS'ta APNs token geri çağrıları eklenti tarafından AppDelegate'e çalışma zamanında eklenir; ek kod gerekmez. Ayrıntı: Cordova SDK.
5.9 .NET MAUI
OneSignalSDK.DotNet 5 | Pushizo.Maui |
|---|---|
dotnet add package OneSignalSDK.DotNet, using OneSignalSDK.DotNet; | dotnet add package Pushizo.Maui, using PushizoSdk.Maui; |
OneSignal.Initialize("APP_ID") | builder.UsePushizo("app_…", o => o.ApiUrl = "https://api.example.com") (MauiProgram.cs) ya da Pushizo.Initialize("app_…", options) |
| iOS token swizzling ile alınır | AppDelegate içinde PushizoIos.RegisteredForRemoteNotifications(deviceToken) / FailedToRegisterForRemoteNotifications(error) |
OneSignal.Login("id") / OneSignal.Logout() | Pushizo.Login("id", identityHash) / Pushizo.Logout() |
OneSignal.User.AddTag / AddTags / RemoveTag / RemoveTags, AddAlias / AddAliases / RemoveAlias, AddEmail / RemoveEmail / AddSms / RemoveSms | aynı adlar + GetTags(), SetLanguage("tr") |
OneSignal.User.PushSubscription.OptIn() / OptOut() / Id / Token / OptedIn + Changed | aynı adlar (e.Previous, e.Current) |
await OneSignal.Notifications.RequestPermissionAsync(true) | await Pushizo.Notifications.RequestPermissionAsync(fallbackToSettings: true) |
OneSignal.Notifications.Clicked / ForegroundWillDisplay / PermissionChanged | aynı olay adları (EventHandler); tıklamada e.Notification, e.ActionId, e.Url; ön planda e.PreventDefault() |
OneSignal.Notifications.ClearAllNotifications() | Pushizo.Notifications.ClearAll() |
OneSignal.InAppMessages.AddTrigger / AddTriggers / RemoveTrigger / RemoveTriggers / ClearTriggers / Paused + Clicked / WillDisplay / DidDisplay / WillDismiss / DidDismiss | aynı adlar + GetTriggers(), SetScreen(name) |
OneSignal.Session.AddOutcome / AddUniqueOutcome / AddOutcomeWithValue | Pushizo.Session.SendEvent(name, properties, value) |
OneSignal.ConsentRequired = true + OneSignal.ConsentGiven = true | o.RequiresPrivacyConsent = true + Pushizo.SetConsentGiven(true) |
OneSignal.Debug.LogLevel = … | Pushizo.Debug.SetLogLevel(LogLevel.Debug) |
| — | Pushizo.Inbox.ListAsync / MarkReadAsync / MarkAllReadAsync / ArchiveAsync / UnreadCountAsync, Pushizo.User.GetPreferencesAsync / SetPreferencesAsync |
Ayrıntı: .NET MAUI SDK.
5.10 Unity
| OneSignal Unity SDK 5 | com.pushizo.unity |
|---|---|
OneSignal UPM paketleri, using OneSignalSDK; | Git URL ile UPM paketi (https://github.com/exec0de/pushizo.git?path=sdk/unity#sdk-v0.1.0), using PushizoSdk;; Project Settings → Pushizo (App ID, App Group, google-services.json yolu) |
OneSignal.Initialize("APP_ID") | Pushizo.Initialize("app_…", new PushizoOptions { ApiUrl = "https://api.example.com" }) |
OneSignal.Login("id") / OneSignal.Logout() | Pushizo.Login("id", identityHash) / Pushizo.Logout() |
OneSignal.User.AddTag / AddTags / RemoveTag / RemoveTags, AddAlias / AddAliases / RemoveAlias, AddEmail / RemoveEmail / AddSms / RemoveSms | aynı adlar + GetTags(), SetLanguage("tr") |
OneSignal.User.PushSubscription.OptIn() / OptOut() / Id / Token / OptedIn + Changed | aynı adlar |
await OneSignal.Notifications.RequestPermissionAsync(true) | await Pushizo.Notifications.RequestPermissionAsync(fallbackToSettings: true) |
OneSignal.Notifications.Clicked / ForegroundWillDisplay / PermissionChanged += (sender, e) => … | aynı olay adları, Action<T> imzası: Clicked += e => …, PermissionChanged += granted => … (olaylar ana iş parçacığında gelir) |
OneSignal.Notifications.ClearAllNotifications() | Pushizo.Notifications.ClearAll() |
OneSignal.InAppMessages.AddTrigger / AddTriggers / RemoveTrigger / RemoveTriggers / ClearTriggers / Paused + Clicked / WillDisplay / DidDisplay / WillDismiss / DidDismiss | aynı adlar + GetTriggers(), SetScreen(name) |
OneSignal.Session.AddOutcome / AddUniqueOutcome / AddOutcomeWithValue | Pushizo.Session.SendEvent(name, properties, value) |
OneSignal.ConsentRequired = true + OneSignal.ConsentGiven = true | new PushizoOptions { RequiresPrivacyConsent = true } + Pushizo.SetConsentGiven(true) |
OneSignal.Debug.LogLevel = … | Pushizo.Debug.SetLogLevel(LogLevel.Debug) |
| — | Pushizo.Inbox.*Async, Pushizo.User.GetPreferencesAsync / SetPreferencesAsync |
Android bağımlılıkları EDM4U ile çözülür ve Assets/google-services.json derlemede işlenir (Firebase Unity SDK'sı gerekmez); iOS'ta Push yeteneği, NSE hedefi ve Podfile derleme sonrası işlemle eklenir. Ayrıntı: Unity SDK.
5.11 Bildirim kutusu ve tercihler (OneSignal'de olmayanlar)
- Bildirim kutusu:
add_to_inbox: trueile gönderilen mesajlar kullanıcıya özel kutuda listelenir (Inbox.list,markRead,markAllRead,archive,unreadCount); OneSignal'de karşılığı olmadığından taşınacak veri yoktur. - Kategori tercihleri: OneSignal "push categories" slidedown'ı yerine dashboard'da Kategoriler tanımlanır; SDK'lar
User.getPreferences()/setPreferences([...])ile kullanıcı × kanal opt-in yazar. OneSignal'de tag ile yönettiğiniz tercihleri (tags.promo_optin = "0") göç sonrasında bir kerelikPUT /v1/apps/{app_id}/users/by/external_id/{id}/preferencesçağrısıyla gerçek tercihe çevirebilirsiniz.
6. Kesinti planı (çift yazma dönemi)
- Hafta 0 — hazırlık: kanallar doğrulanmış, player göçü tamamlanmış, sunucu entegrasyonu Pushizo'ya de yazıyor (çift yazma: her bildirim/olay OneSignal ve Pushizo'ya birlikte gider; Pushizo'da
test_devices_only: trueile yalnızca test cihazlarına gönderim yapın ya da hedefi küçük bir segmentle sınırlayın). - Hafta 1–2 — istemci yayını: Pushizo SDK'sını içeren mobil sürümü yayınlayın, web'de SDK'yı canlıya alın. Her iki SDK aynı uygulamada çalışabilir; ancak push izni istemini yalnızca Pushizo'dan yapın (iki SDK birden izin isterse kullanıcı kafa karışıklığı yaşar) ve Android'de yalnızca birinin ön plan bildirimi göstermesine izin verin (
addForegroundLifecycleListener+preventDefault()). - Hafta 2–3 — trafik kaydırma: işlemsel bildirimleri (sipariş, OTP) Pushizo'dan, kampanyaları dashboard'dan göndermeye başlayın. OneSignal'den gönderimi segment bazında azaltın; Analitik → Teslimat raporu ve Sağlayıcı sağlığı sayfalarından teslim/açılma oranlarını karşılaştırın.
- Hafta 3–4 — kesinti: OneSignal gönderimlerini durdurun,
migrate:onesignalile son bir fark çekimi yapın (içe aktarma idempotenttir; yeni player'lar eklenir, mevcutlar güncellenir), OneSignal webhook/Event Stream'lerini kapatın, REST API anahtarını iptal edin. - Eski uygulama sürümleri: OneSignal SDK'sı içeren eski sürümler hâlâ OneSignal'e token kaydeder; bu kullanıcılar için haftalık fark çekimini sürümün kullanım payı %1'in altına inene kadar sürdürün.
- Geri alma: çift yazma döneminde OneSignal yapılandırmasını silmeyin; kritik bir sorun olursa gönderimi OneSignal'e geri alabilirsiniz. Kesintiden sonra
.p8/servis hesabı anahtarlarını OneSignal'den kaldırın.
7. Sık karşılaşılan farklar
| Konu | OneSignal | Pushizo |
|---|---|---|
| Kimlik | onesignal_id + external_id | hs_id + external_id + özel alias'lar (users/by/{label}/{value}) |
| Cihaz birleştirme | login cihazı kullanıcıya bağlar | Aynı; anonim kullanıcı birleştirilir, user.merged webhook'u üretilir |
| Hata biçimi | { "errors": [...] } | { "error": { "code": "HS_…", … } }, x-request-id |
| Hız sınırı | sabit | Plan bazlı (api_rps), X-RateLimit-* başlıkları, 429 HS_RATE_LIMITED + Retry-After |
| Sessiz saatler / frekans sınırı | panel | App ayarları; mesaj başına quiet_hours_exempt, frequency_cap_exempt |
| Şablon dili | {{ tag }} basit değişkenler | Liquid ({{ user.tags.name }}, filtreler, koşullar) |
| Web push kimliği | OneSignal VAPID | Kendi VAPID çiftiniz (kanal kaydında üretilir); abonelikler yeniden oluşur |
| Veri yerleşimi | OneSignal bulutu | Kendi altyapınız (self-hosted) |
Faturalama, planlar ve kota (Faz 13)
Plan matrisi, deneme, Stripe/iyzico/mock sağlayıcıları, kullanım raporu, kota ve özellik kapıları, uyarı e-postaları. Tasarım kararları: ADR-0020. Ortak kod: packages/billing (plan matrisi, sağlayıcı adaptörleri, kota…
Firebase Cloud Messaging'den (FCM) Pushizo'ya göç
Bildirimleri doğrudan Firebase Cloud Messaging (FCM HTTP v1 API, Firebase Admin SDK ya da Firebase konsolu) ile gönderiyorsanız bu rehber Pushizo'ya geçişi anlatır. Pushizo Android'de FCM'i taşıma katmanı olarak…