iOS

[AEM as a Cloud Service]{class="badge informative"}

Exempelprogram är ett bra sätt att utforska Adobe Experience Manager headless-funktioner (AEM). I det här iOS-programmet visas hur du använder AEM GraphQL API:er med beständiga frågor.

iOS SwiftUI-app med AEM Headless

Visa källkoden på GitHub

Förutsättningar prerequisites

Följande verktyg bör installeras lokalt:

AEM

IOS fungerar med följande AEM driftsättningsalternativ. Alla distributioner kräver att WKND-platsen v3.0.0+ är installerad.

IOS-programmet är utformat för att ansluta till en AEM Publish -miljö, men det kan hämta innehåll från AEM författare om autentisering anges i iOS-programmets konfiguration.

Så här använder du

  1. Klona adobe/aem-guides-wknd-graphql-databasen:

    code language-shell
    $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
    
  2. Öppna Xcode och öppna mappen ios-app

  3. Ändra filen Config.xcconfig och uppdatera AEM_SCHEME och AEM_HOST så att de matchar AEM Publish-tjänst.

    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 författare lägger du till autentiseringsegenskaperna AEM_AUTH_TYPE och tillhörande autentiseringsegenskaper i Config.xcconfig.

    Grundläggande autentisering

    AEM_USERNAME och AEM_PASSWORD autentiserar en lokal AEM 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
    
  4. Bygg applikationen med Xcode och distribuera den till iOS-simulatorn

  5. 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

Efter AEM Headless-metodtips 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ån slug (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 via HTTP-GET och därför kan vanliga GraphQL-bibliotek som använder HTTP-POST som 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:

  1. Varje beständig fråga har en motsvarande offentlig funktion (t.ex. getAdventures(..) eller getAdventureBySlug(..)) iOS-programmets vyer anropas för att hämta äventyrsdata.

  2. Funktionen public anropar en privat funktion makeRequest(..) som anropar en asynkron HTTP GET-begäran för AEM Headless och returnerar JSON-data.

  3. 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 mappas till JSON-objekten som returnerade min AEM Headless.
    /// # 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 mappas till de AEM JSON-svar som returneras genom 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 via aem.getAdventures(). Det delade aem-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 av AdventureListItemView.

  • 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 AEM om du vill ha fullständig äventyrsinformation med hjälp av aem.getAdventureBySlug(slug: slug), där parametern slug skickas baserat på urvalslisteraden.

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:

  1. aem.imageUrl(path: String) används i vyer för att lägga till prepend-schemat för AEM 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
    
  2. convenience init(..) i Aem 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+.

Ytterligare resurser

recommendation-more-help
e25b6834-e87f-4ff3-ba56-4cd16cdfdec4