signalbird/app · /react · /vue · /angular · /react-nativeUygulama (App) - kendi sohbet arayüzünüz ve mobil push
Bu yüzey sizin müşterinizin kullanıcısı içindir: ziyaretçi ya da uygulama kullanıcısı. Canlı sohbet ve push cihaz kaydı yapar.
İki yolunuz var:
| Hazır widget | Uygulama SDK'sı | |
|---|---|---|
| Kurulum | tek <script> |
paket + kendi arayüzünüz |
| Görünüm | panelden yönetilir | tamamen sizin |
| Mobil | yok | iOS, Android, React Native |
| Ne zaman | siteye hızlıca sohbet | ürünün içine gömülü sohbet |
Hazır widget için Widget dokümanına bakın. Bu sayfa SDK'yı anlatır.
Anahtar
Panelde Gelen Kutusu → Ayarlar → Uygulamalar (ya da SDK ile
createApp) ile bir uygulama açın. Verilen sb_public_live_…
anahtarı açıktır ve istemciye gömülür.
Güvenliği gizlilikten değil kısıttan gelir:
- yalnız izinli kökenlerden çalışır (web),
- yalnız ziyaretçinin kendi verisine dokunur,
- gönderim yapamaz, kişi listesi okuyamaz.
Takım anahtarınızı (
sb_…) istemciye koymayın. Kurucu bunu yakalar ve hata verir; yakalamasaydı bile bir kez yayınlanan anahtar herkesindir.
Ziyaretçi sırrı ve saklama
Kimlik iki parçadır: uygulama anahtarı ve ziyaretçi sırrı. Sır yalnız
startSession yanıtında döner ve saklanması zorunludur - cihazda kalmazsa
kullanıcı uygulamayı her açtığında sohbet geçmişini kaybeder.
| Platform | Varsayılan | Nasıl değiştirilir |
|---|---|---|
| Web | localStorage |
storage seçeneği |
| React Native | yok - vermeniz gerekir | asyncStorageAdapter(AsyncStorage) |
| iOS (Swift) | UserDefaults |
SignalbirdStorage uyarlaması |
| Android (Kotlin) | bellek (yalnız test) | SharedPreferences sarmalayıcısı |
Saklanan kayıt uygulama anahtarını da taşır. Anahtarı yenilerseniz eski kimlik otomatik yok sayılır ve yeni oturum açılır.
React / Next.js
npm install signalbirdimport { SignalbirdProvider, useChat, useIdentify } from 'signalbird/react'
export function App() {
return (
<SignalbirdProvider publicKey={process.env.NEXT_PUBLIC_SIGNALBIRD_APP_KEY!}>
<Chat />
</SignalbirdProvider>
)
}
function Chat() {
const {
enabled, // sohbet bu uygulamada açık mı (bootstrap cevabı)
loading,
messages,
unread,
agentTyping,
withinHours, // çalışma saati dışıysa false
send,
typing,
markRead,
close,
} = useChat({ open: true })
// Kullanıcı giriş yaptığında ziyaretçiyi kişi kaydına bağlar
useIdentify(user && { external_id: user.id, email: user.email, name: user.name })
if (!enabled) return null
return (
<>
{!withinHours && <OfflineBanner />}
{messages.map((m) => <Bubble key={m.id} message={m} />)}
{agentTyping && <Typing />}
<Composer onSend={send} onType={() => typing(true)} />
</>
)
}open yalnız yoklama hızını değiştirir; paneli her açışta oturum yeniden
kurulmaz. Rozet için sohbet arayüzü açılmadan da çalışan bir kısayol var:
import { useUnreadCount } from 'signalbird/react'
const unread = useUnreadCount()Push kaydı:
import { usePushRegistration } from 'signalbird/react'
usePushRegistration(token ? { token, platform: 'web', provider: 'webpush' } : null)Vue 3
import { signalbirdPlugin, useChat } from 'signalbird/vue'
app.use(signalbirdPlugin, { publicKey: import.meta.env.VITE_SIGNALBIRD_APP_KEY })<script setup lang="ts">
import { ref } from 'vue'
import { useChat } from 'signalbird/vue'
const isOpen = ref(false)
const { state, send, typing, markRead } = useChat({ open: isOpen })
</script>
<template>
<div v-for="m in state.messages" :key="m.id">{{ m.body }}</div>
<span v-if="state.agentTyping">yazıyor…</span>
<input @input="typing(true)" @keyup.enter="send(($event.target as HTMLInputElement).value)" />
</template>Bileşen yok olduğunda yoklama otomatik durur.
Angular
// main.ts
import { provideSignalbird } from 'signalbird/angular'
bootstrapApplication(App, {
providers: [provideSignalbird({ publicKey: environment.signalbirdAppKey })],
})// chat.component.ts
import { SignalbirdService } from 'signalbird/angular'
@Component({
template: `
<div *ngFor="let m of (chat$ | async)?.messages">{{ m.body }}</div>
<input #box (keyup.enter)="send(box.value)" />
`,
})
export class ChatComponent implements OnInit {
private signalbird = inject(SignalbirdService)
chat$ = this.signalbird.chat$()
ngOnInit() { this.signalbird.setOpen(true) }
send(body: string) { this.signalbird.send(body) }
}Paket Angular'a derleme zamanı bağımlılık taşımaz (dekoratör kullanmaz), bu yüzden Angular sürümünüzü yükselttiğinizde yeniden yayın beklemeniz gerekmez.
React Native / Expo
import AsyncStorage from '@react-native-async-storage/async-storage'
import { AppState } from 'react-native'
import {
createSignalbirdApp,
asyncStorageAdapter,
useNativeChat,
useNativePush,
} from 'signalbird/react-native'
// Depoyu vermek ZORUNLU
const client = createSignalbirdApp({
publicKey: 'sb_public_live_…',
storage: asyncStorageAdapter(AsyncStorage),
})
export function ChatScreen() {
const [foreground, setForeground] = useState(true)
useEffect(
() => AppState.addEventListener('change', (s) => setForeground(s === 'active')).remove,
[],
)
const { messages, send, agentTyping } = useNativeChat(client, {
open: true,
isForeground: foreground, // arka planda yoklama turu atlanır - pil
})
useNativePush(client, token ? { token, platform: 'ios' } : null)
return <MessageList data={messages} typing={agentTyping} onSend={send} />
}Push token'ını almak (Expo Notifications ya da Firebase Messaging) ve izin diyaloğunu göstermek uygulamanın işidir: izni ne zaman isteyeceğiniz bir ürün kararıdır ve mağaza kuralları bunu ciddiye alır.
Swift (iOS)
Swift Package Manager: https://github.com/Pariette-Inc/signalbird.sdk
import Signalbird
let client = try SignalbirdApp(config: .init(
publicKey: "sb_public_live_…",
chatKey: "destek",
pushKey: "mobil"
))
// Sohbet açık mı, hangi renk, çalışma saati içinde miyiz
let boot = try await client.bootstrap()
try await client.startSession(["name": "Ayşe", "email": "ayse@example.com"])
try await client.startConversation(body: "Kargom nerede?")
// Yeni mesajlar - imleçle, tam listeyi tekrar indirmez
let updates = try await client.getConversation(conversationID, after: lastMessageID)
try await client.setTyping(conversationID: conversationID, isTyping: true)
try await client.markRead(conversationID: conversationID, lastMessageID: lastID)
// APNs
try await client.registerDevice(token: apnsToken, externalID: user.id, identityHash: user.signalbirdHash)Keychain isteyen kendi deposunu verir:
struct KeychainStorage: SignalbirdStorage {
func get(_ key: String) -> String? { … }
func set(_ key: String, _ value: String) { … }
func remove(_ key: String) { … }
}
let client = try SignalbirdApp(config: .init(
publicKey: "sb_public_live_…",
chatKey: "destek",
pushKey: "mobil",
storage: KeychainStorage()
))Kotlin (Android)
implementation("io.signalbird:signalbird-sdk:2.10.1")import io.signalbird.sdk.*
class PrefsStorage(private val prefs: SharedPreferences) : SignalbirdStorage {
override fun get(key: String) = prefs.getString(key, null)
override fun set(key: String, value: String) = prefs.edit().putString(key, value).apply()
override fun remove(key: String) = prefs.edit().remove(key).apply()
}
val client = SignalbirdApp(SignalbirdAppConfig(
publicKey = "sb_public_live_…",
chatKey = "destek",
pushKey = "mobil",
storage = PrefsStorage(prefs),
))
lifecycleScope.launch {
client.bootstrap()
client.startSession(mapOf("name" to "Ayşe"))
client.startConversation("Kargom nerede?")
val updates = client.getConversation(conversationId, after = lastMessageId)
client.registerDevice(token = fcmToken, externalId = user.id, identityHash = user.signalbirdHash)
}Tüm metotlar suspend'dir ve IO dağıtıcısında çalışır.
Çatısız kullanım (düz TypeScript)
import { SignalbirdApp, ChatSession } from 'signalbird/app'
const client = new SignalbirdApp({ publicKey: 'sb_public_live_…' })
// Ham uçlar
await client.bootstrap()
await client.startSession({ name: 'Ayşe' })
await client.startConversation({ body: 'Merhaba' })
// ya da durum katmanı
const session = new ChatSession(client, { active: true })
session.subscribe((state) => render(state))
await session.start()
await session.send('Kargom nerede?')ChatSession şunları üstlenir: iyimser gönderim (mesaj listeye anında düşer,
sunucu cevabıyla değiştirilir), yoklama merdiveni, okunmamış sayısı, yazıyor
durumu.
Yoklama nasıl çalışır
WebSocket yoktur. İmleçli yoklama bağlantı kopmasında kendi kendini toparlar ve mobil ağda pil yakmaz.
| Durum | Aralık |
|---|---|
| Panel açık | 3 sn |
| Panel kapalı - ilk 3 tur | 20 sn |
| sonraki 2 tur | 60 sn |
| sonrası | 180 sn |
| Sekme/uygulama arka planda | tur atlanır |
Yeni veri geldiğinde merdiven sıfırlanır: konuşma canlandığında bir sonraki yoklamayı üç dakika beklemek, kullanıcıyı terk edilmiş hissettirirdi.
Kimlik doğrulaması (identity_hash)
Uygulama anahtarı açıktır; biri external_id'ye başkasının kimliğini yazabilir.
Bu yüzden Signalbird external_id'yi (ve e-postayı) ancak yanında geçerli bir
identity_hash varsa güvenilir sayar (2.7.0). Hash olmadan:
- ziyaretçi kişi kaydınıza (contact) bağlanmaz,
- cihaz o kullanıcıya push hedefi olarak bağlanmaz,
- kanal ajanının araçları kimliği yalnız
visitor.unverifiedaltında görür.
Hash kendi sunucunuzda, gizli anahtarla üretilir ve oturum açan kullanıcıyla birlikte uygulamaya verilir (ör. giriş yanıtınızda):
identity_hash = hex( HMAC-SHA256( hex(SHA-256(sb_secret_live_…)), external_id ) )Sunucu yardımcıları: PHP Signalbird::identityHash($id), Node
client.identityHash(id), Python client.identity_hash(id), Go
client.IdentityHash(id), .NET client.IdentityHash(id).
await client.startSession({ external_id: user.id, identity_hash: user.signalbirdHash })
await client.identify({ external_id: user.id, identity_hash: user.signalbirdHash, email: user.email })
await client.registerDevice({ token, platform: 'web', external_id: user.id, identity_hash: user.signalbirdHash })
// `identityHash` yazımı da kabul edilir; sunucuya `identity_hash` olarak gider.Swift ve Kotlin'de sözlük/map girdisine "identity_hash" ekleyin;
registerDevice(…, identityHash:) parametresi vardır.
Ziyaretçi nesnesi iki alan taşır: identity_verified (hash geçerliydi) ve
verified (captcha geçti). Captcha yalnız hazır web widget'ında vardır;
Origin taşımayan mobil istekler muaftır ve bu SDK jeton göndermez. Bootstrap
yanıtındaki captcha alanı bilgi amaçlıdır.
Sürüm bildirimi
SDK her istekte sürümünü bildirir: X-Signalbird-Sdk: app/<sürüm> (React Native'de react-native/<sürüm>). Yeni bir
sürüm yayınlandığında API yanıtında Signalbird-Sdk-Status: outdated (ya da
artık desteklenmiyorsa unsupported) döner ve SDK süreç başına bir kez
uyarı yazar (console.warn). Uyarı hata değildir: isteğin sonucu değişmez.
Panelde Domainler → [domain] → Anahtarlar her anahtarın hangi SDK sürümüyle kullanıldığını gösterir; eski sürümdeki anahtarlar için panelin tepesinde bir uyarı şeridi ve bildirim çıkar. Güncellemek için:
npm i signalbird@latestHata davranışı
Hiçbir metot istisna fırlatmaz (kurucudaki anahtar denetimi hariç). Sonuç her
zaman {ok, status, code?, message?} zarfıdır.
| Kod | Anlamı |
|---|---|
VISITOR_INVALID |
Sır geçersiz - yerel kimlik silinir, sonraki çağrı yeni oturum açar |
CHAT_UNAVAILABLE |
Kota doldu ya da sohbet kapalı |
ORIGIN_NOT_ALLOWED |
Bu alan adı uygulamada tanımlı değil |
MODULE_DISABLED |
Paketinizde chat ya da push modülü yok |
NETWORK_ERROR / TIMEOUT |
Ağ (status 0) |
Tam metot listesi (17 metot) ve davranış kuralları:
signalbird.sdk/docs/CONTRACT.md § 11.