Cree un blog en Swift con Oracle Content Management sin supervisión

Introducción

Un entorno de desarrollo iOS que utiliza Swift y SwiftUI puede ser una potente herramienta para crear aplicaciones que consumen contenido de Oracle Content Management. Armado con el modelo de contenido adecuado, puede crear rápidamente la interfaz de usuario que compone una aplicación de blog típica.

En este tutorial, crearemos una sencilla aplicación de blog para iOS en Swift aprovechando Oracle Content Management como CMS horizontal y su kit de desarrollo de software (SDK) para la entrega de contenido. Este ejemplo de iOS está disponible en GitHub.

El tutorial incluye tres pasos:

  1. Preparación de Oracle Content Management
  2. Crear la aplicación de blog en Xcode
  3. Ejecute la aplicación

Requisitos

Antes de continuar con este tutorial, le recomendamos que lea primero la siguiente información:

Para seguir este tutorial, necesitará:

Lo que estamos construyendo

Nuestra aplicación de blog consta de tres páginas separadas que permiten a los visitantes explorar artículos de blog organizados en temas.

Esta imagen animada muestra la navegación a través de una aplicación de ejemplo de blog, comenzando con temas, navegando a una lista de artículos y finalmente viendo un artículo de blog en detalle.

La primera página, la página inicial, consta de marca (nombre y logotipo de la compañía), algunos enlaces y una lista de temas del blog.

La segunda página, la página de lista de artículos, muestra las vistas previas de cada artículo de blog que pertenece al tema.

Por último, la página de artículo presenta el artículo final del blog, incluida la información sobre el autor del blog.

Para continuar, deberá tener una suscripción activa a Oracle Content Management y conectarse con el rol de administrador de contenido.

Paso 1: Preparación de Oracle Content Management

Si aún no tiene una instancia de Oracle Content Management, consulte el inicio rápido para obtener información sobre cómo registrarse en Oracle Cloud, aprovisionar una instancia de Oracle Content Management y configurar Oracle Content Management como CMS sin cabecera.

Para este tutorial, tendrá que crear un modelo de contenido de dos formas. Hay un paquete de activos descargable disponible que rellenará su repositorio vacío con tipos de contenido y contenido asociado, o bien puede crear su propio modelo de contenido y contenido.

Para preparar Oracle Content Management:

  1. Cree un canal y un repositorio de activos.
  2. Cree un modelo de contenido mediante uno de estos dos métodos:

Creación de un canal y un repositorio de activos

Primero debe crear un canal y un repositorio de activos en Oracle Content Management para poder publicar contenido.

Para crear un canal y un repositorio de activos en Oracle Content Management:

  1. Conéctese a la interfaz web de Oracle Content Management como administrador.

  2. Seleccione Contenido en el menú de navegación izquierdo y, a continuación, seleccione Canales de publicación en la lista de selección de la cabecera de página.

    En esta imagen se muestra la opción Canales de publicación seleccionada en el menú desplegable de la cabecera de la página Contenido.

  3. En la esquina superior derecha, haga clic en Crear para crear un nuevo canal. Asigne el nombre 'OCEGettingStartedChannel' al canal para este tutorial y mantenga el acceso público. Haga clic en Guardar para crear el canal.

    En esta imagen se muestra el panel de definición de canal de publicación, con 'OCEGettingStartedChannel' en el campo de nombre de canal.

  4. Seleccione Contenido en el menú de navegación izquierdo y, a continuación, seleccione Repositorios en la lista de selección de la cabecera de página.

    En esta imagen se muestra la opción Repositories seleccionada en el menú desplegable de la cabecera Content page.

  5. En la esquina superior derecha, haga clic en Crear para crear un nuevo repositorio de activos. Asigne el nombre 'OCEGettingStartedRepository' al repositorio de activos para este tutorial.

    En esta imagen se muestra el panel de definición del repositorio, con 'OCEGettingStartedRepository' en el campo de nombre del repositorio.

  6. En el campo Canales de publicación, seleccione el canal OCEGettingStartedChannel para indicar a Oracle Content Management que el contenido del repositorio OCEGettingStartedRepository se puede publicar en el canal OCEGettingStartedChannel. Haga clic en Guardar cuando termine.

    En esta imagen se muestra el panel de definición de repositorio, con 'OCEGettingStartedChannel' en el campo Canales de publicación.

Creación de un modelo de contenido

El siguiente paso es crear un modelo de contenido. Puede utilizar uno de estos métodos:

Importar el paquete de activos de muestras de Oracle Content Management

Puede descargar un paquete de activos de ejemplo de Oracle Content Management preconfigurado que contiene todos los tipos de contenido y activos necesarios para este tutorial. Si lo prefiere, también puede crear su propio modelo de contenido en lugar de descargar el paquete de activos de ejemplo.

Puede cargar una copia del contenido que estamos utilizando en este tutorial desde el paquete de activos de muestras de Oracle Content Management. Esto le permitirá experimentar con los tipos de contenido y modificar el contenido. Si desea importar el paquete de activos de muestras de Oracle Content Management, descargue el archivo del paquete de activos OCESamplesAssetPack.zip y extráigalo en el directorio que desee:

  1. Descargue el paquete de activos de muestras de Oracle Content Management (OCESamplesAssetPack.zip) desde la página descargas de Oracle Content Management. Extraiga el archivo zip descargado en una ubicación de la computadora. Después de la extracción, esta ubicación incluirá un archivo denominado OCEGettingStarted_data.zip.

  2. Conéctese a la interfaz web de Oracle Content Management como administrador.

  3. Seleccione Contenido en el menú de navegación izquierdo y, a continuación, seleccione Repositorios en la lista de selección de la cabecera de página. A continuación, seleccione OCEGettingStartedRepository y haga clic en el botón Importar contenido de la barra de acción superior.

    En esta imagen se muestra la página Repositorios, con el elemento OCEGettingStartedRepository seleccionado.

  4. Cargue OCEGettingStarted_data.zip desde la computadora local en la carpeta Documentos.

    En esta imagen se muestra la pantalla de confirmación de carga del archivo OCEGettingStarted_data.zip.

  5. Una vez cargado, seleccione OCEGettingStarted_data.zip y haga clic en Aceptar para importar el contenido en el repositorio de activos.

    En esta imagen se muestra el archivo OCEGettingStarted_data.zip seleccionado con el botón Aceptar activado.

  6. Una vez que el contenido se haya importado correctamente, navegue a la página Activos y abra el repositorio OCEGettingStartedRepository. Verá que todas las imágenes y elementos de contenido relacionados se han agregado al repositorio de activos.

    En esta imagen se muestra el repositorio OCEGettingStartedRepository, con todos los activos que se acaban de importar.

  7. Haga clic en Seleccionar todo en la parte superior izquierda y, a continuación, en Publicar para agregar todos los activos importados al canal de publicación que ha creado anteriormente, OCEGettingStartedChannel.

    En esta imagen se muestra el repositorio OCEGettingStartedRepository, con todos los activos seleccionados y la opción Publish en la barra de acción visible.

  8. Antes de publicar, debe validar todos los activos. En primer lugar, agregue OCEGettingStartedChannel como canal seleccionado y, a continuación, haga clic en el botón Validar.

    En esta imagen se muestra la página Resultados de validación, con el canal OCEGettingStartedChannel agregado en el campo Canales, todos los activos que se van a validar y el botón Validar activado.

  9. Después de validar los activos, puede publicar todos los activos en el canal seleccionado haciendo clic en el botón Publicar en la esquina superior derecha.

    En esta imagen se muestra la página Resultados de validación, con el canal OCEGettingStartedChannel agregado en el campo Canales, todos los activos validados y el botón Publicar activado.

Una vez hecho esto, puede ver en la página Activos que todos los activos se han publicado. (Puede hacerlo mediante el icono situado encima del nombre del activo).

En esta imagen se muestra la página Activos, con todos los activos almacenados.

Después de importar el paquete de activos de muestras de Oracle Content Management, puede empezar a crear el blog en Xcode.

Crear su propio modelo de contenido

En lugar de importar el paquete de activos de muestras de Oracle Content Management, también puede crear su propio modelo de contenido.

Para este tutorial, estamos utilizando un tipo de contenido llamado 'OCEGettingStartedHomePage' para crear la página de inicio de nuestro blog. Esta página de inicio consta de marca (nombre y logotipo de la compañía), algunas URL para enlaces y una lista de temas de blog que se deben incluir en la página.

En esta imagen se muestra la página inicial del sitio de demostración de Cafe Supremo.

Para crear tipos de contenido para el modelo de contenido:

  1. Conéctese a la interfaz web de Oracle Content Management como administrador.
  2. Seleccione Contenido en el menú de navegación izquierdo y, a continuación, seleccione Tipos de activos en la lista de selección de la cabecera de página.
  3. Haga clic en Crear en la esquina superior derecha.
  4. Seleccione crear un tipo de contenido (no un tipo de activo digital). Repita esta acción para todos los tipos de contenido necesarios.

En esta imagen se muestra el cuadro de diálogo Crear tipo de activo en la interfaz web de Oracle Content Management.

Crearemos cuatro tipos de contenido, cada uno con su propio conjunto de campos:

El primer tipo de contenido, OCEGettingStartedHomePage, debe tener los siguientes campos:

Nombre mostrado Tipo de campo necesario Nombre de la Máquina
Nombre de la Compañía Campo de texto de un solo valor X company_name
Logotipo de compañía Campo de texto de un solo valor X company_logo
Temas Campo de referencia de varios valores X temas
URL de Contacto Campo de texto de un solo valor X contact_url
Acerca de URL Campo de texto de un solo valor X about_url

Este es el aspecto de la definición de tipo de contenido OCEGettingStartedHomePage:

En esta imagen se muestra la definición del tipo de contenido 'OCEGettingStartedHomePage'. Incluye estos campos de datos: Nombre de la compañía, Logotipo de la compañía, Temas, URL de contacto y URL de Acerca de.

El segundo tipo de contenido, OCEGettingStartedTopic, debe tener el siguiente campo:

Nombre mostrado Tipo de campo necesario Nombre de la Máquina
Vista en miniatura Campo de imagen de valor único X vista en miniatura

Este es el aspecto del tipo de contenido OCEGettingStartedTopic:

En esta imagen se muestra la definición del tipo de contenido 'OCEGettingStartedTopic'. Incluye este campo de datos: Vista en miniatura.

El tercer tipo de contenido, OCEGettingStartedAuthor, debe tener los siguientes campos:

Nombre mostrado Tipo de campo necesario Nombre de la Máquina
Avatar Campo de imagen de valor único X avatar

Este es el aspecto del tipo de contenido OCEGettingStartedAuthor:

En esta imagen se muestra la definición del tipo de contenido 'OCEGettingStartedAuthor'. Incluye este campo de datos: Avatar.

El tipo de contenido cuarto y final, OCEGettingStartedArticle, debe tener los siguientes campos:

Nombre mostrado Tipo de campo necesario Nombre de la Máquina
Fecha de publicación Campo de fecha de valor único X published_name
Autor Campo de referencia de valor único X autor
Imagen Campo de imagen de valor único X imagen
Leyenda de Imagen Campo de texto de un solo valor X image_caption
Contenido del artículo Campo de texto grande de valor único X article_content
Tema Campo de referencia de valor único X Tema

Este es el aspecto del tipo de contenido OCEGettingStartedArticle:

En esta imagen se muestra la definición del tipo de contenido 'OCEGettingStartedArticlePage'. Incluye estos campos de datos: Fecha de publicación, Autor, Imagen, Título de imagen, Contenido de artículo y Tema.

Una vez que haya creado los tipos de contenido, puede agregar estos tipos de contenido al repositorio que ha creado anteriormente, OCEGettingStartedRepository:

  1. Conéctese a la interfaz web de Oracle Content Management como administrador.
  2. Navegue hasta OCEGettingStartedRepository.
  3. Edite el repositorio y, en Tipos de activos, especifique los cuatro tipos de contenido recién creados. Haga clic en el botón Save (Guardar) para guardar los cambios.

En esta imagen se muestra la página Editar repositorio en Oracle Content Management, con los cuatro tipos de contenido recién creados asociados al repositorio OCEGettingStartedRepository.

Después de agregar los tipos de contenido al repositorio, puede abrir el repositorio OCEGettingStartedRepository en la página Activos y empezar a crear los elementos de contenido para todos los tipos de contenido.

En esta imagen se muestran los elementos de contenido de la página Activos de la interfaz web de Oracle Content Management, con opciones a la izquierda para recopilaciones, canales, idiomas, tipos, selección de elementos de contenido y estado.

Paso 2: Crear la aplicación de blog en Xcode

Para consumir nuestro contenido de Oracle Content Management en una aplicación iOS, podemos utilizar el ejemplo de blog de iOS, que está disponible como repositorio de código abierto en GitHub.

Nota: Recuerde que el uso del ejemplo de iOS es opcional y lo usamos en este tutorial para comenzar rápidamente. También puede crear su propia aplicación iOS.

Para construir el blog en Swift:

  1. Clonar el repositorio de ejemplo
  2. Configurar la aplicación iOS
  3. Uso del SDK de contenido para recuperar contenido

Clonar el repositorio de ejemplo

El ejemplo de blog de iOS está disponible como repositorio de código abierto en GitHub.

Primero deberá clonar el ejemplo de GitHub en el equipo local:

git clone https://github.com/oracle-samples/oce-ios-blog-sample.git

Una vez que haya clonado el ejemplo, abra el archivo de proyecto Xcode, BlogDemo.xcodeproj.

Al abrir el proyecto de ejemplo en Xcode, se extraerá automáticamente de la dependencia de content-management-swift, el paquete Swift que implanta el SDK de entrega de contenido de Oracle.

No hay otras dependencias de terceros para esta aplicación, por lo que no se requieren otras instalaciones manuales. Sin embargo, antes de ejecutar la aplicación, es necesaria una configuración adicional.

Configurar la aplicación iOS

En este ejemplo de blog de iOS, debe configurar algunas partes de la información para que el SDK de Oracle Content Management Content pueda dirigir la URL de instancia correcta con el token de canal correcto. Estos valores se utilizan cada vez que la aplicación solicita datos de la instancia de Oracle Content Management.

Abra el archivo credentials.json y cambie ambos pares clave-valor para reflejar la URL de instancia y el token de canal asociado al canal de publicación. El canal de este tutorial es OCEGettingStartedChannel.

{
    "url": "https://samples.mycontentdemo.com",
    "channelToken": "47c9fb78774d4485bc7090bf7b955632"
}

Uso del SDK de contenido para recuperar contenido

Oracle Content Management ofrece un paquete Swift (content-management-swift) que consta de las bibliotecas OracleContentCore y OracleContentDelivery para ayudar a detectar y utilizar contenido en sus aplicaciones. El paquete se aloja en GitHub.

Obtenga más información sobre el SDK de contenido para Swift en la biblioteca de documentación de Oracle Content Management:

Puede aprovechar estas bibliotecas de Content SDK para recuperar contenido para que podamos presentarlo en nuestra aplicación iOS.

Vinculación de la aplicación

Para solicitar datos, debe proporcionar la información necesaria a su biblioteca, que se conoce como vinculación de la aplicación. Puede asignar determinados elementos de información para que las solicitudes tengan el formato correcto y apunten a la URL de instancia correcta.

En esta demostración, cuando se inicia por primera vez la aplicación, se asigna Onboarding.urlProvider como instancia de su propia clase, MyURLProvider. Esto establece la URL de instancia y el token de canal que utiliza la biblioteca de contenido para cada solicitud realizada.

Si bien la especificación de un proveedor de URL no es estrictamente necesaria (ya que la URL y la información de token se pueden especificar por solicitud), su asignación reduce la cantidad de código necesario para cada sitio de llamada.

@main
struct BlogDemo: App {
    init() {
        // ... 

        // The sample code expects the URL and channel token to be provided by ``OracleContentCore.Onboarding``
        // Assign your ``OracleContentCore.URLProvider`` implementation to the ``OracleContentCore.Onboarding.urlProvider`` property
        Onboarding.urlProvider = MyURLProvider()
        
        // ...
        
    }
}

La implementación MyURLProvider lee datos de credentials.json para obtener la URL y el token de canal.

{
    "url": "https://samples.mycontentdemo.com",
    "channelToken": "47c9fb78774d4485bc7090bf7b955632"
}

Cada vez que la biblioteca de contenido de Oracle necesita crear una solicitud, recupera la siguiente propiedad:

/// This function provides the URL to be used for each OracleContentCore request
///
/// Services which implement ``OracleContentCore.ImplementsOverrides`` may provide a different URL and
/// authorization headers (if required) on a call-by-call basis
public var url: () -> URL? = {
  return URL(string: MyURLProvider.credentials.url)
}

Cada vez que la biblioteca necesita crear una solicitud, también recuperará el token de entrega:

/// This function provides the delivery channel token to be used for each OracleContentCore request
///
/// Services which implement ``OracleContentCore.ImplementsChannelToken`` may override this value
/// on a call-by-call basis
public var deliveryChannelToken: () -> String? = {
  
  return MyURLProvider.credentials.channelToken
}

Además, la asignación a Onboarding.logger proporciona la oportunidad de definir su propia implantación de registro. Para esta demostración, la implantación de MyLogger consiste en simplemente "imprimir" en la consola. En entornos de producción, el registrador puede utilizar el registro universal, los datos principales o cualquier tecnología que elija.

@main
struct BlogDemo: App {
    init() {
        // ... 

         Onboarding.logger = MyLogger()
        
        // ...
        
    }
}

Solicitud de datos mediante la biblioteca de contenido de Oracle

Nota: Todos los códigos de solicitud de red para esta demostración se pueden encontrar en BlogNetworking.swift.

Ahora podemos aprovechar el SDK de contenido para recuperar contenido para que podamos presentarlo en la aplicación iOS.

El archivo BlogNetworking.swift contiene todo el código para obtener datos para la aplicación. El objeto de modelo asociado a cada página llamará a varios métodos para recuperar los datos de Oracle Content Management.

Datos de la página de inicio

La página inicial de nuestra aplicación es BlogDemoMain.swift, un archivo SwiftUI con un objeto de modelo asociado. El objeto modelo es responsable de mantener el estado de la página y emitir las llamadas de función necesarias para iniciar el proceso de recuperación de datos. A medida que se reciben los datos, el estado de la página cambia y SwiftUI refrescará la interfaz de usuario según corresponda.

Inicialmente, la página principal solicita dos partes de datos diferentes:

  1. En primer lugar, se consulta el elemento de contenido que representa la página inicial del blog.
  2. A continuación, descargamos el logotipo al que hace referencia el elemento de contenido.

Abra BlogNetworking.swift y busque la función fetchHomePage(), que realiza la solicitud inicial.

/// Retrieve the content item which represents the home page of the blog
/// - returns: Asset
public func fetchHomePage() async throws -> Asset {
    let typeNode = QueryNode.equal(field: "type", value: "OCEGettingStartedHomePage")
    let nameNode = QueryNode.equal(field: "name", value: "HomePage")
    let q = QueryBuilder(node: typeNode).and(nameNode)
    
    let result = try await DeliveryAPI
        .listAssets()
        .query(q)
        .fields(.all)
        .limit(1)
        .fetchNextAsync()
        .items
        .first
       
    guard let foundResult = result else {
        throw BlogNetworkingError.homePageNotFound
    }
    
    return foundResult
}

Esta función utiliza la simultaneidad de Swift para solicitar datos. Tenga en cuenta que todos los objetos de solicitud (o servicios) se asignan a DeliveryAPI. En este ejemplo, nuestro objeto de solicitud es listAssets().

A continuación del objeto request se encuentran una serie de componentes del creador que nos permiten ajustar la solicitud. Aquí hemos especificado algunos detalles de la consulta, se nos ha pedido que recuperen todos los campos y hemos limitado nuestros datos de respuesta a un solo objeto.

Nuestra solicitud a Oracle Content Management se envía mediante el verbo de invocación fetchNextAsync().

Nota: Como nuestro objeto de solicitud empieza por "list", el verbo de llamada empieza por "fetchNext".

Las solicitudes "List" devolverán datos que indican cuántos registros se han devuelto, si hay más datos y una recopilación de resultados (en la propiedad "items").

Nuestra función obtiene el primer valor de la propiedad "items" y lo devuelve. Este es el activo que representa nuestro blog y contiene el ID del logotipo, el nombre de la compañía, las URL de about y contact, y una lista de temas.

Con el ID de logotipo disponible, podemos emitir nuestra segunda solicitud para descargar el logotipo:

/// Download the logo for display on the home page
/// - parameter logoId: The identifier of the logo to download
/// - returns: BlogImageState 
public func fetchLogo(logoId: String?) async throws -> BlogImageState {
    
    do {
        guard let logoID = logoId else { 
          throw BlogNetworkingError.missingLogoId 
        }
        
        let result = try await DeliveryAPI
            .downloadNative(identifier: logoID)
            .downloadAsync(progress: nil)
        
        guard let image = UIImage(contentsOfFile: result.result.path) else {
            throw OracleContentError.couldNotCreateImageFromURL(URL(string: result.result.path))
        }
        
        return .image(image)
        
    } catch {
        return .error(error)
    }

}

Nuestra solicitud y llamada son mucho más simples en esta función. Creamos el objeto de solicitud mediante downloadNative(identifier: logoID) y lo enviamos mediante el verbo de llamada downloadAsync.

Cuando se descarga el objeto, se convierten los datos en UIImage y se devuelve como una enumeración BlogImageState con la propia imagen como valor asociado.

Nota: Este ejemplo utiliza la enumeración BlogImageState porque nos permite representar los distintos estados de imagen sin tener que utilizar valores opcionales. Esto hace que la captación en SwiftUI sea muy fácil.

Datos de temas

Cuando nuestro modelo solicitó los datos de la página inicial, ejecutó una llamada similar a esta:

self.home = try await self.networking.fetchHomePage()   

Con la página inicial recuperada correctamente, necesitamos encontrar la recopilación de valores de activos que representan los temas de nuestro blog. Para ello, pedimos el campo denominado "temas" cuyo tipo es una matriz de activos.

self.topics = try self.home.customField("topics") as [Asset]

BlogDemoMain.swift itera sobre esta recopilación de temas y representa cada uno como un elemento en una vista de cuadrícula. Esa representación de la interfaz de usuario se define en Topic.swift y su objeto de modelo asociado, TopicModel.swift.

Para mostrar información sobre un tema individual, debemos realizar dos tareas:

  1. Necesitamos recuperar la información detallada sobre cada tema.
  2. Debemos descargar la imagen a la que hace referencia cada tema.

En TopicModel.swift, llamamos al código de red para obtener el activo completo:

let fullAsset = try await self.networking.readAsset(assetId: self.topic.identifier)

Obtener información detallada sobre el tema es un proceso simple. Cree una solicitud de lectura con el identificador proporcionado y, a continuación, recupere los datos.

/// Obtain detailed information about an Asset
/// - parameter assetId: The identifier of the asset to read
/// - returns: Asset
public func readAsset(assetId: String) async throws -> Asset {
    let result = try await DeliveryAPI
        .readAsset(assetId: assetId)
        .fetchAsync()
    
    return result
}

Nota: Todas las solicitudes de lectura devuelven un único objeto y se envían mediante un verbo de llamada que empieza por "recuperar".

Una vez que hayamos recuperado la información detallada sobre nuestro tema, debemos extraer los datos que definen la vista en miniatura y, a continuación, descargarla.

En TopicModel.swift, obtenemos la información de la vista en miniatura solicitando el campo personalizado denominado "vista en miniatura". Puesto que los campos personalizados pueden ser uno de varios tipos diferentes, necesitamos especificar explícitamente que este campo es un tipo de activo. Una vez que hayamos encontrado correctamente el activo, podemos obtener su identificador.

imageIdentifier = (try fullAsset.customField("thumbnail") as Asset).identifier

Con el identificador disponible, TopicModel.swift ahora puede solicitar al código de red que recupere la representación media de la imagen en miniatura.

let imageState = await self.networking.downloadMediumRendition(identifier: imageIdentifier)
return imageState

El código de red para obtener la imagen crea un objeto de solicitud "downloadRendition" para recuperar una representación denominada "Medio" en formato jpg. El verbo de llamada utilizado para enviar la solicitud es "downloadAsync".

Cuando se descarga el objeto, se convierten los datos en UIImage y se devuelve como una enumeración BlogImageState con la propia imagen como valor asociado.

/// Downloads the "Medium" rendition of an asset and returns the value as a `BlogImageState`
/// Note that any error while downloading the image will result in a placeholder image
public func downloadMediumRendition(identifier: String) async -> BlogImageState {
    
    do {
        let result = try await DeliveryAPI
                                .downloadRendition(identifier: identifier,
                                                   renditionName: "Medium",
                                                   format: "jpg")
                                .downloadAsync(progress: nil)
        
        guard let uiImage = UIImage(contentsOfFile: result.result.path()) else {
            throw OracleContentError.couldNotCreateImageFromURL(result.result)
        }
        
        return .image(uiImage)
        
    } catch {
        return .image(UIImage(systemName: "questionmark.circle")!)
    }

}

Ahora que tenemos la información detallada del tema y la imagen en miniatura, SwiftUI puede construir la representación visual de un tema.

En esta imagen se muestra la interfaz de usuario que representa un tema. Contiene un título de 'How To', una imagen en miniatura de tazas de café con contacto latte y una descripción que define el tema como aprender a crear hermoso arte latte y verter solo la copa derecha.

Datos de lista de artículos

Al tocar un tema, el usuario accede a una nueva página que contiene una lista de artículos asignados al tema seleccionado.

La creación de las páginas de artículos es muy similar al proceso utilizado para crear la lista de temas. Teniendo en cuenta un identificador de tema, debemos:

  1. Recuperar la lista de artículos para ese tema y
  2. Para cada artículo, recupere la representación en miniatura del activo contenido en su campo "image".

Al recuperar la lista de activos, nuestro objeto de solicitud es .listAssets().

En ausencia de otros componentes del creador, se recuperarán todos los activos publicados del canal de publicación especificado en credentials.json. Sin embargo, lo que queremos es recuperar solo aquellos activos cuyo tipo sea OCEGettingStartedArticle y cuya propiedad de tema coincida con el identificador de tema transferido.

/// Obtain the collection of articles for a given topic. Limited to a maximum of 50 articles for demo purposes.
/// - parameter topic: Asset
/// - returns: [Asset] representing the articles for the specified topic
public func fetchArticles(for topic: Asset) async throws -> [Asset] {

    let typeNode = QueryNode.equal(field: "type", value: "OCEGettingStartedArticle")
    let fieldsTopicNode = QueryNode.equal(field: "fields.topic", value: topic.identifier)
    let fullQuery = QueryBuilder(node: typeNode).and(fieldsTopicNode)
    
    let result = try await DeliveryAPI
        .listAssets()
        .query(fullQuery)
        .order(.field("fields.published_date", .desc))
        .limit(50)
        .fetchNextAsync()
    
    return result.items
}

Para cada uno de los artículos recuperados, necesitamos determinar qué imagen descargar. Obtenemos el identificador del activo al que se hace referencia en el campo "image" y lo usamos para enviar una solicitud para descargar su vista en miniatura.

let identifier = (try article.customField("image") as Asset).identifier
let image = await self.networking.downloadThumbnail(identifier: identifier, fileGroup: article.fileGroup)

El código de red para solicitar la descarga tiene el siguiente aspecto:

/// Downloads the thumbnail rendition of an asset and returns the values as a ``BlogImageState``
/// Note that any error while downloading the image will result in a placeholder image
/// - parameter identifier: The identifier of the asset
/// - parameter fileGroup: The file group of the asset - used to differentiate thumbnails for digital assets, videos and "advanced videos"
public func downloadThumbnail(identifier: String, fileGroup: String) async -> BlogImageState {
    do {
        let result = try await DeliveryAPI
            .downloadThumbnail(identifier: identifier, fileGroup: fileGroup)
            .downloadAsync(progress: nil)
        
        guard let uiImage = UIImage(contentsOfFile: result.result.path()) else {
           throw OracleContentError.couldNotCreateImageFromURL(result.result)
        }
        
        return .image(uiImage)
    } catch {
        Onboarding.logError(error.localizedDescription)
        return .image(UIImage(systemName: "questionmark.circle")!)
    }
}

Ahora podemos mostrar una vista previa de cada artículo:

En esta imagen se muestra una vista previa de un artículo. Contiene un título de 'Create Beautiful Latte Art', una fecha formateada que indica cuándo se publicó el artículo, una imagen en miniatura de tazas de café con latte que contacta y un texto descriptivo sobre el artículo - que 'Con una pequeña práctica, puedes crear diseños con leche al vapor'.

Datos de artículo

Al tocar en la vista previa de un artículo, la página final de la aplicación de ejemplo se muestra, es decir, el propio artículo. Como antes, se deben realizar varias solicitudes de datos:

  1. Dado el identificador del artículo seleccionado, necesitamos recuperar su información detallada.
  2. Descargue el avatar del autor.
  3. Descargue la imagen del artículo para mostrar.
@MainActor
func fetchArticle() async throws {

    self.article = try await self.networking.readArticle(assetId: article.identifier)
    
    let author: Asset = try self.article.customField("author")
    let authorAvatar: Asset = try author.customField("avatar")

    Task {
        self.avatar = await self.networking.downloadNative(identifier: authorAvatar.identifier)
    }
    
    Task {
        let hero: Asset = try self.article.customField("image_16x9")
        self.heroImage = await self.networking.downloadNative(identifier: hero.identifier)
    }
}

La lectura de la información detallada de un activo es un proceso sencillo:

/// Obtain detailed information about an Asset
/// - parameter assetId: The identifier of the asset to read
/// - returns: Asset
public func readAsset(assetId: String) async throws -> Asset {
    let result = try await DeliveryAPI
        .readAsset(assetId: assetId)
        .fetchAsync()
    
    return result
}

Descargar las imágenes del avatar y del artículo siguen el mismo patrón general que se utilizó para obtener otras imágenes:

/// Downloads the native rendition of an asset and returns the values as a ``BlogImageState``
/// Note that any error while downloading the image will result in a placeholder image
public func downloadNative(identifier: String) async -> BlogImageState {
    do {
        let result = try await DeliveryAPI
            .downloadNative(identifier: identifier)
            .downloadAsync(progress: nil)
        
        guard let uiImage = UIImage(contentsOfFile: result.result.path()) else {
           throw OracleContentError.couldNotCreateImageFromURL(result.result)
        }
        
        return .image(uiImage)
    } catch {
        Onboarding.logError(error.localizedDescription)
        return .image(UIImage(systemName: "questionmark.circle")!)
    }
    
}

El resultado es un artículo de blog con formato completo:

Esta imagen muestra un artículo de blog completo. Contiene información sobre el autor (incluida una imagen de avatar), la imagen utilizada para representar el artículo y el texto con formato HTML del artículo.

Paso 3: Ejecución de la aplicación

Con la aplicación completa, puede ejecutarla en el simulador o desplegarla en cualquier iPhone o iPad que ejecute iOS o iPadOS 16.0 o superior.

Conclusión

En este tutorial, creamos un sitio de aplicación de blog para iOS, que se puede encontrar en GitHub. Esta aplicación utiliza Oracle Content Management como CMS sin cabecera. Después de configurar Oracle Content Management con un canal de contenido publicado para el tutorial del blog, hemos ejecutado la aplicación para recuperar el contenido necesario.

Para obtener más información sobre Swift, vaya al sitio web de Swift.

Obtenga información sobre los conceptos importantes de Oracle Content Management en la documentación.

Puede encontrar más ejemplos como este en la página Ejemplos de Oracle Content Management en Oracle Help Center.