15 min read
Anpassade flikar och JS Bridge
Ett vanligt problem när man lägger till en anpassad flik – en inbäddad webbsida med en enda angiven URL som är tillgänglig i Android- eller iOS-appen – med innehåll från externa källor är att detta innehåll ligger på en separat webbsida och inte kan kommunicera direkt med Android- eller iOS-appen, eftersom appen ser den anpassade fliken som en ”svart låda” vars gränser inte kan överskridas. För att lösa detta kan du använda JavaScript-SDK:t JS Bridge, som gör det möjligt att programmatiskt kommunicera på klientsidan med den inbyggda appen och den inbäddade webbsidan via JavaScript-anrop.
Fördelarna med att implementera JS Bridge:
- Delad inloggning — användarna loggar in en gång, oavsett om de loggar in via den inbyggda appen eller via den inbäddade webbsidan;
- Inbyggda varningar om bristande åtkomst — visar appens egen varning när en användare saknar åtkomst till premiuminnehåll (låst av prenumeration), istället för att du behöver skapa en egen;
- Delat samtycke — användarnas samtyckesval synkroniseras mellan den inbyggda appen och din webbsida;
- Ljud i appen — ljud på din webbsida kan spelas upp via den inbyggda ljudspelaren i den inbyggda appen;
- Integration med startsidan — innehållet på din sida kan visas som objekt på den inbyggda appens startsida som innehåll för en startsidskomponent;
- Hantering av pushmeddelandeämnen — användare kan välja vilka av dina pushmeddelandeämnen de vill prenumerera på;
Var börjar jag?
Om det här är första gången du konfigurerar JS Bridge kan du komma igång så här:
- Meddela Prenlys helpdesk så att de kan aktivera integrationen på Prenlys sida.
- Installera JS Bridge SDK på den inbäddade webbsidan som du kommer att lägga till eller redan har lagt till som en anpassad flik i din e-tidningsapplikation via Prenly Workspace.
- Initiera SDK:t på webbsidan och anropa de API-funktioner du behöver.
- Kontrollera att JS Bridge är aktivt.
- Testa din implementering innan du går live.
Resten av denna guide går igenom vart och ett av dessa steg i detalj. Om du fastnar på ett tekniskt begrepp, kolla den tekniska referensen i slutet av artikeln för ytterligare information.
Hur implementeras det?
1. Meddela Prenlys helpdesk för att aktivera funktionen
När JS Bridge har lagts till på din sida ska du meddela Prenlys helpdesk på hello@prenly.com. JS Bridge är en kostnadsfri tilläggsfunktion som kan behöva aktiveras för din applikation. Tills funktionen är aktiverad kommer API:et att returnera undefined när det anropas (se Hur vet jag att JS Bridge är aktivt?).
2. Aktivera i den anpassade fliken i PWS…
JS Bridge är som standard inte aktivt för den inbäddade webbsidan. Du kan aktivera det i menyns byggverktyg i applikationshanteraren i Prenly Workspace.
3. Installera JS Bridge-biblioteket
Du kan installera JavaScript-biblioteket JS Bridge SDK antingen som ett npm-paket eller låta klienten hämta det direkt från GitHub.
npm
Besök npm för att hitta installationsanvisningar, eller kör helt enkelt:
npm i prenly-js-bridge
GitHub
Du behöver inte använda npm. Du kan importera SDK direkt från GitHub om du föredrar det.
Besök GitHub. Importera SDK till din webbsida via exemplet
import PrenlyAppSDK from "https://raw.githubusercontent.com/Textalk/prenly-js-bridge/refs/heads/main/dist/prenly-app-sdk.es.js";
I handboken utgår vi från att du installerar SDK:t via npm.
4. Initiera SDK:t på webbsidan
Importera biblioteket och skapa en instans av det. Detta ger dig api-objektet, vilket är det du kommer att använda för alla JS Bridge-funktioner som beskrivs i handboken. Behåll referensen till api och använd den för att anropa varje önskad funktion.
import PrenlyAppSDK from "prenly-js-bridge";
const { api } = new PrenlyAppSDK();
5. Använd JS Bridge-funktionerna
När det är installerat och aktiverat kan du använda JavaScript-funktionerna som tillhandahålls av JS Bridge för att interagera med den inbyggda appen. Varje funktion stöds av en eller flera API-funktioner som valfritt kan anropas:
| Prenly-funktion | Vad den gör | Funktioner du kommer att använda |
|---|---|---|
| Delad inloggning | Användarna loggar in en gång, antingen via den inbyggda appen eller din webbsida | api.login(), api.logout(), api.getUserJwt() |
| Varning om bristande åtkomst | Visar den inbyggda varningen i den inbyggda appen när en användare saknar åtkomst till premiuminnehåll | api.showNoAccessAlert() |
| Synkronisering av samtycke | Användarens samtyckesval delas mellan den inbyggda appen och din webbsida | api.getUserConsent(), api.showUserConsentDialog() |
| Ljudspelare i appen | Ljud på din sida spelas upp via den inbyggda appens inbyggda spelare | api.playPauseAudio(), api.queueDequeueAudio(), api.getAudioStatus() |
| Webbinnehållskomponent på startsidan | Ditt innehåll visas som objekt på appens startsida | api.setComponentData() |
| Ämnen för push-meddelanden | Användarna väljer vilka av dina push-ämnen de vill prenumerera på (JS Bridge skickar inte push-meddelanden själv – se anmärkning nedan) | api.getPushTopics(), api.subscribePushTopics(), api.unsubscribePushTopics() |
För en fullständig lista över tillgängliga funktioner, händelser och scheman, se Prenly App SDK – JS Bridge på GitHub. Betrakta denna handbok som en ”kom igång”-version och använd README (på GitHub) som den fullständiga referensen.
Observera att JS Bridge endast låter användare hantera sina prenumerationer på push-ämnen – den kan inte själv skicka push-meddelanden. Att skicka ett push-meddelande eller skapa ett nytt push-ämne görs i Prenly Workspace.
Varje API-funktion returnerar ett Promise, så använd await eller .then() för att hämta resultatet. Varje funktion kan avvisa begäran, så det rekommenderas starkt att alltid omsluta funktionsanrop medtry/catch och kontrollera error.code (se felkoder för begäran):
try {
const userJwt = await api.getUserJwt();
} catch (error) {
if (api.isRequestError(error) && error.code === "rejected") {
// Användaren eller appen avvisade begäran.
}
}
Utöver dessa funktioner utlöser JS Bridge även anpassade händelser som din kod kan lyssna efter. Du kan till exempel lyssna efter userLogin för att få reda på när en användare loggar in i den inbyggda appen:
api.on("userLogin", (userData) => {
// Körs automatiskt varje gång användaren loggar in.
});
Varje funktion har också en förväntad ordning för när funktionerna ska anropas. De följande avsnitten guidar dig genom den förväntade ordningen för funktionsanrop.
Inloggnings- och utloggningsflöde
Kontrollera alltid om användaren redan är inloggad innan du bestämmer vad som ska visas eller göras. Undvik att anropa api.login() för en användare som redan är inloggad.
- Anropa
api.getUserJwt()och verifiera samt avkoda svarsfältetjwtför att läsais_logged_in-anspråket. - Om
is_logged_inärfalseär användaren för närvarande inte autentiserad (inloggad). Visa då alternativet ”Logga in” som anroparapi.login(). - Om
is_logged_inärtrueär användaren autentiserad. Visa då ett ”Logga ut”-alternativ som istället anroparapi.logout()för att låta användaren logga ut.
Om du inte vill styra in- eller utloggningsflödet kan du, istället för att förlita dig på `api.login()` och `api.logout `, lyssna på händelserna `userLogin ` och ` userLogout `, så att ditt användargränssnitt förblir korrekt om användaren loggar in eller ut från någon annanstans i appen medan den anpassade fliken som visar din webbsida är öppen.
Om användaren är inloggad kan du kontrollera den avkodade JWT-anspråket `prenly_package_slugs` för att se vilka prenumerationer Prenly känner till för användaren. Om den prenumeration som krävs för att läsa ditt innehåll saknas, anropa `api.showNoAccessAlert()` istället för att skriva ditt eget ”ingen åtkomst”-meddelande. Detta gör att varningsmeddelandena blir konsekventa med resten av appen.
Samtyckesflöde
- Anropa först
api.getUserConsent()för att läsa användarens befintliga val (nullom ingen CMP används). Resultatet består av två delar:prenly_purpose_grants, en fast uppsättning syften (funktionella,analytiska,marknadsföringssyften), ochcmp_purpose_grants, som använder de syften som din specifika CMP definierar. - Innan du gör något som är beroende av ett samtyckesändamål, kontrollera det relevanta fältet. Ladda till exempel endast ett analysskript om
prenly_purpose_grants.analyticalärsant. - Om ett nödvändigt syfte inte har godkänts av användaren, anropa
api.showUserConsentDialog()för att låta användaren godkänna det, och kontrollera sedan igen medapi.getUserConsent()(eller vänta på händelsen nedan) innan du fortsätter.
const consent = await api.getUserConsent();
if (consent?.prenly_purpose_grants?.analytical) {
// Ladda ditt analysskript.
} else {
// Ladda det inte – eller anropa först api.showUserConsentDialog() för att fråga.
}
Du kan lyssna på den anpassade händelsen userConsentChange för att reagera på förändringar i användarens samtycke i den inbyggda appen.
Flöde för ljuduppspelning
-
Anropa först
api.getAudioStatus(AudioId)(eller spåra status via händelsenaudioStatusChange) så att ditt användargränssnitt visar rätt status för ”Spela” eller ”Pausa” innan användaren gör något.Observera: du kan inte fråga den inbyggda appen om tillgängliga ljud-ID:n; därför kan du lyssna på den anpassade händelsen
audioStatusChangeför att få det ljud som spelas upp just nu. - Anropa
api.playPauseAudio(AudioData)för att starta uppspelningen eller pausa den om den redan pågår. - Kontrollera den aktuella ljudstatusen och lägg sedan till i kön om ljudet för närvarande inte finns i kön, eller ta bort ljudet från kön genom att anropa
api.queueDequeueAudio(AudioData).
Lyssna efter audioStatusChange för att hålla dig synkroniserad, särskilt eftersom ljuduppspelningen kan ändras utanför din webbsida och appen kan spela upp ljud som inte är tillgängligt från din webbplats.
Flöde av push-meddelandeämnen
-
Anropa alltid
api.getPushTopics()först för att hämta listan över giltiga ämnes-ID:n och respektive ämnes aktuella prenumerationsstatus.Hårdkoda inte och gissa inte ett tillgängligt ämnes-ID för push-meddelanden
- Använd ID:n från det svaret när du anropar
api.subscribePushTopics()ellerapi.unsubscribePushTopics().
Ingen av funktionerna för push-meddelandeämnen har en egen specifik felkod; om en funktion misslyckas får du en av de allmänna felkoderna för förfrågningar (rejected, not_supported eller feature_disabled) istället för något i stil med get_push_topics_failed.
const { topics } = await api.getPushTopics();
const newsTopic = topics.find((t) => t.name === "News");
if (newsTopic.subscribed) {
await api.unsubscribePushTopics({ ids: [newsTopic.id] });
} else {
await api.subscribePushTopics({ ids: [newsTopic.id] });
}
5. Om webbinnehållskomponenten ska användas
Om du vill att en artikel eller annat innehåll som visas på din webbsida även ska visas på appens startsida som en startsidskomponent, gör då så här…:
-
Skapa en ny startsidekomponent för webbinnehåll i Prenly Workspace.
Kopiera den unika identifieraren som genereras av startsidskomponenten.
- Konfigurera källan i komponentinställningarna och välj den anpassade fliken som visar din webbsida.
- Gör eventuella ytterligare inställningar för din komponent, spara den och publicera sedan komponenten så att den blir tillgänglig på appens startsida.
- I din JS Bridge -implementering anropar du
api.setComponentData()med den identifieraren och de objekt du vill visa, till exempel:
await api.setComponentData({
id: "<komponentens unika identifierare>",
items: [
{
id: "article-1",
header: "Rubrik här",
subheader: "Kort teasertext",
deeplink_url: "https://example.com/article-1",
image_url: "https://example.com/images/article-1.jpg",
},
],
});
Varje objekt du skickar in blir en klickbar ruta på startsidan, som länkar tillbaka till innehållet i din anpassade flik.
Observera att du inte ska förväxla startsidskomponenten för webbinnehåll med en Web API-webbkomponent.
Hur vet jag om JS Bridge är aktivt?
Kontrollera om api är definierat efter att SDK har instansierats:
const { api } = new PrenlyAppSDK();
if (api) {
// JS Bridge är aktivt — du kan anropa API-funktioner.
} else {
// Ännu inte aktivt. Antingen har biblioteket inte laddats korrekt,
// eller så har det inte aktiverats för den anpassade fliken i Prenly Workspace
}
Om `api` är odefinierat, kontrollera noga att du har slutfört steg 1 (meddelat Prenly Helpdesk) och att du tittar på webbsidan som är inbäddad i din app, inte i en vanlig webbläsarflik.
Hur kan jag testa JS Bridge?
Det finns ingen särskild testmiljö för JS Bridge. Hur testningen ser ut beror på vad som finns tillgängligt för dig:
-
Om du har en sandbox-app kan du använda den för att testa din implementering innan den går live.
Om du är osäker, kontrollera vilka applikationer som finns tillgängliga i Prenly Workspace eller kontakta Prenly Helpdesk för att begära en.
-
Om du inte har en sandbox-app sker testningen live: när JS Bridge har konfigurerats och aktiverats för din anpassade flik (se stegen ovan) testar du direkt i produktionsappen.
Obs! En produktionsapp kan inte gå in i felsökningsläge, vilket gör att du inte kan använda Safari för att granska den anpassade fliken i din iOS-app eller Google Chrome för att granska den anpassade fliken i din Android-app.
- Bekräfta aktiveringen med hjälp av
API-kontrollen som beskrivs i ”Hur vet jag att JS Bridge är aktivt?”. Detta är det snabbaste sättet att upptäcka ett konfigurationsfel innan du testar enskilda funktioner. - Observera det synliga resultatet av varje funktion. Anropa till exempel
api.login()och kontrollera att appens eget inloggningsläge ändras.
api.on("userLogin", (userData) => {
// Att denna återanrop utlöses (och appens användargränssnitt uppdateras) bekräftar att inloggningsflödet fungerade.
});
Om en begäran fortsätter att misslyckas eller om ingenting förändras kan det hända att funktionen ännu inte har aktiverats för ditt konto – kontakta Prenlys helpdesk på hello@prenly.com så att de kan hjälpa dig att aktivera JS Bridge.
Felsökningsläge (konsolåtkomst)
För att kunna läsa konsolloggar eller inspektera error.code-värden direkt måste felsökningsläget vara aktiverat för din anpassade flik. Detta är inte något du kan aktivera själv – det kräver en speciell appvariant som endast Prenlys helpdesk kan aktivera för både Android och iOS. Om du behöver denna åtkomstnivå under utvecklingen ska du begära den från Prenly Helpdesk på hello@prenly.com; utgå inte från att den redan är tillgänglig.
Teknisk referens
Begreppen nedan förekommer genomgående i denna guide. De finns här så att du inte behöver lämna sidan för att slå upp dem.
Vad är ett SDK?
SDK, eller Software Development Kit, är en uppsättning verktyg för mjukvaruutveckling som finns tillgängliga i ett enda paket och som möjliggör integration med målsystemet.
Vad är npm?
npm är den vanligaste pakethanteraren för JavaScript. Att ”installera ett paket” innebär att ladda ner en kod (i det här fallet JS Bridge- biblioteket) och lägga till den i ditt projekt, vanligtvis genom att köra ett kommando som npm i prenly-js-bridge i projektets terminal. Paketet blir då tillgängligt för import i din kod.
Vad är ett Promise?
Ett Promise representerar ett värde som ännu inte är tillgängligt men som kommer att bli det vid någon tidpunkt. Till exempel resultatet av att be appen att logga in användaren. Du hanterar det vanligtvis med await inuti en async-funktion, eller med .then()/.catch():
// Använda `await` (inuti en `async`-funktion):
const result = await api.getUserJwt();
// Använda .then()/.catch():
api
.getUserJwt()
.then((result) => {
/* ... */
})
.catch((error) => {
/* ... */
});
Om löftet avvisas (något gick fel) körs koden i ditt catch-block och tar emot felet som du kan granska – se felkoder för begäran nedan.
Vad är fetch()?
fetch() är det vanligaste sättet att göra en HTTP(s)-förfrågan från JavaScript – till exempel att skicka data från din sida till din egen HTTP-server. Den returnerar ett Promise, så den används med await/.then() på samma sätt som API-funktionerna:
await fetch("https://your-backend.example.com/session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jwt: userJwt.jwt }),
});
Detta har inget att göra med JS Bridge i sig; det är det vanliga sättet som en webbsida kommunicerar med en server på, och används här eftersom JS Bridge endast finns på klientsidan och inte skickar något till din HTTP-server på egen hand.
Vad är en händelselyssnare?
Funktioner som api.getUserJwt() är saker du begär. Händelser är motsatsen: de är anpassade aviseringar som JS Bridge utlöser automatiskt när något händer baserat på användarens interaktion med appen, och din webbsida kan ”reagera” på det. Till exempel när användaren loggar in eller ut.
Du prenumererar med api.on(eventType, handler), där handler är en funktion som körs varje gång händelsen utlöses:
api.on("userLogin", (userData) => {
// Körs automatiskt varje gång användaren loggar in.
});
Avsluta lyssnandet med api.off(eventType, handler) (eller api.off(eventType) för att ta bort alla hanterare för den händelsen). Se README-filen på GitHub för en fullständig lista över tillgängliga händelser.
Vad är en JWT?
En JWT (JSON Web Token) är en kompakt, signerad sträng som används för att representera en användares identitet och uppgifter om denne. api.getUserJwt() och inloggnings-/utloggningsfunktionerna returnerar en sådan. Du måste verifiera och avkoda den med hjälp av Prenlys certifikat innan du läser något i den – betrakta inte den råa strängen som läsbar i sig. När den väl har avkodats innehåller nyttolasten, utöver standarduppgifter som given_name och email, även Prenly-specifika uppgifter:
{
"given_name": "Jane",
"family_name": "Doe",
"email": "jane@example.com",
"customer_number": "12345",
"prenly_package_slugs": ["premium"],
"is_logged_in": true
}
För mer information om JWT i allmänhet (inte specifikt för Prenly), se introduktionen på jwt.io. Under utvecklingen kan du också klistra in en JWT i JWT-felsökaren på jwt.io för att granska dess header och payload (undvik att klistra in en riktig användares JWT där, eftersom payloaden innehåller deras personuppgifter (namn, e-postadress osv.); använd istället testdata).
Obs! Vilka anspråk som är tillgängliga beror på vilket inloggningssystem appen använder. Det enda garanterade anspråket är is_logged_in.
Om din HTTP-server också behöver information om den inloggade användaren (till exempel för att skapa en session), skicka den relevanta informationen själv, t.ex. med en fetch() -förfrågan till din egen slutpunkt:
await fetch("https://your-backend.example.com/session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jwt: userJwt.jwt }),
});
Hur din HTTP-server hanterar den begäran – verifierar den på nytt, skapar en session eller något annat – är din egen implementering och faller utanför ramen för den här handboken.
Detta certifikat genereras och tillhandahålls av Prenly – du kan inte skapa eller tillhandahålla ett eget. Prenly levererar det till dig om din konfiguration kräver ett, eller så kan du begära det från Prenlys helpdesk på hello@prenly.com. En konfiguration som använder något annat certifikat kommer inte att fungera.
Vad är en CMP, och vad betyder ”samtycke” i detta sammanhang?
En CMP (Consent Management Platform) är det system som ber användarna om deras samtycke till integritetshantering (t.ex. för analys- eller marknadsföringscookies) och lagrar deras val. api.getUserConsent() låter din anpassade flik läsa av det samtycke som användaren redan har gett i Prenly-appen, så att du inte behöver be dem om det igen separat.
Felkoder för förfrågningar
När ett Promise från en API-funktion avvisas innehåller felobjektet en kod som du kan kontrollera. Vissa koder är allmänna och kan komma från vilken funktion som helst; andra är specifika för ett visst flöde. En funktion utan en särskild felkod (t.ex. getPushTopics(), getUserConsent()) genererar alltid endast en allmän kod:
| Kod | Gäller | Betydelse |
|---|---|---|
avvisad |
Alla funktioner | Begäran avvisades av användaren eller appen. |
not_supported |
Vilken funktion som helst | Den begärda funktionen stöds inte av appen (t.ex. en gammal appversion). |
feature_disabled |
Vilken funktion som helst | Funktionen har inte aktiverats för ditt konto – se steg 3. |
login_failed |
api.login() |
Inloggningsprocessen misslyckades. |
logout_failed |
api.logout() |
Utloggningsflödet misslyckades. |
play_pause_audio_failed |
api.playPauseAudio() |
Det gick inte att spela upp eller pausa ljudet. |
queue_dequeue_audio_failed |
api.queueDequeueAudio() |
Det gick inte att lägga till eller ta bort ljud från kön. |
set_component_data_failed |
api.setComponentData() |
Det gick inte att skicka data till startsidans komponent. |
För en fullständig och alltid uppdaterad lista över funktioner, händelser och datamodeller, se README på GitHub.