Las aplicaciones de ejemplo son una buena manera de explorar las capacidades sin objetivos de Adobe Experience Manager (AEM). Esta aplicación de iOS muestra cómo consultar contenido mediante las API de GraphQL AEM mediante consultas persistentes.
Consulte la código fuente en GitHub
Las siguientes herramientas deben instalarse localmente:
La aplicación iOS funciona con las siguientes opciones de implementación de AEM. Todas las implementaciones requieren la variable Sitio WKND v2.0.0+ para instalar.
La aplicación iOS está diseñada para conectarse a un AEM Publish , sin embargo, puede obtener contenido de AEM Author si la autenticación se proporciona en la configuración de la aplicación de iOS.
Clonar el adobe/aem-guides-wknd-graphql
repositorio:
$ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
Launch Xcode y abra la carpeta ios-app
Modificación del archivo Config.xcconfig
archivo y actualizar AEM_SCHEME
y AEM_HOST
para que coincida con el servicio de publicación de AEM de Target.
// The http/https protocol scheme used to access the AEM_HOST
AEM_SCHEME = http
// Target hostname for AEM environment, do not include http:// or https://
AEM_HOST = localhost:4503
Si se conecta a AEM Author, agregue la variable AEM_AUTH_TYPE
y las propiedades de autenticación compatibles con Config.xcconfig
.
Autenticación básica
La variable AEM_USERNAME
y AEM_PASSWORD
autentique a un usuario AEM local con acceso al contenido de WKND GraphQL.
AEM_AUTH_TYPE = basic
AEM_USERNAME = admin
AEM_PASSWORD = admin
Autenticación de tokens
La variable AEM_TOKEN
es un token de acceso que se autentica a un usuario AEM con acceso al contenido de WKND GraphQL.
AEM_AUTH_TYPE = token
AEM_TOKEN = abcd...0123
Cree la aplicación utilizando Xcode e implemente la aplicación en el simulador de iOS.
Se debe mostrar una lista de las aventuras del sitio WKND en la aplicación. Al seleccionar una aventura, se abren los detalles de la aventura. En la vista de lista de aventuras, presione para actualizar los datos de AEM.
A continuación se muestra un resumen de cómo se crea la aplicación de iOS, cómo se conecta a AEM sin encabezado para recuperar contenido mediante consultas persistentes de GraphQL y cómo se presentan esos datos. El código completo se puede encontrar en GitHub.
Siguiendo AEM prácticas recomendadas sin encabezado, la aplicación de iOS utiliza consultas persistentes AEM GraphQL para consultar datos de aventura. La aplicación utiliza dos consultas persistentes:
wknd/adventures-all
consulta persistente, que devuelve todas las aventuras en AEM con un conjunto abreviado de propiedades. Esta consulta persistente impulsa la lista de aventuras de la vista inicial.# Retrieves a list of all adventures
{
adventureList {
items {
_path
slug
title
price
tripLength
primaryImage {
... on ImageRef {
_path
mimeType
width
height
}
}
}
}
}
wknd/adventure-by-slug
consulta persistente, que devuelve una sola aventura de slug
(una propiedad personalizada que identifica de forma exclusiva una aventura) con un conjunto completo de propiedades. Esta consulta persistente potencia las vistas de detalles de aventura.# Retrieves an adventure Content Fragment based on it's slug
# Example query variables:
# {"slug": "bali-surf-camp"}
# Technically returns an adventure list but since the the slug
# property is set to be unique in the CF Model, only a single CF is expected
query($slug: String!) {
adventureList(filter: {
slug: {
_expressions: [ { value: $slug } ]
}
}) {
items {
_path
title
slug
activity
adventureType
price
tripLength
groupSize
difficulty
price
primaryImage {
... on ImageRef {
_path
mimeType
width
height
}
}
description {
json
plaintext
}
itinerary {
json
plaintext
}
}
_references {
...on AdventureModel {
_path
slug
title
price
__typename
}
}
}
}
AEM las consultas persistentes se ejecutan a través de GET HTTP y, por lo tanto, no se pueden utilizar las bibliotecas comunes de GraphQL que utilizan POST HTTP como Apollo. En su lugar, cree una clase personalizada que ejecute las solicitudes de GET HTTP de consulta persistentes a AEM.
AEM/Aem.swift
crea una instancia de Aem
clase utilizada para todas las interacciones con AEM sin encabezado. El patrón es:
Cada consulta persistente tiene una función pública correspondiente (por ejemplo, getAdventures(..)
o getAdventureBySlug(..)
) las vistas de la aplicación de iOS se invocan para obtener datos de aventura.
El func público llama a un func privado makeRequest(..)
que invoca una solicitud de GET HTTP asincrónica para AEM sin encabezado y devuelve los datos JSON.
A continuación, cada func pública descodifica los datos JSON y realiza las comprobaciones o transformaciones necesarias antes de devolver los datos de Aventura a la vista.
AEM/Models.swift
, que se asignaban a los objetos JSON devolvía mi AEM sin encabezado. /// # 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(completion: @escaping ([Adventure]) -> ()) {
// Create the HTTP request object representing the persisted query to get all adventures
let request = makeRequest(persistedQueryName: "wknd-shared/adventures-all")
// Wait fo the HTTP request to return
URLSession.shared.dataTask(with: request) { (data, response, error) in
// Error check as needed
if ((error) != nil) {
print("Unable to connect to AEM GraphQL endpoint")
completion([])
}
if (!data!.isEmpty) {
// Decode the JSON data into Swift objects
let adventures = try! JSONDecoder().decode(Adventures.self, from: data!)
DispatchQueue.main.async {
// Return the array of Adventure objects
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
}
...
iOS prefiere asignar objetos JSON a modelos de datos con tipo.
La variable src/AEM/Models.swift
define el descodificable Estructuras y clases de Swift que se asignan a las AEM respuestas JSON devueltas por AEM respuestas JSON.
SwiftUI se utiliza para las distintas vistas de la aplicación. Apple proporciona un tutorial de introducción para creación de listas y navegación con SwiftUI.
WKNDAdventuresApp.swift
La entrada de la aplicación e incluye AdventureListView
whose .onAppear
el controlador de eventos se utiliza para recuperar todos los datos de aventuras mediante aem.getAdventures()
. El aem
se inicializa aquí y se expone a otras vistas como un EnvironmentObject.
Views/AdventureListView.swift
Muestra una lista de aventuras (según los datos de aem.getAdventures()
) y muestra un elemento de lista para cada aventura utilizando la variable AdventureListItemView
.
Views/AdventureListItemView.swift
Muestra cada elemento de la lista de aventuras (Views/AdventureListView.swift
).
Views/AdventureDetailView.swift
Muestra los detalles de una aventura, incluidos el título, la descripción, el precio, el tipo de actividad y la imagen principal. Esta vista consulta AEM para obtener detalles de aventura completos mediante aem.getAdventureBySlug(slug: slug)
, donde la variable slug
se transfiere en función de la fila de lista de selección.
Las imágenes a las que se hace referencia en los fragmentos de contenido de aventura son proporcionadas por AEM. Esta aplicación de iOS utiliza la ruta _path
en la respuesta de GraphQL y añade los prefijos a la variable AEM_SCHEME
y AEM_HOST
para crear una URL completa.
Si la conexión a recursos protegidos en AEM que requiere autorización, también se deben agregar credenciales a solicitudes de imagen.
SDWebImageSwiftUI y SDWebImage se utilizan para cargar las imágenes remotas de AEM que rellenan la imagen de aventura en la variable AdventureListItemView
y AdventureDetailView
vistas.
La variable aem
clase (en AEM/Aem.swift
) facilita el uso de imágenes AEM de dos maneras:
aem.imageUrl(path: String)
se utiliza en las vistas para anteponer el esquema de AEM y alojar la ruta de la imagen, creando una URL completa.
// adventure.image() => /content/dam/path/to/an/image.png
let imageUrl = aem.imageUrl(path: adventure.image())
// imageUrl => http://localhost:4503/content/dam/path/to/an/image.png
La variable convenience init(..)
en Aem
establezca encabezados de autorización HTTP en la solicitud HTTP de imagen, según la configuración de las aplicaciones iOS.
/// 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")
}
/// 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")
}
Se puede usar un enfoque similar con el nativo de la interfaz de usuario de Swift AsyncImage. AsyncImage
es compatible con iOS 15.0+.