..

Web push bildirishnomalar yuborish

Loyihani qo'llab quvvatlash uchub buyerga bosing

Push bildirishnomalar bugungi kunda foydalanuvchilar bilan doimiy kontent ulashish va ularni doimiy aktiv ushlashning eng yaxshi usullaridan biri hisoblanadi. Shuningdek ushbu metodning qulayliklaridan biri deyarli barcha qurilmalarda brauzerning o’zida to’g’ridan to’g’ri qo’llay olishi hisoblanadi.

Odatda bunday xizmatni taklif etadigan ko’plab servislar mavjud. Ammo ularning qimmatligi doim ham dasturchiga maqul kelmasligi mumkin. Aslida esa google firebase orqali bu ishni osonroq bajarish imkoni ham mavjud. Bugun esa anan shu metodni ko’rib chiqamiz.

Talablar:

Bu qanday ishlaydi?

Push bildirishnomalar ishlashi aslida juda murakkab emas. Ayni damda brauzerlarda buning uchun deyarli barcha apilar mavjud.

Xabarlar push serveriga yuboriladi (Firebase, Mozilla Push Service), shundan so’ng mijoz brauzeridagi service worker (ishchi) push xabarni qabul qilib oladi va kerakli ma’lumotni ko’rsatadi. Ushbu amallar esa VAPID (Voluntar Application Server Identification) protokoli orqali amalga oshiriladi.

Identifikatsiya uchun VAPID kalit generatsiya qilish:

VAPID kalitlar uchun Prime 256v1 shifrlash metodi kerak bo’ladi. Bu ishni openssl kutubxonasi orqali amalga oshirish mumkin. Shundan so’ng shifr kordinatalari base64da olinadi va umumiy identifikatsiya uchun ishlatiladi.

Bunga ko’ra kalit turi ikki xil public va private bo’lishi lozim. Public kalit web sahifada ishlatildi, private esa push servisga ma’lumotlarni yuborish vaqtida apiga murojaat qilish uchun qo’llaniladi.

<?php

function base64UrlEncode($data) {
    return rtrim(
        strtr(
            base64_encode(
                $data
            ),
            '+/',
            '-_'
        ),
        '='
    );
}

function generateVAPIDKeys($privateKeyPath = 'private_key.pem') {
    $keyResource = openssl_pkey_new([
        "private_key_type" => OPENSSL_KEYTYPE_EC,
        "curve_name" => "prime256v1"
    ]);

    if ( ! $keyResource ) {
        throw new Exception("Kalitni generatsiya qilishda xatolik: " . openssl_error_string());
    }

    if ( ! openssl_pkey_export_to_file( $keyResource, $privateKeyPath ) ) {
        throw new Exception("Kalitni saqlashda xatolik: " . openssl_error_string());
    }

    echo "Kalit $privateKeyPath fayliga saqlandi" . PHP_EOL;

    $keyDetails = openssl_pkey_get_details( $keyResource );
    
    if ( ! $keyDetails || ! isset( $keyDetails['ec']['x'], $keyDetails['ec']['y'] ) ) {
        throw new Exception( "Kalit kordinatalarini olishda xatolik!" );
    }

    $rawPublicKey = "\x04" . $keyDetails['ec']['x'] . $keyDetails['ec']['y'];
    $publicKey = base64UrlEncode( $rawPublicKey );

    $privateKeyDetails = openssl_pkey_get_private( file_get_contents( $privateKeyPath ) );
    $privateKey = base64UrlEncode( openssl_pkey_get_details( $privateKeyDetails )['ec']['d'] );

    return [
        'publicKey' => $publicKey,
        'privateKey' => $privateKey,
    ];
}

try {
    $vapidKeys = generateVAPIDKeys();
    echo "Public kalit: " . $vapidKeys['publicKey'] . PHP_EOL;
    echo "Private kalit: " . $vapidKeys['privateKey'] . PHP_EOL;
} catch (Exception $e) {
    echo "Xatolik: " . $e->getMessage() . PHP_EOL;
}

Service worker:

Ushbu servis brauzerni fon rejimida push servis yangilanishlarini kuzatishga yordam beradi. Shuningdek u ma’lumotlarni o’ziga qabul qilib kerakli amalni bajarishni ham ta’minlaydi.

Eslatma: Ushbu demo bildirishnoma yuborish sifatida ko’rsatilmoqda, siz push servisdan fantaziyangizga qarab absolut boshqa maqsadlarda foydalanishingiz ham mumkin. Masalan qanaqadir configlarni sozlash, qurilmalarni sinxronizatsiya qilish kabi.

//sw.js
self.addEventListener('push', (event) => {
    const data = event.data ? event.data.json() : {};
    const title = data.title || 'Bildirishnoma';
    const options = {
        body: data.body || 'Yangi xabar qabul qilindi',
        icon: '/icon.png',
    };
    event.waitUntil(self.registration.showNotification(title, options));
});

self.addEventListener('notificationclick', (event) => {
    event.notification.close();
    event.waitUntil(
        clients.openWindow('/')
    );
});

Service worker faqatgina fon rejimida ishlay olish qobiliyatiga ega, shu sababli uni asosiy sahifadan ro’yxatdan o’tkazish va mijoz uchun push service ma’lumotlarin saqlab olish kerak.

Mijoz qism:

//app.js
const applicationServerKey = 'PUBLIC_KEY';

function urlBase64ToUint8Array( base64String ) {
    const padding = '='.repeat( ( 4 - ( base64String.length % 4 ) ) % 4 );
    const base64 = ( base64String + padding ).replace( /-/g, '+' ).replace( /_/g, '/' );
    const rawData = window.atob( base64 );
    const outputArray = new Uint8Array( rawData.length );
    for ( let i = 0; i < rawData.length; ++i ) {
        outputArray[ i ] = rawData.charCodeAt( i );
    }
    return outputArray;
}

async function subscribeUser() {
    if ( 'serviceWorker' in navigator ) {
        try {
            const registration = await navigator.serviceWorker.register( '/sw.js' );
            const subscription = await registration.pushManager.subscribe({
                userVisibleOnly: true,
                applicationServerKey: urlBase64ToUint8Array( applicationServerKey ),
            });
            const data = JSON.stringify( subscription, null, "\t" );
            document.getElementById( "log" ).innerText = data;
            console.log("Obuna ma'lumotlari:", log);
        } catch ( error ) {
            console.error( "Push bildirishnomalarga obuna bo'lishda xatolik:", error );
        }
    } else {
        console.warn( "Ushbu brauzer service workerni qo'llab quvvatlamaydi" );
    }
}

document.getElementById( "subscribe" ).addEventListener( "click", function ( e ) {
  subscribeUser();
});

Psevdo UI:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Push obuna</title>
</head>
<body>
	<button id="subscribe" >Obuna bo'lish</button>
	<pre id="log"></pre>
	<script src="app.js"></script>
</body>
</html>

Shundan so’ng script sizga quyidagicha json ma’lumotini beradi:

{  
	"endpoint": "https://fcm.googleapis.com/fcm/send/----------",  
	"expirationTime": null,  
	"keys": {  
		"p256dh": "----",  
		"auth": "----"  
	}  
}

BIldirishnoma yuborish:

Ushbu jarayon https://github.com/web-push-lib repositoriyasi o’zida deyarli barcha tillar uchun mos bo’lgan kutubxonalarni mujassam etgan. Quyida esa php orqali yuborishga kichik misol:

require 'vendor/autoload.php';
use Minishlink\WebPush\Subscription;
use Minishlink\WebPush\WebPush;

$subscription = [
    'endpoint' => '---',
    'keys' => [
        'p256dh' => '---',
        'auth' => '---',
    ],
];

$payload = json_encode([
    'title' => 'Salom!',
    'body' => 'Bu serverdan bildirishnoma!'
]);

$auth = [
    'VAPID' => [
        'subject' => 'mailto:user@dmain.uz',
        'publicKey' => '---',
        'privateKey' => '---',
    ],
];

$webPush = new WebPush($auth);
$report = $webPush->sendOneNotification( Subscription::create($subscription), $payload, ['TTL' => 5000]);
var_dump( $report->isSuccess() );