A anatomia de um aplicativo

Última atualização em 2023-11-08
  • Tópicos
  • Mobile
    Exibir mais informações sobre este tópico
  • Criado para:
  • User
OBSERVAÇÃO

A Adobe recomenda o uso do Editor SPA para projetos que exigem renderização no lado do cliente baseada em estrutura de aplicativo de página única (por exemplo, React). Saiba mais.

Modelos de página para aplicativos móveis

Os componentes de página criados para seu aplicativo são baseados no componente /libs/mobileapps/components/angular/ng-page (abrir no CRXDE Lite em um servidor local). Este componente contém os seguintes scripts JSP que seu componente herda ou substitui:

  • ng-page.jsp
  • head.jsp
  • body.jsp
  • angular-app-module.js.jsp
  • angular-route-fragment.js.jsp
  • angular-app-controllers.js.jsp
  • controller.js.jsp
  • template.jsp
  • angular-module-list.js.jsp
  • header.jsp
  • footer.jsp
  • js_clientlibs.jsp
  • css_clientlibs.jsp

ng-page.jsp

Determina o nome do aplicativo usando o applicationName propriedade e a expõe por meio do pageContext.

Inclui head.jsp e body.jsp.

head.jsp

Escreve o <head> elemento da página do aplicativo.

Se você quiser substituir a metapropriedade viewport do aplicativo, esse será o arquivo que você substituirá.

Seguindo as práticas recomendadas, o aplicativo inclui a parte css das bibliotecas do cliente no cabeçalho, enquanto o JS está incluído no fechamento < body> elemento.

body.jsp

O corpo de uma página de Angular é renderizado de forma diferente dependendo de o wcmMode ser detectado (!= WCMMode.DISABLED) para determinar se a página está aberta para criação ou como uma página publicada.

Modo Autor

No modo de criação, cada página individual é renderizada separadamente. O Angular não lida com o roteamento entre páginas, nem uma ng-view é usada para carregar um modelo parcial que contém os componentes da página. Em vez disso, o conteúdo do modelo de página (template.jsp) é incluído no lado do servidor por meio do cq:include tag.

Essa estratégia permite que os recursos do autor (como adicionar e editar componentes no sistema de parágrafo, Sidekick, modo de design e assim por diante) funcionem sem modificação. As páginas que dependem da renderização do lado do cliente, como aquelas para aplicativos, não têm bom desempenho no modo de autor AEM.

A inclusão template.jsp é encapsulada em um div elemento que contém o ng-controller diretiva. Essa estrutura permite a vinculação do conteúdo DOM com o controlador. Portanto, embora as páginas que se renderizam no lado do cliente falhem, os componentes individuais que o fazem funcionam bem (consulte a seção Componentes abaixo).

<div ng-controller="<c:out value="${controllerNameStripped}"/>">
      <cq:include script="template.jsp"/>
</div>

Modo de publicação

No modo de publicação (como quando o aplicativo é exportado usando a Sincronização de conteúdo), todas as páginas se tornam um aplicativo de página única (SPA). (Para saber mais sobre o SPA, use o tutorial do Angular, especificamente https://docs.angularjs.org/tutorial/step_07.)

Há apenas uma página de HTML em um SPA (uma página que contém a variável <html> elemento). Essa página é conhecida como "modelo de layout". Na terminologia do Angular, é "…um modelo comum a todas as exibições no nosso aplicativo". Considere essa página como a "página do aplicativo de nível superior". Por convenção, a página do aplicativo de nível superior é a cq:Page nó do aplicativo mais próximo à raiz (e não é um redirecionamento).

Como o URI real do seu aplicativo não é alterado no modo de publicação, as referências a ativos externos desta página devem usar caminhos relativos. Portanto, é fornecido um componente de imagem especial que considera essa página de nível superior ao renderizar imagens para exportação.

Como um SPA, essa página de modelo de layout simplesmente gera um elemento div com uma diretiva ng-view.

 <div ng-view ng-class="transition"></div>

O serviço de rota de Angular usa esse elemento para exibir o conteúdo de cada página no aplicativo, incluindo o conteúdo autorável da página atual (contido em template.jsp).

O arquivo body.jsp inclui header.jsp e footer.jsp que estão vazios. Se você quiser fornecer conteúdo estático em cada página, é possível substituir esses scripts no aplicativo.

Por fim, as clientlibs do javascript estão incluídas na parte inferior do <body> elemento incluindo dois arquivos JS especiais gerados no servidor: <page name="">.angular-app-module.js e <page name="">.angular-app-controllers.js

angular-app-module.js.jsp

Este script define o módulo Angular do aplicativo. A saída desse script está vinculada à marcação que o restante do componente do modelo gera por meio do html elemento em ng-page.jsp, que contém o seguinte atributo:

ng-app="<c:out value='${applicationName}'/>"

Esse atributo indica ao Angular que o conteúdo desse elemento DOM deve ser vinculado ao seguinte módulo. Esse módulo vincula as visualizações (no AEM, seriam cq:Page resources) com os controladores correspondentes.

Esse módulo também define um controlador de nível superior chamado AppController que expõe a wcmMode ao escopo e configura o URI do qual buscar cargas de atualização da Sincronização de conteúdo.

Por fim, esse módulo itera por cada página descendente (incluindo ele mesmo) e renderiza o conteúdo do fragmento de rota de cada página (por meio do seletor e extensão angular-route-fragment.js), incluindo-o como uma entrada de configuração para o $routeProvider do Angular. Em outras palavras, o $routeProvider informa ao aplicativo qual conteúdo deve ser renderizado quando determinado caminho for solicitado.

angular-route-fragment.js.jsp

Esse script gera um fragmento JavaScript que deve ter o seguinte formato:

.when('/<path>', {
    templateUrl: '<path to template>',
    controller: '<controller name>'
})

Este código indica a $routeProvider (definido em angular-app-module.js.jsp) que '/<path>' deve ser manipulada pelo recurso em templateUrle conectado por controller (que chegaremos em seguida).

Se necessário, é possível substituir esse script para manipular caminhos mais complexos, incluindo aqueles com variáveis. Um exemplo disso pode ser visto no script /apps/geometrixx-outdoors-app/components/angular/ng-template-page/angular-route-fragment.js.jsp que está instalado com AEM:

// note the :id suffix on the path
.when('<c:out value="${resource.path}"/>/:id', {
    templateUrl: '<c:out value="${relativeResourcePath}"/>.template.html',
    controller: '<c:out value="${controllerNameStripped}"/>'
})

angular-app-controllers.js.jsp

No Angular, os Controladores ativam variáveis no $scope, expondo-as à visualização. O script angular-app-controllers.js.jsp segue o padrão ilustrado por angular-app-module.js.jsp na medida em que repete cada página descendente (incluindo ela mesma) e gera o fragmento do controlador definido por cada página (via controller.js.jsp). O módulo definido é chamado de cqAppControllers e devem ser listados como uma dependência do módulo de aplicativo de nível superior para que os controladores de página sejam disponibilizados.

controller.js.jsp

O script controller.js.jsp gera o fragmento de controlador para cada página. Esse fragmento de controlador assume o seguinte formato:

.controller('<c:out value="${controllerNameStripped}"/>', ['$scope', '$http',
    function($scope, $http) {
        var data = $http.get('<c:out value="${relativeResourcePath}"/>.angular.json' + cacheKiller);

        // component fragments which consume the contents of `data` go here
    }
])

A variável data é atribuída à variável a promessa retornada pelo Angular $http.get método. Cada componente incluído nesta página pode, se desejado, disponibilizar conteúdo .json (por meio do script angular.json.jsp) e agir de acordo com o conteúdo dessa solicitação quando ela for resolvida. A solicitação é muito rápida em dispositivos móveis porque simplesmente acessa o sistema de arquivos.

Para que um componente faça parte da controladora dessa maneira, ele deve estender o componente /libs/mobileapps/components/angular/ng-component e incluir o parâmetro frameworkType: angular propriedade.

template.jsp

Introduzido pela primeira vez na seção body.jsp, o template.jsp simplesmente contém o parsys da página. No modo de publicação, esse conteúdo é referenciado diretamente (em <page-path>.template.html) e carregado no SPA por meio do templateUrl configurado no $routeProvider.

O parsys neste script pode ser configurado para aceitar qualquer tipo de componente. No entanto, é necessário ter cuidado ao lidar com componentes criados para um site tradicional (em vez de um SPA). Por exemplo, o componente de imagem de base funciona corretamente somente na página do aplicativo de nível superior, pois não foi projetado para fazer referência a ativos que estão dentro de um aplicativo.

angular-module-list.js.jsp

Esse script simplesmente gera as dependências do Angular do módulo do aplicativo Angular de nível superior. É referenciado por angular-app-module.js.jsp.

header.jsp

Um script para colocar conteúdo estático na parte superior do aplicativo. Esse conteúdo é incluído pela página de nível superior, fora do escopo da ng-view.

Um script para colocar conteúdo estático na parte inferior do aplicativo. Esse conteúdo é incluído pela página de nível superior, fora do escopo da ng-view.

js_clientlibs.jsp

Substitua esse script para incluir suas bibliotecas de clientes JavaScript.

css_clientlibs.jsp

Substitua esse script para incluir suas bibliotecas de clientes CSS.

Componentes do aplicativo

Os componentes do aplicativo devem funcionar não apenas em uma instância AEM (publicação ou autor), mas também quando o conteúdo do aplicativo for exportado para o sistema de arquivos por meio da Sincronização de conteúdo. O componente deve, portanto, incluir as seguintes características:

  • Todos os ativos, modelos e scripts em um aplicativo PhoneGap devem ser referenciados relativamente.
  • O manuseio de links é diferente se a instância do AEM estiver operando no modo de autor ou publicação.

Ativos relativos

O URI de qualquer ativo específico em um aplicativo PhoneGap difere não apenas em uma base por plataforma, mas é exclusivo em cada instalação do aplicativo. Por exemplo, observe o seguinte URI de um aplicativo em execução no iOS Simulator:

file:///Users/userId/Library/Application%20Support/iPhone%20Simulator/7.0.3/Applications/24BA22ED-7D06-4330-B7EB-F6FC73251CA3/Library/files/www/content/phonegap/geometrixx/apps/ng-geometrixx-outdoors/en/home.html

Observe o GUID '24BA22ED-7D06-4330-B7EB-F6FC73251CA3' no caminho.

Como desenvolvedor do PhoneGap, o conteúdo com o qual você está preocupado está localizado abaixo do diretório www. Para acessar os ativos do aplicativo, use caminhos relativos.

Para compor o problema, seu aplicativo PhoneGap usa o padrão de aplicativo de página única (SPA), para que o URI base (excluindo o hash) nunca seja alterado. Portanto, cada ativo, modelo ou script que você referencia deve ser relativo à página de nível superior. ​ A página de nível superior inicializa o roteamento e os controladores do Angular em virtude do *<name>*.angular-app-module.js e *<name>*.angular-app-controllers.js. Essa página deve ser a mais próxima da raiz do repositório que *não *estende um sling:redirect.

Vários métodos auxiliares estão disponíveis para lidar com caminhos relativos:

  • FrameworkContentExporterUtils.getTopLevelAppResource
  • FrameworkContentExporterUtils.getRelativePathToRootLevel
  • FrameworkContentExporterUtils.getPathToAsset

Para ver exemplos de uso, abra a origem mobileapps localizada em /libs/mobileapps/components/angular.

Os links devem usar o ng-click="go('/path')" para suportar todos os modos WCM. Essa função depende do valor de uma variável de escopo para determinar corretamente a ação do link:

<c:choose><c:when test="${wcmMode}">
    <%-- WCMMode is enabled - page is being rendered in AEM --%>
    $scope.wcmMode = true;
</c:when><c:otherwise>
    <%-- WCMMode is disabled --%>
    $scope.wcmMode = false;
</c:otherwise></c:choose>

Quando $scope.wcmMode == true tratamos cada evento de navegação da maneira usual, de modo que o resultado seja uma alteração no caminho e/ou parte da página do URL.

Em alternativa, se $scope.wcmMode == false, cada evento de navegação resulta em uma alteração na parte de hash do URL, que é resolvida internamente pelo módulo ngRoute do Angular.

Detalhes do script de componente

chlimage_1-144

ng-component.jsp

Este script exibe o conteúdo do componente ou um espaço reservado adequado quando o modo Editar é detectado.

template.jsp

O script template.jsp renderiza a marcação do componente. Se o componente em questão for orientado por dados JSON extraídos do AEM (como "ng-text": /libs/mobileapps/components/angular/ng-text/template.jsp), esse script será responsável por conectar a marcação com dados expostos pelo escopo do controlador da página.

No entanto, os requisitos de desempenho às vezes exigem que nenhum modelo do lado do cliente (também conhecido como vinculação de dados) seja executado. Nesse caso, basta renderizar a marcação do componente no lado do servidor e ela será incluída no conteúdo do modelo de página.

overhead.jsp

Em componentes orientados por dados JSON (como "ng-text": /libs/mobileapps/components/angular/ng-text), overhead.jsp pode ser usado para remover todo o código Java de template.jsp. Ele é referenciado a partir do template.jsp e todas as variáveis que ele expõe na solicitação estão disponíveis para uso. Essa estratégia incentiva a separação da lógica da apresentação e limita a quantidade de código que deve ser copiada e colada quando um novo componente é derivado de um existente.

controller.js.jsp

Conforme descrito em Modelos de página AEM, cada componente pode produzir um fragmento de JavaScript para consumir o conteúdo JSON exposto pelo data promessa. Seguindo as convenções de Angular, um controlador só deve ser usado para atribuir variáveis ao escopo.

angular.json.jsp

Esse script está incluído como um fragmento no campo "<page-name>Arquivo .angular.json' que é exportado para cada página que estende ng-page. Nesse arquivo, o desenvolvedor do componente pode expor qualquer estrutura JSON exigida pelo componente. No exemplo de "ng-text", essa estrutura simplesmente inclui o conteúdo do texto do componente e um sinalizador que indica se o componente inclui ou não rich text.

O componente de produto do aplicativo Geometrixx outdoors é um exemplo mais complexo (/apps/geometrixx-outdoors-app/components/angular/ng-product?lang=pt-BR):

{
    "content-par/ng-product": {
        "items": [{
            "name": "Cajamara",
            "description": "Bike",
            "summaryHTML": "",
            "price": "$610.00",
            "SKU": "eqsmcj",
            "numberOfLikes": "0",
            "numberOfComments": "0"
        }]
    },
    "content-par/ng-product/ng-image": {
        "items": [{
            "hasContent": true,
            "imgSrc": "home/products/eq/eqsm/eqsmcj/jcr_content/content-par/ng-product/ng-image.img.jpg/1377771306985.jpg",
            "description": "",
            "alt": "Cajamara",
            "title": "Cajamara",
            "hasLink": false,
            "linkPath": "",
            "attributes": [{
                "attributeName": "class",
                "attributeValue": "cq-dd-image"
            }]
        }]
    }
}

Conteúdo do download dos ativos CLI

Baixe ativos de CLI no console Aplicativos para otimizá-los para uma plataforma específica e, em seguida, crie o aplicativo usando a API de integração de linha de comando (CLI) do PhoneGap. O conteúdo do arquivo ZIP que você salva no sistema de arquivos local tem a seguinte estrutura:

.cordova/
  |- hooks/
     |- after_prepare/
     |- before_platform_add/
     |- Other Hooks
plugins/
www/
  |- config.xml
  |- index.html
  |- res/
  |- etc/
  |- apps/
  |- content/
  |- package.json
  |- package-update.json

.cordova

Este é um diretório oculto que talvez você não veja, dependendo das configurações atuais do sistema operacional. Você deve configurar o sistema operacional para que esse diretório fique visível se quiser modificar os ganchos de aplicativo que ele contém.

.cordova/ganchos/

Esse diretório contém o Ganchos da CLI. As pastas no diretório de ganchos contêm scripts node.js que são executados em pontos exatos durante a criação.

.cordova/hooks/after-platform_add/

O diretório after-platform_add contém a variável copy_AMS_Conifg.js arquivo. Este script copia um arquivo de configuração para suportar a coleção de análises do Adobe Mobile Services.

.cordova/hooks/after-prepare/

O diretório após a preparação contém o copy_resource_files.js arquivo. Esse script copia vários ícones e imagens da tela de abertura em locais específicos da plataforma.

.cordova/hooks/before_platform_add/

O diretório before_platform_add contém o install_plugins.js arquivo. Esse script repete por meio de uma lista de identificadores de plug-in Cordova, instalando aqueles que ele detecta que ainda não estão disponíveis.

Essa estratégia não requer que você empacote e instale os plug-ins no AEM sempre que o Maven content-package:install é executado. A estratégia alternativa de verificar os arquivos no sistema SCM requer o agrupamento repetitivo e a instalação de atividades.

.cordova/ganchos/Outros ganchos

Inclua outros ganchos conforme necessário. Os seguintes ganchos estão disponíveis (conforme fornecido pelo aplicativo Hello world de amostra do Phonegap):

  • after_build
  • before_build
  • after_compile
  • before_compile
  • after_docs
  • before_docs
  • after_emulate
  • before_emulate
  • after_platform_add
  • before_platform_add
  • after_platform_ls
  • before_platform_ls
  • after_platform_rm
  • before_platform_rm
  • after_plugin_add
  • before_plugin_add
  • after_plugin_ls
  • before_plugin_ls
  • after_plugin_rm
  • before_plugin_rm
  • after_prepare
  • before_prepare
  • after_run
  • before_run

plataformas/

Esse diretório fica vazio até que você execute o phonegap run <platform> no projeto. Atualmente, <platform> pode ser ios ou android.

Depois de criar o aplicativo para uma plataforma específica, o diretório correspondente é criado e contém o código do aplicativo específico da plataforma.

plugins/

O diretório de plug-ins é preenchido por cada plug-in listado no .cordova/hooks/before_platform_add/install_plugins.js após executar o phonegap run <platform> comando. O diretório está inicialmente vazio.

www/

O diretório www contém todo o conteúdo da Web (arquivos HTML, JS e CSS) que implementa a aparência e o comportamento do aplicativo. Exceto pelas exceções descritas abaixo, esse conteúdo é originário do AEM e é exportado para sua forma estática por meio da Sincronização de conteúdo.

www/config.xml

A documentação do PhoneGap (https://docs.phonegap.com) refere-se a esse arquivo como um "arquivo de configuração global". O config.xml contém muitas propriedades do aplicativo, como o nome do aplicativo, as "preferências" do aplicativo (por exemplo, se uma visualização da Web do iOS permite a rolagem excessiva) e as dependências de plug-in que são somente consumido pelo PhoneGap build.

O arquivo config.xml é um arquivo estático no AEM e é exportado como está pela Sincronização de conteúdo.

www/index.html

O arquivo index.html redireciona para a página inicial do aplicativo.

O arquivo config.xml contém o content elemento:

<content src="content/phonegap/geometrixx/apps/ng-geometrixx-outdoors/en.html" />

Na documentação do PhoneGap (https://docs.phonegap.com), esse elemento é descrito como "O <content> O elemento define a página inicial do aplicativo no diretório de ativos da web de nível superior. O valor padrão é index.html, que normalmente aparece em um diretório www de nível superior do projeto."

A build do PhoneGap falhará se um arquivo index.html não estiver presente. Portanto, esse arquivo está incluído.

www/res

O diretório res contém imagens e ícones da tela inicial. A variável copy_resource_files.js O script copia os arquivos para seus locais específicos da plataforma durante o after_prepare fase de criação.

www/etc

Por convenção, no AEM, o nó /etc contém conteúdo clientlib estático. O diretório etc contém as bibliotecas Topcoat, AngularJS e Geometrixx-clientlibsall.

www/apps

O diretório apps contém o código relacionado à página inicial. A característica única da página inicial de um aplicativo AEM é que ele inicializa o aplicativo sem nenhuma interação com o usuário. O conteúdo clientlib (CSS e JS) do aplicativo é, portanto, mínimo para maximizar o desempenho.

www/content

O diretório de conteúdo contém o restante do conteúdo da Web do aplicativo. O conteúdo pode incluir, mas não está limitado aos seguintes arquivos:

  • conteúdo da página HTML, que é criado diretamente no AEM
  • Ativos de imagem associados aos componentes do AEM
  • Conteúdo JavaScript gerado pelos scripts do lado do servidor
  • Arquivos JSON que descrevem o conteúdo da página ou do componente

www/package.json

O arquivo package.json é um arquivo de manifesto que lista os arquivos que um completo O download da Sincronização de conteúdo inclui. Esse arquivo também contém o carimbo de data e hora em que a carga da sincronização de conteúdo foi gerada ( lastModified). Essa propriedade é usada ao solicitar atualizações parciais do aplicativo do AEM.

www/package-update.json

Se essa carga for um download do aplicativo inteiro, esse manifesto conterá a lista exata de arquivos como package.json.

No entanto, se essa carga for uma atualização parcial, package-update.json contém somente os arquivos incluídos nessa carga específica.

Próximas etapas

Depois de saber mais sobre a anatomia de um aplicativo, consulte Aplicativos de página única.

Nesta página