İlk adım, kullanıcıdan push mesajı göndermek için izin almaktır. Ardından PushSubscription
elde edebiliriz.
Bunu yapmak için kullanacağınız JavaScript API oldukça basittir. Mantık akışını adım adım inceleyelim.
Özellik algılama
Öncelikle mevcut tarayıcının push mesajlaşmayı destekleyip desteklemediğini kontrol etmemiz gerekiyor. İki basit kontrolle push'in desteklenip desteklenmediğini kontrol edebiliriz.
- navigator üzerinde serviceWorker olup olmadığını kontrol edin.
- Pencere'de PushManager olup olmadığını kontrol edin.
if (!('serviceWorker' in navigator)) {
// Service Worker isn't supported on this browser, disable or hide UI.
return;
}
if (!('PushManager' in window)) {
// Push isn't supported on this browser, disable or hide UI.
return;
}
Hem servis çalışanı hem de push mesajlaşma için tarayıcı desteği hızla artıyor olsa da her ikisinde de özellik algılamak ve kademeli olarak geliştirmek her zaman iyi bir fikirdir.
Hizmet çalışanı kaydetme
Özellik algılama özelliğiyle hem servis çalışanlarının hem de Push'ın desteklendiğini biliyoruz. Sonraki adım, hizmet işleyicimizi "kaydetmek"tir.
Bir hizmet çalışanını kaydettiğimizde tarayıcıya hizmet çalışanı dosyamızın nerede olduğunu bildiririz. Dosya hâlâ yalnızca JavaScript'tir ancak tarayıcı, itme dahil olmak üzere hizmet çalışanı API'lerine "erişim verir". Daha doğrusu, tarayıcı dosyayı bir hizmet çalışanı ortamında çalıştırır.
Bir hizmet çalışanı kaydetmek için navigator.serviceWorker.register()
işlevini çağırarak dosyanızın yolunu iletin. Örneğin:
function registerServiceWorker() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
console.log('Service worker successfully registered.');
return registration;
})
.catch(function (err) {
console.error('Unable to register service worker.', err);
});
}
Bu işlev, tarayıcıya bir hizmet çalışanı dosyamız olduğunu ve bu dosyanın nerede bulunduğunu bildirir. Bu durumda, hizmet çalışanı dosyası /service-worker.js
adresindedir. Arka planda tarayıcı, register()
çağrısından sonra aşağıdaki adımları uygular:
Hizmet çalışanı dosyasını indirin.
JavaScript'i çalıştırın.
Her şey doğru şekilde çalışırsa ve hata yoksa
register()
tarafından döndürülen söz çözülür. Herhangi bir hata varsa söz reddedilir.
register()
reddedilirse Chrome Geliştirici Araçları'nda JavaScript'inizi yazım hataları / hatalar açısından tekrar kontrol edin.
register()
çözüldüğünde bir ServiceWorkerRegistration
döndürür. PushManager API'ye erişmek için bu kaydı kullanırız.
PushManager API tarayıcı uyumluluğu
İzin isteme
Hizmet işleyicimizi kaydettik ve kullanıcıyı abone etmeye hazırız. Bir sonraki adım, kullanıcıdan push mesajı göndermek için izin almaktır.
İzin almak için kullanılan API nispeten basittir. Bunun dezavantajı, API'nin yakın zamanda geri çağırma işlevini yerine getirmek yerine Promise döndürmeye geçmesidir. Bununla ilgili sorun, mevcut tarayıcı tarafından API'nin hangi sürümünün uygulandığını belirleyemememizdir. Bu nedenle, her ikisini de uygulamanız ve yönetmeniz gerekir.
function askPermission() {
return new Promise(function (resolve, reject) {
const permissionResult = Notification.requestPermission(function (result) {
resolve(result);
});
if (permissionResult) {
permissionResult.then(resolve, reject);
}
}).then(function (permissionResult) {
if (permissionResult !== 'granted') {
throw new Error("We weren't granted permission.");
}
});
}
Yukarıdaki kodda önemli kod snippet'i Notification.requestPermission()
çağrısıdır. Bu yöntem, kullanıcıya bir istem gösterir:
Kullanıcı izin istemiyle etkileşime geçtikten sonra (İzin ver, Engelle'ye basarak veya istemi kapatarak) sonuç bize bir dize olarak gönderilir: 'granted'
, 'default'
veya 'denied'
.
Yukarıdaki örnek kodda, izin verilirse askPermission()
tarafından döndürülen söz çözülür. Aksi takdirde, söz reddedilmesini sağlayan bir hata atarız.
Kullanıcının "Engelle" düğmesini tıklaması gibi uç durumlarla da ilgilenmeniz gerekir. Bu durumda web uygulamanız kullanıcıdan tekrar izin isteyemez. Kullanıcıların, ayarlar panelinde bulunan izin durumunu değiştirerek uygulamanızın "engelini manuel olarak kaldırmaları" gerekir. Kullanıcıdan nasıl ve ne zaman izin isteyeceğinizi dikkatlice düşünün. Kullanıcı engellemeyi tıklarsa bu kararı geri almak kolay değildir.
Neyse ki çoğu kullanıcı, izin neden bildikleri sürece izin vermekten memnuniyet duyar.
Bazı popüler sitelerin izin isteğinde bulunma şeklini daha sonra inceleyeceğiz.
PushManager ile kullanıcıları abone etme
Hizmet işleyicimizi kaydettikten ve izin aldıktan sonra registration.pushManager.subscribe()
işlevini çağırarak kullanıcıları abone edebiliriz.
function subscribeUserToPush() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
),
};
return registration.pushManager.subscribe(subscribeOptions);
})
.then(function (pushSubscription) {
console.log(
'Received PushSubscription: ',
JSON.stringify(pushSubscription),
);
return pushSubscription;
});
}
subscribe()
yöntemini çağırırken hem zorunlu hem de isteğe bağlı parametrelerden oluşan bir options nesnesi iletiyoruz.
İletilebilen tüm seçeneklere göz atalım.
userVisibleOnly seçenekleri
Push, tarayıcılara ilk kez eklendiğinde geliştiricilerin bildirim göstermeden push mesajı gönderip gönderemeyeceği konusunda belirsizlik vardı. Kullanıcının arka planda bir şey olduğunu bilmediği için bu işleme genellikle sessiz push adı verilir.
Geliştiricilerin, kullanıcının bilgisi olmadan sürekli olarak konumunu izlemek gibi kötü şeyler yapabileceğinden endişeleniliyordu.
Bu senaryoyu önlemek ve spesifikasyon yazarlarına bu özelliği en iyi şekilde nasıl destekleyebileceklerini düşünmeleri için zaman tanımak amacıyla userVisibleOnly
seçeneği eklendi. true
değeri gönderildiğinde, web uygulamasının her push aldığında bildirim göstereceği (yani sessiz push olmaz) konusunda tarayıcı ile sembolik bir sözleşme yapılmış olur.
Şu anda true
değeri göndermeniz gerekir. userVisibleOnly
anahtarını veya geçişini false
içine eklemezseniz aşağıdaki hatayı alırsınız:
Chrome şu anda yalnızca kullanıcı tarafından görülebilen mesajlarla sonuçlanacak abonelikler için Push API'yi desteklemektedir. Bunun yerine pushManager.subscribe({userVisibleOnly: true})
numaralı telefonu arayarak bu durumu belirtebilirsiniz. Daha fazla bilgi için https://goo.gl/yqv4Q4 adresine göz atın.
Şu anda, sessiz push'in Chrome'da hiçbir zaman uygulanmayacağı anlaşılıyor. Bunun yerine, spesifikasyon yazarları, web uygulamalarının kullanımına göre belirli sayıda sessiz push mesajı göndermesine olanak tanıyacak bir bütçe API'si fikrini araştırıyor.
applicationServerKey seçeneği
Önceki bölümde "uygulama sunucusu anahtarları"ndan kısaca bahsetmiştik. "Uygulama sunucusu anahtarları", bir kullanıcıya abone olan uygulamayı tanımlamak ve aynı uygulamanın bu kullanıcıya mesaj göndermesini sağlamak için bir push hizmeti tarafından kullanılır.
Uygulama sunucusu anahtarları, uygulamanıza özgü bir genel ve özel anahtar çiftidir. Özel anahtar, uygulamanızda gizli tutulmalıdır. Ortak anahtar ise serbestçe paylaşılabilir.
subscribe()
çağrısına iletilen applicationServerKey
seçeneği, uygulamanın herkese açık anahtarıdır. Tarayıcı, kullanıcıyı abone ederken bunu bir push hizmetine iletir. Bu sayede push hizmeti, uygulamanızın herkese açık anahtarını kullanıcının PushSubscription
ile bağlayabilir.
Aşağıdaki şemada bu adımlar gösterilmektedir.
- Web uygulamanız bir tarayıcıya yüklenir ve herkese açık uygulama sunucu anahtarınızı ileterek
subscribe()
işlevini çağırırsınız. - Ardından tarayıcı, bir uç nokta oluşturacak, bu uç noktayı uygulamanın ortak anahtarıyla ilişkilendirecek ve uç noktayı tarayıcıya döndürecek bir push hizmetine ağ isteği gönderir.
- Tarayıcı, bu uç noktayı
subscribe()
vaadi aracılığıyla döndürülenPushSubscription
'e ekler.
Daha sonra bir push mesajı göndermek istediğinizde, uygulama sunucunuzun gizli anahtarıyla imzalanmış bilgileri içeren bir Yetkilendirme başlığı oluşturmanız gerekir. Push hizmeti, push mesajı gönderme isteği aldığında, isteği alan uç noktaya bağlı ortak anahtarı arayarak bu imzalı Yetkilendirme üstbilgisini doğrulayabilir. İmza geçerliyse itme hizmeti, eşleşen özel anahtarla uygulama sunucusundan gelmiş olması gerektiğini bilir. Temel olarak, bir uygulamanın kullanıcılarına başkalarının mesaj göndermesini engelleyen bir güvenlik önlemidir.
Teknik olarak applicationServerKey
isteğe bağlıdır. Ancak Chrome'da en kolay uygulama için bu gereklidir ve diğer tarayıcılarda da gelecekte gerekli olabilir. Firefox'ta isteğe bağlıdır.
Uygulama sunucusu anahtarının nasıl olması gerektiğini tanımlayan spesifikasyon VAPID spesifikasyonudur. "Uygulama sunucusu anahtarları" veya "VAPID anahtarları" ile ilgili bir şey okuduğunuzda bunların aynı şey olduğunu unutmayın.
Uygulama sunucusu anahtarları oluşturma
web-push-codelab.glitch.me adresini ziyaret ederek herkese açık ve özel bir uygulama sunucusu anahtar grubu oluşturabilir veya aşağıdakileri yaparak anahtar oluşturmak için web-push komut satırını kullanabilirsiniz:
$ npm install -g web-push
$ web-push generate-vapid-keys
Uygulamanız için bu anahtarları yalnızca bir kez oluşturmanız gerekir. Özel anahtarı gizli tuttuğunuzdan emin olun. (Evet, az önce söyledim.)
İzinler ve subscribe()
subscribe()
çağrısının bir yan etkisi vardır. Web uygulamanız, subscribe()
çağrısı sırasında bildirim gösterme iznine sahip değilse tarayıcı sizin adınıza izinleri ister. Kullanıcı arayüzünüz bu akışla çalışıyorsa bu yöntem faydalıdır. Ancak daha fazla kontrol sahibi olmak istiyorsanız (ki çoğu geliştiricinin bunu isteyeceğini düşünüyorum) daha önce kullandığımız Notification.requestPermission()
API'sini kullanın.
PushSubscription nedir?
subscribe()
işlevini çağırırız, bazı seçenekleri iletiriz ve karşılığında PushSubscription
değerine çözümlenen bir söz alırız. Bu da aşağıdaki gibi bir kodla sonuçlanır:
function subscribeUserToPush() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
),
};
return registration.pushManager.subscribe(subscribeOptions);
})
.then(function (pushSubscription) {
console.log(
'Received PushSubscription: ',
JSON.stringify(pushSubscription),
);
return pushSubscription;
});
}
PushSubscription
nesnesi, ilgili kullanıcıya push mesajı göndermek için gereken tüm bilgileri içerir. İçeriği JSON.stringify()
kullanarak yazdırırsanız aşağıdakileri görürsünüz:
{
"endpoint": "https://some.pushservice.com/something-unique",
"keys": {
"p256dh":
"BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
"auth":"FPssNDTKnInHVndSTdbKFw=="
}
}
endpoint
, push hizmetleri URL'sidir. Bir push mesajı tetiklemek için bu URL'ye bir POST isteği gönderin.
keys
nesnesi, push mesajıyla gönderilen mesaj verilerini şifrelemek için kullanılan değerleri içerir (bu bölümde daha sonra ele alacağız).
Süre sonunu önlemek için düzenli olarak yeniden abone olma
Push bildirimlerine abone olduğunuzda genellikle null
ile ilgili bir PushSubscription.expirationTime
alırsınız. Teorik olarak bu, aboneliğin süresinin hiçbir zaman dolmayacağı anlamına gelir (aboneliğin süresinin tam olarak ne zaman dolacağını belirten bir DOMHighResTimeStamp
aldığınız durumlara kıyasla). Ancak pratikte, tarayıcıların aboneliklerin süresinin dolmasına izin vermesi yaygındır. Örneğin, uzun süre boyunca push bildirimi alınmadıysa veya tarayıcı, kullanıcının push bildirimi izni olan bir uygulama kullanmadığını algıladıysa abonelik süresi dolabilir. Bunu önlemek için kullanabileceğiniz yöntemlerden biri, aşağıdaki snippet'te gösterildiği gibi, her bildirim aldığında kullanıcıyı yeniden abone etmektir. Bu durumda, tarayıcı aboneliğin süresini otomatik olarak sonlandırmaması için bildirimleri yeterince sık göndermeniz gerekir. Bu nedenle, geçerli bildirim ihtiyaçlarının avantajlarını ve dezavantajlarını, yalnızca aboneliğin süresinin dolmaması için kullanıcıya istemeden spam gönderme durumuna karşı çok dikkatli bir şekilde tartmanız gerekir. Sonuç olarak, kullanıcıyı uzun zaman önce unutulmuş bildirim aboneliklerinden korumaya çalışan tarayıcıya karşı çıkmamalısınız.
/* In the Service Worker. */
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
// Display notification or handle data
// Example: show a notification
const title = 'New Notification';
const body = 'You have new updates!';
const icon = '/images/icon.png';
const tag = 'simple-push-demo-notification-tag';
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
// Attempt to resubscribe after receiving a notification
event.waitUntil(resubscribeToPush());
});
function resubscribeToPush() {
return self.registration.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
return subscription.unsubscribe();
}
})
.then(function() {
return self.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
});
})
.then(function(subscription) {
console.log('Resubscribed to push notifications:', subscription);
// Optionally, send new subscription details to your server
})
.catch(function(error) {
console.error('Failed to resubscribe:', error);
});
}
Sunucunuza abonelik gönderme
Bir push aboneliğiniz olduğunda bunu sunucunuza göndermeniz gerekir. Bunu nasıl yapacağınız size bağlıdır ancak abonelik nesnesinden gerekli tüm verileri almak için JSON.stringify()
kullanmanızı öneririz. Alternatif olarak, aynı sonucu manuel olarak aşağıdaki gibi oluşturabilirsiniz:
const subscriptionObject = {
endpoint: pushSubscription.endpoint,
keys: {
p256dh: pushSubscription.getKeys('p256dh'),
auth: pushSubscription.getKeys('auth'),
},
};
// The above is the same output as:
const subscriptionObjectToo = JSON.stringify(pushSubscription);
Abonelik, web sayfasında aşağıdaki gibi gönderilir:
function sendSubscriptionToBackEnd(subscription) {
return fetch('/api/save-subscription/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(subscription),
})
.then(function (response) {
if (!response.ok) {
throw new Error('Bad status code from server.');
}
return response.json();
})
.then(function (responseData) {
if (!(responseData.data && responseData.data.success)) {
throw new Error('Bad response from server.');
}
});
}
Düğüm sunucusu bu isteği alır ve verileri daha sonra kullanmak üzere bir veritabanına kaydeder.
app.post('/api/save-subscription/', function (req, res) {
if (!isValidSaveRequest(req, res)) {
return;
}
return saveSubscriptionToDatabase(req.body)
.then(function (subscriptionId) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({data: {success: true}}));
})
.catch(function (err) {
res.status(500);
res.setHeader('Content-Type', 'application/json');
res.send(
JSON.stringify({
error: {
id: 'unable-to-save-subscription',
message:
'The subscription was received but we were unable to save it to our database.',
},
}),
);
});
});
Sunucumuzdaki PushSubscription
ayrıntıları sayesinde istediğimiz zaman kullanıcımıza mesaj gönderebiliriz.
Süre sonunu önlemek için düzenli olarak yeniden abone olma
Push bildirimlerine abone olduğunuzda genellikle null
ile ilgili bir PushSubscription.expirationTime
alırsınız. Teorik olarak bu, aboneliğin süresinin hiçbir zaman dolmayacağı anlamına gelir (aboneliğin süresinin tam olarak ne zaman dolacağını belirten bir DOMHighResTimeStamp
aldığınız durumlara kıyasla). Ancak pratikte, tarayıcıların aboneliklerin süresinin dolmasına izin vermesi yaygındır. Örneğin, uzun süre boyunca push bildirimi alınmadıysa veya tarayıcı, kullanıcının push bildirimi izni olan uygulamayı kullanmadığını algıladıysa aboneliklerin süresi dolar. Bunu önlemek için kullanabileceğiniz yöntemlerden biri, aşağıdaki snippet'te gösterildiği gibi, her bildirim aldığında kullanıcıyı yeniden abone etmektir. Bu durumda, tarayıcı aboneliğin süresini otomatik olarak sonlandırmaması için bildirimleri yeterince sık göndermeniz gerekir. Ayrıca, geçerli bildirim ihtiyaçlarının avantajlarını ve dezavantajlarını, yalnızca aboneliğin süresinin dolmaması için kullanıcıya spam göndermeyle karşılaştırmalı olarak çok dikkatli bir şekilde değerlendirmeniz gerekir. Sonuç olarak, kullanıcıyı uzun zaman önce unutulmuş bildirim aboneliklerinden korumaya çalışan tarayıcıya karşı çıkmamalısınız.
/* In the Service Worker. */
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
// Display notification or handle data
// Example: show a notification
const title = 'New Notification';
const body = 'You have new updates!';
const icon = '/images/icon.png';
const tag = 'simple-push-demo-notification-tag';
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
// Attempt to resubscribe after receiving a notification
event.waitUntil(resubscribeToPush());
});
function resubscribeToPush() {
return self.registration.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
return subscription.unsubscribe();
}
})
.then(function() {
return self.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
});
})
.then(function(subscription) {
console.log('Resubscribed to push notifications:', subscription);
// Optionally, send new subscription details to your server
})
.catch(function(error) {
console.error('Failed to resubscribe:', error);
});
}
SSS
Bu aşamada kullanıcıların sıklıkla sorduğu bazı soruları aşağıda bulabilirsiniz:
Bir tarayıcının kullandığı push hizmetini değiştirebilir miyim?
Hayır. Push hizmeti tarayıcı tarafından seçilir ve subscribe()
çağrısında gördüğümüz gibi tarayıcı, PushSubscription'ı oluşturan ayrıntıları almak için push hizmetine ağ istekleri gönderir.
Her tarayıcı farklı bir Push Hizmeti kullanıyor. Farklı API'leri yok mu?
Tüm push hizmetleri aynı API'yi bekler.
Bu yaygın API, Web Push Protokolü olarak adlandırılır ve uygulamanızın bir push mesajını tetiklemek için yapması gereken ağ isteğini açıklar.
Bir kullanıcıyı masaüstünde abone edersem telefonunda da abone olur mu?
Maalesef hayır. Kullanıcıların, mesaj almak istedikleri her tarayıcıda push'e kaydolması gerekir. Bunun için kullanıcının her cihazda izin vermesi gerektiğini de belirtmek isteriz.
Sonraki adımlar
- Web Push Bildirimlerine Genel Bakış
- Push bildirimleri nasıl çalışır?
- Kullanıcıları abone etme
- İzin kullanıcı deneyimi
- Web Push Kitaplıklarıyla Mesaj Gönderme
- Web Push Protokolü
- Push Etkinliklerini İşleme
- Bildirim görüntüleme
- Bildirim Davranışı
- Sık Karşılaşılan Bildirim Desenleri
- Push bildirimleri ile ilgili SSS
- Sık Karşılaşılan Sorunlar ve Hata Bildirimleri