iOS
[AEM Headless as a Cloud Service]{class="badge informative"}
Exempelprogram är ett bra sätt att utforska de headless-funktionerna i Adobe Experience Manager (AEM). I det här iOS-programmet visas hur du använder AEM GraphQL-API:er med beständiga frågor.
Visa källkoden på GitHub
Förutsättningar prerequisites
Följande verktyg bör installeras lokalt:
AEM
IOS fungerar med följande distributionsalternativ för AEM. Alla distributioner kräver att WKND-platsen v3.0.0+ är installerad.
- AEM as a Cloud Service
- Lokal konfiguration med SDK för AEM Cloud-tjänsten
IOS-programmet är utformat för att ansluta till en AEM Publish -miljö, men det kan hämta innehåll från AEM Author om autentisering anges i iOS-programmets konfiguration.
Så här använder du
-
Klona
adobe/aem-guides-wknd-graphql
-databasen:code language-shell $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
-
Öppna Xcode och öppna mappen
ios-app
-
Ändra filen
Config.xcconfig
och uppdateraAEM_SCHEME
ochAEM_HOST
så att den matchar AEM-målpubliceringstjänsten.code language-plain // The http/https protocol scheme used to access the AEM_HOST AEM_SCHEME = https // Target hostname for AEM environment, do not include http:// or https:// AEM_HOST = publish-p123-e456.adobeaemcloud.com
Om du ansluter till AEM Author lägger du till autentiseringsegenskaperna
AEM_AUTH_TYPE
och tillhörande autentiseringsegenskaper iConfig.xcconfig
.Grundläggande autentisering
AEM_USERNAME
ochAEM_PASSWORD
autentiserar en lokal AEM-användare med åtkomst till WKND GraphQL-innehåll.code language-plain AEM_AUTH_TYPE = basic AEM_USERNAME = admin AEM_PASSWORD = admin
Tokenautentisering
AEM_TOKEN
är en åtkomsttoken som autentiserar en AEM-användare med åtkomst till WKND GraphQL-innehåll.code language-plain AEM_AUTH_TYPE = token AEM_TOKEN = abcd...0123
-
Bygg applikationen med Xcode och distribuera den till iOS-simulatorn
-
En lista över äventyr från WKND-webbplatsen ska visas i programmet. Om du väljer ett äventyr öppnas äventyrsinformationen. Uppdatera data från AEM genom att dra i äventyrslistvyn.
Koden
Nedan följer en sammanfattning av hur iOS-programmet byggs, hur det ansluter till AEM Headless för att hämta innehåll med GraphQL beständiga frågor och hur dessa data presenteras. Den fullständiga koden finns på GitHub.
Beständiga frågor
I enlighet med bästa praxis för AEM Headless använder iOS-programmet AEM GraphQL-beständiga frågor för att fråga efter äventyrsdata. Programmet använder två beständiga frågor:
wknd/adventures-all
beständig fråga, som returnerar alla äventyr i AEM med en förkortad uppsättning egenskaper. Den här beständiga frågan styr den inledande vyns äventyrslista.
# Retrieves a list of all Adventures
#
# Optional query variables:
# - { "offset": 10 }
# - { "limit": 5 }
# - {
# "imageFormat": "JPG",
# "imageWidth": 1600,
# "imageQuality": 90
# }
query ($offset: Int, $limit: Int, $sort: String, $imageFormat: AssetTransformFormat=JPG, $imageWidth: Int=1200, $imageQuality: Int=80) {
adventureList(
offset: $offset
limit: $limit
sort: $sort
_assetTransform: {
format: $imageFormat
width: $imageWidth
quality: $imageQuality
preferWebp: true
}) {
items {
_path
slug
title
activity
price
tripLength
primaryImage {
... on ImageRef {
_path
_dynamicUrl
}
}
}
}
}
wknd/adventure-by-slug
beständig fråga, som returnerar ett enskilt äventyr frånslug
(en anpassad egenskap som unikt identifierar ett äventyr) med en fullständig uppsättning egenskaper. Den här beständiga frågan styr äventyrsdetaljvyerna.
query ($slug: String!, $imageFormat:AssetTransformFormat=JPG, $imageSeoName: String, $imageWidth: Int=1200, $imageQuality: Int=80) {
adventureList(
filter: {slug: {_expressions: [{value: $slug}]}}
_assetTransform: {
format: $imageFormat
seoName: $imageSeoName
width: $imageWidth
quality: $imageQuality
preferWebp: true
}) {
items {
_path
title
slug
activity
adventureType
price
tripLength
groupSize
difficulty
price
primaryImage {
... on ImageRef {
_path
_dynamicUrl
}
}
description {
json
plaintext
html
}
itinerary {
json
plaintext
html
}
}
_references {
... on AdventureModel {
_path
slug
title
price
__typename
}
}
}
}
Kör GraphQL beständig fråga
AEM beständiga frågor körs över HTTP GET och därför kan vanliga GraphQL-bibliotek som använder HTTP POST, till exempel Apollo, inte användas. Skapa i stället en anpassad klass som kör den beständiga frågan från HTTP GET till AEM.
AEM/Aem.swift
instansierar klassen Aem
som används för alla interaktioner med AEM Headless. Mönstret är:
-
Varje beständig fråga har en motsvarande offentlig funktion (t.ex.
getAdventures(..)
ellergetAdventureBySlug(..)
) iOS-programmets vyer anropas för att hämta äventyrsdata. -
Funktionen public anropar en privat funktion
makeRequest(..)
som anropar en asynkron HTTP GET-begäran till AEM Headless och returnerar JSON-data. -
Varje offentlig funktion avkodar sedan JSON-data och utför alla nödvändiga kontroller eller omvandlingar innan Adventure-data returneras till vyn.
- AEM GraphQL JSON-data avkodas med hjälp av de strukturer/klasser som definieras i
AEM/Models.swift
, som mappar till JSON-objekten som returnerade mitt AEM Headless.
- AEM GraphQL JSON-data avkodas med hjälp av de strukturer/klasser som definieras i
/// # getAdventures(..)
/// Returns all WKND adventures using the `wknd-shared/adventures-all` persisted query.
/// For this func call to work, the `wknd-shared/adventures-all` query must be deployed to the AEM environment/service specified by the host.
///
/// Since HTTP requests are async, the completion syntax is used.
func getAdventures(params: [String:String], completion: @escaping ([Adventure]) -> ()) {
let request = makeRequest(persistedQueryName: "wknd-shared/adventures-all", params: params)
URLSession.shared.dataTask(with: request) { (data, response, error) in
if ((error) != nil) {
print("Unable to connect to AEM GraphQL endpoint")
completion([])
} else if (!data!.isEmpty) {
let adventures = try! JSONDecoder().decode(Adventures.self, from: data!)
DispatchQueue.main.async {
completion(adventures.data.adventureList.items)
}
}
}.resume();
}
...
/// #makeRequest(..)
/// Generic method for constructing and executing AEM GraphQL persisted queries
private func makeRequest(persistedQueryName: String, params: [String: String] = [:]) -> URLRequest {
// Encode optional parameters as required by AEM
let persistedQueryParams = params.map { (param) -> String in
encode(string: ";\(param.key)=\(param.value)")
}.joined(separator: "")
// Construct the AEM GraphQL persisted query URL, including optional query params
let url: String = "\(self.scheme)://\(self.host)/graphql/execute.json/" + persistedQueryName + persistedQueryParams;
var request = URLRequest(url: URL(string: url)!);
// Add authentication to the AEM GraphQL persisted query requests as defined by the iOS application's configuration
request = addAuthHeaders(request: request)
return request
}
...
GraphQL svarsdatamodeller
iOS föredrar att mappa JSON-objekt till datamodeller.
src/AEM/Models.swift
definierar de decoeable Swift-strukturer och klasser som mappar till AEM JSON-svaren som returneras av AEM JSON-svar.
Vyer
SwiftUI används för de olika vyerna i programmet. I Apple finns en självstudiekurs för att komma igång med skapa listor och navigering med SwiftUI.
-
WKNDAdventuresApp.swift
Programposten och innehåller
AdventureListView
vars.onAppear
-händelsehanterare används för att hämta alla äventyrsdata viaaem.getAdventures()
. Det deladeaem
-objektet initieras här och exponeras för andra vyer som ett EnvironmentObject. -
Views/AdventureListView.swift
Visar en lista med äventyr (baserat på data från
aem.getAdventures()
) och visar ett listobjekt för varje äventyr med hjälp avAdventureListItemView
. -
Views/AdventureListItemView.swift
Visar varje objekt i äventyrslistan (
Views/AdventureListView.swift
). -
Views/AdventureDetailView.swift
Visar information om ett äventyr, inklusive titel, beskrivning, pris, aktivitetstyp och primär bild. Den här vyn frågar AEM efter fullständig äventyrsinformation med hjälp av
aem.getAdventureBySlug(slug: slug)
, där parameternslug
skickas baserat på urvalslistraden.
Fjärrbilder
Bilder som refereras av äventyrliga innehållsfragment hanteras av AEM. Den här iOS-appen använder sökvägsfältet _dynamicUrl
i GraphQL-svaret och prefixerar AEM_SCHEME
och AEM_HOST
för att skapa en fullständigt kvalificerad URL. Om du utvecklar mot AE SDK returnerar _dynamicUrl
null, så för utveckling återgår du till bildens _path
-fält.
Om du ansluter till skyddade resurser på AEM som kräver auktorisering, måste autentiseringsuppgifter också läggas till i bildbegäranden.
SDWebImageSwiftUI och SDWebImage används för att läsa in fjärrbilder från AEM som fyller i Adventure-bilden i vyerna AdventureListItemView
och AdventureDetailView
.
Klassen aem
(i AEM/Aem.swift
) underlättar användningen av AEM-bilder på två sätt:
-
aem.imageUrl(path: String)
används i vyer för att lägga till prepend för AEM-schemat och vara värd för bildens sökväg, vilket skapar en fullständigt kvalificerad URL.code language-swift // adventure.image() => /adobe/dynamicmedia/deliver/dm-aid--741ed388-d5f8-4797-8095-10c896dc9f1d/example.jpg?quality=80&preferwebp=true let imageUrl = aem.imageUrl(path: adventure.image()) // imageUrl => https://publish-p123-e456.adobeaemcloud.com/adobe/dynamicmedia/deliver/dm-aid--741ed388-d5f8-4797-8095-10c896dc9f1d/example.jpg?quality=80&preferwebp=true
-
convenience init(..)
iAem
anger rubriker för HTTP-auktorisering på avbildningens HTTP-begäran, baserat på iOS-programkonfigurationen.- Om grundläggande autentisering har konfigurerats bifogas grundläggande autentisering till alla bildbegäranden.
code language-swift /// AEM/Aem.swift /// /// # Basic authentication init /// Used when authenticating to AEM using local accounts (basic auth) convenience init(scheme: String, host: String, username: String, password: String) { ... // Add basic auth headers to all Image requests, as they are (likely) protected as well SDWebImageDownloader.shared.setValue("Basic \(encodeBasicAuth(username: username, password: password))", forHTTPHeaderField: "Authorization") }
- Om tokenautentisering har konfigurerats kopplas tokenautentisering till alla bildbegäranden.
code language-swift /// AEM/Aem.swift /// /// # Token authentication init /// Used when authenticating to AEM using token authentication (Dev Token or access token generated from Service Credentials) convenience init(scheme: String, host: String, token: String) { ... // Add token auth headers to all Image requests, as they are (likely) protected as well SDWebImageDownloader.shared.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") }
- Om ingen autentisering har konfigurerats bifogas ingen autentisering till bildbegäranden.
En liknande metod kan användas med SwiftUI-inbyggt AsyncImage. AsyncImage
stöds i iOS 15.0+.