Android App
[AEM Headless as a Cloud Service]{class="badge informative"}
Example applications are a great way to explore the headless capabilities of 51黑料不打烊 Experience Manager (AEM). This Android application demonstrates how to query content using the GraphQL APIs of AEM. The is used to execute the GraphQL queries and map data to Java objects to power the app.
View the
Prerequisites prerequisites
The following tools should be installed locally:
AEM requirements
The Android application works with the following AEM deployment options. All deployments requires the to be installed.
The Android application is designed to connect to an AEM Publish environment, however it can source content from AEM Author if authentication is provided in the Android application鈥檚 configuration.
How to use
-
Clone the
adobe/aem-guides-wknd-graphqlrepository:code language-shell $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git -
Open and open the folder
android-app -
Modify the file
config.propertiesatapp/src/main/assets/config.propertiesand updatecontentApi.endpointto match your target AEM environment:code language-plain contentApi.endpoint=https://publish-p123-e456.adobeaemcloud.comBasic authentication
The
contentApi.userandcontentApi.passwordauthenticate a local AEM user with access to WKND GraphQL content.code language-plain contentApi.endpoint=https://author-p123-e456.adobeaemcloud.com contentApi.user=my-special-android-app-user contentApi.password=password123 -
Download an (minimum API 28).
-
Build and deploy the app using the Android emulator.
Connecting to AEM environments
If connecting to an AEM author environment is required. The provides the ability to use token-based authentication. To use token-based authentication update client builder in AdventureLoader.java and AdventuresLoader.java:
/* Comment out basicAuth
if (user != null && password != null) {
builder.basicAuth(user, password);
}
*/
// use token-authentication where `token` is a String representing the token
builder.tokenAuth(token)
The code
Below is a brief summary of the important files and code used to power the application. The full code can be found on .
Persisted queries
Following AEM Headless best practices, the iOS application uses AEM GraphQL persisted queries to query adventure data. The application uses two persisted queries:
wknd/adventures-allpersisted query, which returns all adventures in AEM with an abridged set of properties. This persisted query drives the initial view鈥檚 adventure list.
# Retrieves a list of all adventures
{
adventureList {
items {
_path
slug
title
price
tripLength
primaryImage {
... on ImageRef {
_dynamicUrl
_path
}
}
}
}
}
wknd/adventure-by-slugpersisted query, which returns a single adventure byslug(a custom property that uniquely identifies an adventure) with a complete set of properties. This persisted query powers the adventure detail views.
# 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 {
_dynamicUrl
_path
}
}
description {
json
plaintext
}
itinerary {
json
plaintext
}
}
_references {
...on AdventureModel {
_path
slug
title
price
__typename
}
}
}
}
Execute GraphQL persisted query
AEM鈥檚 persisted queries are executed over HTTP GET and thus, the is used to execute the persisted GraphQL queries against AEM and load the adventure content into the app.
Each persisted query has a corresponding 鈥渓oader鈥 class, that asynchronously calls the AEM HTTP GET end point, and returns the adventure data using the custom defined data model.
-
loader/AdventuresLoader.javaFetches the list of Adventures on the home screen of the application using the
wknd-shared/adventures-allpersisted query. -
loader/AdventureLoader.javaFetches a single adventure selecting it via the
slugparameter, using thewknd-shared/adventure-by-slugpersisted query.
//AdventuresLoader.java
public static final String PERSISTED_QUERY_NAME = "/wknd-shared/adventures-all";
...
AEMHeadlessClientBuilder builder = AEMHeadlessClient.builder().endpoint(config.getContentApiEndpoint());
// Optional authentication for basic auth
String user = config.getContentApiUser();
String password = config.getContentApiPassword();
if (user != null && password != null) {
builder.basicAuth(user, password);
}
AEMHeadlessClient client = builder.build();
// run a persistent query and get a response
GraphQlResponse response = client.runPersistedQuery(PERSISTED_QUERY_NAME);
GraphQL response data models data-models
Adventure.java is a Java POJO that is initialized with the JSON data from the GraphQL request, and models an adventure for use in the Android application鈥檚 views.
Views
The Android application uses two views to present the adventure data in the mobile experience.
-
AdventureListFragment.javaInvokes the
AdventuresLoaderand displays the returned adventures in a list. -
AdventureDetailFragment.javaInvokes the
AdventureLoaderusing theslugparam passed in via the adventure selection on theAdventureListFragmentview, and displays the details of a single adventure.
Remote images
loader/RemoteImagesCache.java is a utility class that helps prepare remote images in a cache so that they can be used with Android UI elements. The adventure content references images in AEM Assets via a URL and this class is used to display that content.