Push Notifications
Push-ilmoitukset voivat saavuttaa käyttäjät jopa silloin, kun sovellus ei ole avoinna. Selain tilaa sen kerran, sovellus tallentaa tilauksen ja palvelin käyttää sitä ilmoitusten toimittamiseen tapahtumien esiintyessä. Push hallitsee tilausta ja peruutusta selaimessa. Palvelimella PushSender lähettää PushMessage:n tallennettuun tilaukseen.
Asennus ja vaatimus
Push-ilmoitukset tarjotaan erillisellä moduulilla. Lisää se sovellukseesi:
- Maven
- Gradle
<dependency>
<groupId>com.webforj</groupId>
<artifactId>webforj-push</artifactId>
</dependency>
dependencies {
implementation 'com.webforj:webforj-push'
}
Push-ilmoitukset vaativat:
- Servlet-levitys, kuten Jetty, Spring Boot tai WAR-tiedosto.
- Avaipari, joka on luotu alla, jota levitys käyttää ilmoitusten allekirjoittamiseen.
- Turvallinen alkuperä. Selaimet hylkäävät tilaukset, joita tarjotaan muilla kuin
https-protokollilla, paitsilocalhost-osoitteesta kehityksen aikana.
Lisätietoja turvallisista konteksteista ja niiden tärkeydestä saat Turvalliset kontekstit MDN dokumentista.
Avainten luominen
Push-palvelut hyväksyvät vain ilmoituksia, joita on allekirjoitettu levityksellä, johon selain on tilannut. Suorita rakennuslaajennus kerran jokaiselle levitykselle avainparin luomiseksi:
- Maven
- Gradle
mvn webforj:push-keys
./gradlew webforjPushKeys
Komentorivi tulostaa kolme konfiguraatiorivie. Liitä ne application.properties-tiedostoon ilman lainausmerkkejä, tai kopioi ne sellaisenaan webforj.conf-tiedostoon. Korvaa aiheella levityksen yhteystiedot. Sen on oltava mailto: tai https://-osoite, jota push-palvelut voivat käyttää operaattorin tavoittamiseen.
webforj.push.public-key=...
webforj.push.private-key=...
webforj.push.subject=mailto:ops@example.com
| Ominaisuus | Selitys |
|---|---|
webforj.push.public-key | Avaiparin julkinen osa, jota levitys käyttää ilmoitusten allekirjoittamiseen |
webforj.push.private-key | Avaiparin yksityinen osa. Kuten muutkin salaisuudet, pidä se poissa lähdekoodin hallinnasta |
webforj.push.subject | Levityksen yhteystiedot. Sen on oltava mailto: tai https://-osoite, jonka kautta push-palvelut voivat tavoittaa operaattorin |
Sovellus lukee nämä ominaisuudet käynnistyksen yhteydessä. Jos konfiguraatio sisältää vain osan niistä, käynnistys epäonnistuu ja ilmoittaa puuttuvat ominaisuudet.
Jokainen selain tilaavat yhden avainparin. Jos avaimet muuttuvat, push-palvelu hylkää olemassa olevat tilaukset. Seuraava subscribe()-kutsu jokaisessa selaimessa korvataan sen tilaus.
Miten se toimii
Prosessissa on kolme vaihetta:
- Tilaa. Näkymästä
Push.getCurrent().subscribe()pyytää käyttäjän lupaa ja palauttaaPushSubscription:n, joka tunnistaa selaimen osoitteen. - Tallenna. Sovellus tallentaa tilauksen sen tietojen kanssa ja yhdistää sen vastaavaan käyttäjään.
- Lähetä. Myöhemmin, mistä tahansa säikeestä,
PushSender.send(subscription, message)välittää viestin selaimen tarjoajalle push-palvelulle. Palvelu näyttää ilmoituksen riippumatta siitä, onko sovellus avoinna vai ei.
Push.getCurrent().subscribe().thenAccept(subscriptions::save);
sender.send(subscription,
PushMessage.create("Tilauksen toimitus").setUrl("/tilaukset/42").build());
Seuraavat osat selittävät, mitä selain näyttää ja kuinka käsitellä epäonnistumisia jokaisessa vaiheessa.
Instanssi
Hanki push-instanssi nykyisestä ympäristöstä:
import com.webforj.push.Push;
Push push = Push.getCurrent();
if (Push.isPresent()) {
// ...
}
Push.ifPresent(p -> {
// ...
});
Selaimen tilaaminen
Kutsu subscribe() vastauksena käyttäjän toimintaan, kuten napsauttamalla "Ota ilmoitukset käyttöön" -painiketta. Palautettu PendingResult valmistuu selaimen PushSubscription:n kanssa. Jos selain ei voi tilata, se valmistuu poikkeuksellisesti WebforjPushException:n kanssa.
PendingResult<PushSubscription> request = Push.getCurrent().subscribe();
request.thenAccept(subscription -> {
subscriptions.save(subscription);
});
request.exceptionally(throwable -> {
WebforjPushException error = (WebforjPushException) throwable.getCause();
PushStatus status = error.getStatus();
String message = error.getMessage();
return null;
});
Jos selain on jo tilattu, subscribe()-kutsuminen palauttaa olemassa olevan tilauksen. Voit siten kutsua sitä turvallisesti jokaisella vierailulla.
Ensimmäinen kutsu subscribe() pyytää käyttäjältä lupaa. Selain näyttää tämän kehotteen, se ei ole osa sovelluksen UI:ta. Koska selaimet näyttävät kehotteen vain käyttäjän toiminnan seurauksena, kutsu subscribe() napsautustapahtumasta sen sijaan, että näkymäkonstruoitteesta.
Jos käyttäjä estää kehotteen, sovellus ei voi pyytää sitä uudelleen tälle alkuper älle.
Tilauksien tallentaminen
Tilaus edustaa yhden selaimen osoitetta ja kuuluu palvelimelle. Tallenna se sovelluksen tietojen kanssa, käyttäen sen päätepistettä avaimena. Sisällytä kaikki tiedot, joita sovellus tarvitsee valitakseen oikeat selaimet myöhemmin, kuten liitetty käyttäjä. Jokainen tilaus sisältää kolme tekstiarvoa:
| Arvo | Merkitys |
|---|---|
getEndpoint() | Toimitus-URL, jonka selainpalvelun push-palvelu on määrittänyt |
getP256dh() | Selaimen julkinen avain |
getAuth() | Selaimen vahvistussalaisuus |
Käyttäjä, joka tilaa kahdesta selaimesta, saa kaksi tilausta. Poista tilaus, kun sen selain peruuttaa tai kun lähetys ilmoittaa, että se on vanhentunut. Katso Epäonnistumistila.
Tilauksen palauttaminen
getSubscription() palauttaa selaimen nykyisen tilauksen tai tyhjät tulokset, jos sellaista ei ole. Käytä sitä synkronoimaan palvelimen kopiot, esimerkiksi sen jälkeen, kun sovelluksen tallennus on palautettu:
Push.getCurrent().getSubscription().thenAccept(existing -> {
existing.ifPresent(subscriptions::save);
});
Kautta PushPermission, getPermission() ilmoittaa, onko käyttäjä myöntänyt, evännyt tai ei ole vielä vastannut ilmoituskehotteeseen. Käytä tätä tulosta piilottaaksesi "Ota ilmoitukset käyttöön" -painikkeen, jos sen napsauttaminen ei vaikuta.
Peruuttaminen
unsubscribe() peruuttaa selaimen tilauksen. Se valmistuu poistetuilla tilauksilla, jotta sovellus voi poistaa sen tallennetun kopion tai tyhjillä tuloksilla, jos selaimella ei ollut tilausta.
Push.getCurrent().unsubscribe().thenAccept(removed -> {
removed.ifPresent(subscriptions::delete);
});
Ilmoitusten lähettäminen
PushSender lähettää PushMessage:n tallennettuun tilaukseen. Se allekirjoittaa viestin levityksen avaimilla ja välittää sen selaimen tarjoajan push-palvelulle. Tämä palvelu herättää selaimen ja näyttää ilmoituksen. Koska operaatio ei koskaan estä kutsuvaa säiettä, voit kutsua sitä napsautustapahtumasta, aikataulutetusta työstä tai pyyntö-käsittelystä.
Kun ominaisuudet on konfiguroitu, lähettäjä on saatavilla beanina, jonka voit injektoida näkymiin, palveluihin ja aikataulutettuihin työpäiviin. Jos haluat korvata sen, määritä oma PushSender-beanisi.
@Route("/tilaukset")
public class OrdersView extends Composite<FlexLayout> {
public OrdersView(PushSender sender, PushSubscriptions subscriptions) {
// ...
}
}
Ilman Springiä new PushSender() lukee avaimet sovelluksen konfiguraatiosta. Luo lähettäjä sovellus- säikeessä, joko näkymässä tai App.run()-menetelmässä, ja käytä sitä sitten mistä tahansa säikeestä. Kaikki lähettäjät jakavat yhden yhteyspoolin push-palveluihin, joten niiden luominen missä tahansa tarvitaan ei aiheuta kustannuksia.
Viesteille, jotka on lähetettävä myöhemmin tai käyttäjän poistuttua, käytä palvelimen aikataulutinta, kuten Springin TaskScheduler. Älä käytä sivuaikataulutinta, kuten Interval, koska se pysähtyy, kun välilehti sulkeutuu.
Viestin kokoaminen
Luo viesti sen otsikolla ja määritä sitten jokainen muu vaihtoehto rakennusohjelmassa:
PushMessage message = PushMessage.create("Tilauksen toimitus")
.setBody("Tilaus #42 on matkalla")
.setIcon("icons://icon-192x192.png")
.setUrl("/tilaukset/42")
.setActions(List.of(new PushAction("seuraa", "Seuraa", "/tilaukset/42/seuranta")))
.build();
PendingResult<Void> sent = sender.send(subscription, message);
sent.thenAccept(v -> status.setText("Lähetetty"));
sent.exceptionally(throwable -> {
WebforjPushException error = (WebforjPushException) throwable;
status.setText(error.getStatus() + ": " + error.getMessage());
return null;
});
send() palauttaa heti. PendingResult valmistuu, kun push-palvelu hyväksyy viestin tai valmistuu poikkeuksellisesti, jos palvelu ei hyväksy sitä. Jos send()-kutsu tehdään sovellus-säikeessä, kuten kuuntelijasta, sen palautteet suoritetaan tuolla säikeellä ja voivat päivittää komponentteja. Jos sesio, joka kutsui send(), päättyy ennen kuin vastaus saapuu, palautteet eivät suoriteta, mutta ilmoitus toimitetaan silti.
Send-kutsu odottaa korkeintaan 30 sekuntia push-palvelulta ennen kuin se epäonnistuu UNREACHABLE-tilassa. Käytä setTimeout(Duration) muuttaaksesi aikarajaa jokaiselle lähettäjälle.
| Vaihtoehto | Vaikutus |
|---|---|
setBody | Asettaa tekstin, joka näkyy otsikon alapuolella |
setIcon | Asettaa kuvan, joka näkyy ilmoituksen mukana. Se hyväksyy absoluuttiset URL-osoitteet ja icons://- ja ws://-protokollat. Katso Varat. Se ei hyväksy context://-protokollaa, koska push-palvelut rajoittavat viestin 4 kt:n |
setUrl | Asettaa sivun, joka avautuu, kun käyttäjä napsauttaa ilmoitusta. Suhteelliset URL-osoitteet ratkaistaan sovelluksen juurta vastaan. Jos URL-osoitetta ei aseteta, avautuu sovelluksen juuri |
setActions | Asettaa ilmoituksessa näytettävät painikkeet, joilla on erilliset URL-osoitteet jokaiselle painikkeelle. Katso Selaimen tuki |
setTag | Asettaa tunnistavan tagin. Jos ilmoitus, joka on näkyvissä, on sama tagi, uusi ilmoitus korvataan sillä |
setSilent | Näyttää ilmoituksen ilman ääntä tai tärinää |
setTimeToLive | Asettaa, kuinka kauan push-palvelu säilyttää viestin offline-laitteelle, enintään neljä viikkoa |
setUrgency | Käyttää PushUrgency:a, jotta laite voi viivästyttää alhaisen kiireen viestejä ja säästää akkua |
setTopic | Korvataan viesti, joka on edelleen odottamassa push-palvelussa, kun molemmat viestit sisältävät saman aiheen. Aiheilla voi olla enintään 32 merkkiä, jotka ovat turvallisia URL-osoitteissa |
Kun välilehti näyttää jo sivun, napsauttaminen ilmoituksessa keskittyy sovellukseen. Muuten sivu avautuu uuteen välilehteen. Napsauttaessa ilmoituspainiketta avautuu sen URL-osoite samalla tavalla.
Jokainen viesti näyttää ilmoituksen. Koska selaimet eivät herätä sivua viestille, joka ei näytä mitään, pushia ei voida käyttää hiljaisiin tietopäivityksiin.
Epäonnistumistila
Kun subscribe() tai send() epäonnistuu, sen PendingResult ilmoittaa WebforjPushException:n. PushStatus tunnistaa syyn:
| Tila | Milloin | Mitä tehdä |
|---|---|---|
PERMISSION_DENIED | Käyttäjä on estänyt ilmoitukset sovellukselle | Selitä käyttäjälle, mistä hän voi sallia ilmoitukset selaimen asetuksista |
UNSUPPORTED | Push ei ole tuettu selaimessa, sivu ei ole turvallisessa kontekstissa tai sovellusta ei ole otettu käyttöön servletinä | Piilota toiminto |
NOT_CONFIGURED | Vähintään yksi webforj.push.*-ominaisuus on puuttuva tai puutteellinen | Luo avaimet ja konfiguroi kaikki kolme ominaisuutta |
SUBSCRIPTION_EXPIRED | Push-palvelu ei tunnista tilausta enää, koska käyttäjä peruutti tai asensi selaimen uudelleen | Poista tallennettu tilaus |
REJECTED | Push-palvelu hylkäsi viestin; getStatusCode() sisältää sen vastauksen | Varmista avaimet ja viestin koko |
UNREACHABLE | Push-palvelu ei vastannut ennen aikarajan umpeutumista | Yritä uudelleen myöhemmin |
UNKNOWN | Tallennettu päätepiste ei ole voimassa oleva URL-osoite, tai tilausta tai viestiä ei voitu koodata | Varmista tallennettu tilaus |
Poista vanhentuneet tilaukset jokaisen lähetyksen yhteydessä:
sender.send(subscription, message).exceptionally(throwable -> {
WebforjPushException error = (WebforjPushException) throwable;
if (error.getStatus() == PushStatus.SUBSCRIPTION_EXPIRED) {
subscriptions.delete(subscription);
}
return null;
});
Push-palvelut peruutavat tilauksia laiskasti. Ne hyväksyvät edelleen ensimmäisen viestin sen jälkeen, kun käyttäjä peruuttaa, mutta se ei mene minnekään. Seuraava viesti ilmoittaa SUBSCRIPTION_EXPIRED. Hyväksytyn lähetyksen merkki on se, että viesti saapui push-palveluun, ei että käyttäjä näki sen.
Selaimen tuki
Kaikki suuret työpöytä- ja mobiiliselaimet näyttävät push-ilmoituksia tilaamisen jälkeen. Pidä mielessä seuraavat rajoitukset:
- iPhone- ja iPad-laitteella push toimii vain verkko-sovelluksille, jotka on lisätty Käynnistysnäyttöön iOS 16.4 tai uudemmassa. Safari-välilehdessä
subscribe()ilmoittaaUNSUPPORTED. Katso Asennettavat sovellukset vaadittaessa sovellusmanifesteja varten. - Safari ei näytä ilmoituspainikkeita. Se näyttää viestejä toiminnolla niiden painiketta, mutta napsauttamalla ilmoitusta avaa silti viestin URL-osoitteen.
- Android- ja iOS-web-näkymät eivät näytä ilmoituksia.
Selaimen yksityiskohtia katso MDN showNotification-yhteensopivuustaulukosta.
Täydellinen esimerkki
Seuraava näkymä tilaa ja peruuttaa selaimen, tallentaa tilaukset muistiin ja lähettää viestin jokaiselle tallennetulle tilaukselle. Se voi lähettää välittömästi tai odottaa kahdeksan sekuntia käyttämällä Springin TaskScheduler:ia, joka mahdollistaa välilehden sulkemisen ennen ilmoituksen saapumista. Sovellusluokka käyttää @EnableScheduling-asetusta tehdäksesi aikatauluttajan saatavaksi.
package com.example;
import com.webforj.push.PushSubscription;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Service;
@Service
public class PushSubscriptions {
private final Map<String, PushSubscription> byEndpoint = new ConcurrentHashMap<>();
public void save(PushSubscription subscription) {
byEndpoint.put(subscription.getEndpoint(), subscription);
}
public void delete(PushSubscription subscription) {
byEndpoint.remove(subscription.getEndpoint());
}
public Collection<PushSubscription> findAll() {
return byEndpoint.values();
}
}