現在表示中:

注意:

アドビは、シングルページアプリケーションフレームワークをベースにしたクライアント側のレンダリング(React など)を必要とするプロジェクトには SPA エディターを使用することをお勧めします。詳細情報

モバイルアプリのページテンプレート

アプリ用に作成するページコンポーネントは、/libs/mobileapps/components/angular/ng-page コンポーネントに基づいています(ローカルサーバー上の CRXDE Lite で開く)。このコンポーネントには次の JSP スクリプトが含まれており、これらのスクリプトを自分のコンポーネントで継承またはオーバーライドします。

  • 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

applicationName プロパティを使用してアプリケーションの名前を決定し、pageContext を使用して公開します。

head.jsp および body.jsp をインクルードしています。

head.jsp

アプリページの <head> 要素を書き出します。

アプリの viewport メタプロパティをオーバーライドする場合は、これがオーバーライド対象のファイルになります。

ベストプラクティスに従って、アプリはクライアントライブラリの css の部分をヘッドにインクルードし、一方 JS は最後の <body> 要素にインクルードされます。

body.jsp

Angular ページのボディは、wcm モードが検出されたかどうか(! = WCMMode.DISABLED)に応じてレンダリングが異なり、ページを作成用に開くか、公開済みページとして開くかが決まります。

オーサーモード

オーサーモードでは、個々のページが個別にレンダリングされます。Angular では、ページ間のルーティングが処理されません。また、ページのコンポーネントが含まれているテンプレートの部分を読み込むために ng-view が使用されることもありません。その代わり、ページテンプレート(template.jsp)のコンテンツが cq:include タグによってサーバー側にインクルードされます。

この方法により、何も変更を加えることなく、オーサー機能(段落システム、サイドキック、デザインモードでのコンポーネントの追加および編集など)を使用可能にすることができます。アプリ向けのページなどクライアント側のレンダリングを利用するページは、AEM オーサーモードではパフォーマンスがよくありません。

template.jsp インクルードは、ng-controller ディレクティブを含む div 要素にラップされることに注意してください。この構造により、DOM コンテンツをコントローラーとリンクできます。このため、クライアント側で自身をレンダリングするページは失敗しますが、同じようにレンダリングする個々のコンポーネントは正常に機能します(下のコンポーネントに関する節を参照)。

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

パブリッシュモード

パブリッシュモード(コンテンツ同期を使用してアプリをエクスポートする場合など)では、すべてのページがシングルページアプリ(SPA)になります(SPA について学ぶ場合は、Angular のチュートリアル、具体的には http://docs.angularjs.org/tutorial/step_07 を使用してください)。

SPA には HTML ページが 1 つのみ存在します(<html> 要素が含まれているページ)。このページは、「レイアウトテンプレート」と呼ばれています。Angular 用語では、「アプリケーション内のすべてのビューに共通するテンプレート」となります。このページは、「トップレベルのアプリページ」と考えてください。慣例により、ルートに最も近い(かつリダイレクトではない)アプリの cq:Page ノードがトップレベルのアプリページになります。

パブリッシュモードではアプリの実際の URI が変わらないので、このページから外部アセットを参照するには相対パスを使用する必要があります。このため、エクスポート用に画像をレンダリングするときにこのトップレベルページを考慮する特殊な画像コンポーネントが用意されています。

SPA として、このレイアウトテンプレートページは単に ng-view ディレクティブとともに div 要素を生成します。

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

Angular ルーティングサービスは、この要素を使用して、(template.jsp に含まれている)現在のページの作成可能なコンテンツなど、アプリ内のあらゆるページのコンテンツを表示します。

body.jsp ファイルには、header.jsp および footer.jsp が空の状態でインクルードされています。どのページにも静的コンテンツを提供する場合には、アプリでこれらのスクリプトをオーバーライドできます。

最後に、サーバーに生成される 2 つの特殊な JS ファイル(<ページ名>.angular-app-module.js と <ページ名>.angular-app-controllers.js.)など、JavaScript clientlibs が <body> 要素の最下部にインクルードされます。

angular-app-module.js.jsp

このスクリプトでは、アプリケーションの Angular モジュールを定義します。このスクリプトの出力は、テンプレートのコンポーネントの残りの部分が html 要素を利用して ng-page.jsp に生成するマークアップにリンクされます。ng-page.jsp には、次の属性が含まれています。

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

この属性は Angular に対して、この DOM 要素のコンテンツを次のモジュールにリンクする必要があることを示します。このモジュールは、ビュー(AEM では cq:Page リソース)を対応するコントローラーとリンクします。

また、wcmMode 変数をスコープに公開するトップレベルのコントローラーを AppController という名前で定義し、コンテンツ同期更新ペイロードを取得する URI を設定します。

最後に、下位の各ページ(自身を含む)を繰り返し処理して、各ページのルートフラグメントのコンテンツを(angular-route-fragment.js セレクターとエクステンションによって)レンダリングし、それを Angular の $routeProvider に対する設定エントリとしてインクルードします。つまり、$routeProvider は特定のパスが要求されたときにどのコンテンツをレンダリングするかをアプリに指示します。

angular-route-fragment.js.jsp

このスクリプトは、次の形式を取る JavaScript フラグメントを生成します。

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

このコードは(angular-app-module.js.jsp に定義されている) $routeProvider に対して、「/<path>」が「templateUrl」でリソースによって処理され、「コントローラー」によってワイヤアップされること(この後で説明します)を示します。

必要に応じて、変数があるものも含めさらに複雑なパスを処理するように、このスクリプトをオーバーライドできます。この一例を AEM とともにインストールされる /apps/geometrixx-outdoors-app/components/angular/ng-template-page/angular-route-fragment.js.jsp スクリプトで確認できます。

// 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

Angular では、コントローラーが変数を $scope にワイヤアップしてビューに公開します。angular-app-controllers.js.jsp スクリプトは、angular-app-module.js.jsp に示されているパターンをフォローします。このパターンでは、各下位のページ(自身を含む)を繰り返し処理して、各ページが(controller.js.jsp によって)定義しているコントローラーフラグメントを出力します。このスクリプトが定義しているモジュールは、cqAppControllers という名前であり、ページコントローラーが使用可能になるようにトップレベルアプリモジュールの依存関係としてリストされる必要があります。

controller.js.jsp

controller.js.jsp スクリプトは、ページごとにコントローラーフラグメントを生成します。このコントローラーフラグメントは、次の形式を取ります。

.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
    }
])

「data」変数には、Angular $http.get メソッドから返された promise が代入されることに注意してください。このページにインクルードされている各コンポーネントでは、必要に応じて一部の .json コンテンツを(その angular.json.jsp スクリプトを利用して)使用可能にし、この要求を解決する際に要求のコンテンツに対して処理を実行できます。要求は、単にファイルシステムにアクセスするだけなので、モバイルデバイスでは非常に高速です。

このようにコンポーネントをコントローラーの一部にするには、コンポーネントを /libs/mobileapps/components/angular/ng-component コンポーネントで拡張し、コンポーネントに frameworkType: angular プロパティを含める必要があります。

template.jsp

先に body.jsp の節で説明したように、template.jsp には単にページの parsys が含まれています。パブリッシュモードでは、このコンテンツは(<ページパス>.template.html で)直接参照され、$routeProvider に設定された templateUrl によって SPA に読み込まれます。

このスクリプトの parsys は、任意のタイプのコンポーネントを受け入れるように設定できます。ただし、(SPA ではなく)従来の Web サイト向けにビルドされたコンポーネントを扱うときには注意が必要です。例えば、基盤画像コンポーネントは、アプリ内部にあるアセットを参照するように設計されていないため、トップレベルアプリページでのみ正しく機能します。

angular-module-list.js.jsp

このスクリプトは、単にトップレベルの Angular アプリモジュールの Angular 依存関係を出力します。スクリプトは、angular-app-module.js.jsp によって参照されます。

header.jsp

アプリの最上部に静的コンテンツを配置するスクリプト。このコンテンツは、トップレベルページによって ng-view のスコープ外にインクルードされます。

footer.jsp

アプリの最下部に静的コンテンツを配置するスクリプト。このコンテンツは、トップレベルページによって ng-view のスコープ外にインクルードされます。

js_clientlibs.jsp

JavaScript clientlibs をインクルードするように、このスクリプトをオーバーライドしてください。

css_clientlibs.jsp

CSS clientlibs をインクルードするように、このスクリプトをオーバーライドしてください。

アプリコンポーネント

アプリコンポーネントは、AEM インスタンス(パブリッシュまたはオーサー)で機能するだけではなく、アプリコンテンツがコンテンツ同期によってファイルシステムにエクスポートされるときにも機能する必要があります。このため、コンポーネントは次の特性を備える必要があります。

  • PhoneGap アプリケーション内のすべてのアセット、テンプレートおよびスクリプトが相対的に参照される必要があります。
  • AEM インスタンスがオーサーモードまたはパブリッシュモードで動作している場合には、リンクの処理が異なります。

相対的なアセット

PhoneGap アプリケーション内の特定のアセットの URI は、プラットフォームごとに異なるだけでなく、アプリのインストールごとに一意になります。例えば、iOS シミュレーターで実行中のアプリの次の URI に注意してください。

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

パスの GUID が「24BA22ED-7D06-4330-B7EB-F6FC73251CA3」となっています。

PhoneGap 開発者に関係するコンテンツは、www ディレクトリの下にあります。アプリアセットにアクセスするには、相対パスを使用します。 

問題が複雑なのは、PhoneGap アプリケーションではシングルページアプリ(SPA)パターンを使用しているので、基準 URI が(ハッシュを除いて)変更されないことです。このため、参照するアセット、テンプレートまたはスクリプトはすべてトップレベルページに相対的である必要があります。トップレベルページでは、Angular のルーティングおよびコントローラーをそれぞれ <名前>.angular-app-module.js および <名前>.angular-app-controllers.js で初期化します。このページは、sling:redirect を拡張しないリポジトリのルートに最も近いページである必要があります。

次の複数のヘルパーメソッドで相対パスに対処できます。

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

これらのメソッドの使用例を参照するには、/libs/mobileapps/components/angular にあるモバイルアプリのソースを開いてください。

リンク

リンクでは、ng-click="go('/path')" 関数を使用して、すべての WCM モードをサポートする必要があります。この関数は、スコープ変数の値を利用して、リンクアクションを正しく判別します。

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

$scope.wcmMode == true の場合は、通常の方法で各ナビゲーションイベントを処理します。その結果、URL のパスやページの部分が変更されます。

一方、$scope.wcmMode == false の場合は、ナビゲーションイベントが発生するたびに URL のハッシュ部分が変更されて、Angular の ngRoute モジュールによって内部で解決されます。

コンポーネントスクリプトの詳細

chlimage_1

ng-component.jsp

このスクリプトは、編集モードが検出されたときにコンポーネントコンテンツまたは適切なプレースホルダーを表示します。 

template.jsp

template.jsp スクリプトは、コンポーネントのマークアップをレンダリングします。AEM から抽出された JSON データ('ng-text': /libs/mobileapps/components/angular/ng-text/template.jsp など)で問題のコンポーネントが駆動される場合、このスクリプトはページのコントローラースコープによって公開されているデータでマークアップをワイヤアップします。 

ただし、パフォーマンス要件のために、クライアント側でテンプレート化(データ連結とも呼ばれます)を実行しないように指示されることがあります。この場合は、単にサーバー側でコンポーネントのマークアップをレンダリングし、それをページテンプレートコンテンツにインクルードします。

overhead.jsp

JSON データ('ng-text': /libs/mobileapps/components/angular/ng-text など)で駆動されるコンポーネントでは、overhead.jsp を使用して、template.jsp からすべての Java コードを削除できます。overhead.jsp は template.jsp から参照され、overhead.jsp が要求で公開している変数は使用可能です。この方法により、ロジックと表示を分離でき、既存のコンポーネントから新規のコンポーネントを生成する場合にコピーして貼り付ける必要があるコードの量を抑えることができます。

controller.js.jsp

AEM ページテンプレートで説明しているように、各コンポーネントは JavaScript フラグメントを出力して、「data」変数に代入された promise で公開されている JSON コンテンツを利用できます。Angular の表記規則に従って、コントローラーはスコープに変数を割り当てる目的でのみ使用します。

angular.json.jsp

このスクリプトは、ng-page を拡張するページごとにエクスポートされるページ全体の <ページ名>.angular.json ファイルにフラグメントとしてインクルードされます。このファイルで、コンポーネント開発者はコンポーネントで必要な任意の JSON 構造を公開できます。「ng-text」の例の場合、この構造に含まれているのは、コンポーネントのテキストコンテンツと、コンポーネントにリッチテキストが含まれているかどうかを示すフラグだけです。 

さらに複雑な例が Geometrixx Outdoors アプリ製品コンポーネントです(/apps/geometrixx-outdoors-app/components/angular/ng-product)。

{
    "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"
            }]
        }]
    }
}

CLI アセットのダウンロードの内容

アプリコンソールから CLI アセットをダウンロードすると、CLI アセットを特定のプラットフォームに合わせて最適化したうえで、PhoneGap コマンドライン統合(CLI)API を使用してアプリをビルドできます。ローカルファイルシステムに保存している ZIP ファイルの内容は、次のような構造になっています。

.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

これは、現在の OS 設定によっては表示されない隠しディレクトリです。このディレクトリに含まれているアプリフックを変更する予定がある場合には、このディレクトリが表示されるように OS を設定する必要があります。

.cordova/hooks/

このディレクトリには、CLI フックが含まれています。hooks ディレクトリ内のフォルダーには、ビルド中に正確な時点で実行される node.js スクリプトが含まれています。

.cordova/hooks/after-platform_add/

after-platform_add ディレクトリには、copy_AMS_Conifg.js ファイルが含まれています。このスクリプトは、Adobe Mobile Services 分析を収集できるように設定ファイルをコピーします。

.cordova/hooks/after-prepare/

after-prepare ディレクトリには、copy_resource_files.js ファイルが含まれています。このスクリプトは、数多くのアイコンおよびスプラッシュスクリーンの画像をプラットフォーム固有の場所にコピーします。

.cordova/hooks/before_platform_add/

before_platform_add ディレクトリには、install_plugins.js ファイルが含まれています。このスクリプトは、Cordova プラグイン識別子のリストを繰り返し処理して、まだ使用可能でないことが検出されたプラグインをインストールします。

この方法により、Maven の content-package:install コマンドを実行するたびにすべてのプラグインを AEM にバンドルおよびインストールする必要がなくなります。別の方法で SCM システムにファイルをチェックインする場合には、バンドルとインストールの作業が繰り返し発生します。

.cordova/hooks/Other Hooks

必要に応じて他のフックがインクルードされます。次のフックを使用できます(PhoneGap サンプルの hello world アプリに用意されています)。

  • 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

platforms/

このディレクトリは、プロジェクトに対して phonegap run <プラットフォーム> コマンドを実行するまで空になっています。現時点では、<プラットフォーム> には ios または android のいずれかを指定できます。

特定のプラットフォーム向けのアプリをビルドすると、対応するディレクトリが作成され、プラットフォーム固有のアプリコードが含められます。

plugins/

plugins ディレクトリには、phonegap run <プラットフォーム> コマンドを実行した後、.cordova/hooks/before_platform_add/install_plugins.js ファイルにリストされている各プラグインが配置されます。初期状態では空になっています。

www/

www ディレクトリには、アプリの外観および動作を実装するすべての Web コンテンツ(HTML、JS、CSS の各ファイル)が含まれています。次に説明する例外を除き、このコンテンツは AEM から発生し、コンテンツ同期によって静的フォームにエクスポートされます。

www/config.xml

PhoneGap ドキュメントでは、このファイルを「グローバル設定ファイル」と呼んでいます。config.xml には数多くのアプリプロパティが含まれており、アプリの名前、アプリの「環境設定」(例えば、iOS WebView でオーバースクロールを許可するかどうかなど)、PhoneGap Build でのみ利用されるプラグイン依存関係などがあります。

config.xml ファイルは、AEM の静的ファイルで、コンテンツ同期によってそのままエクスポートされます。

www/index.html

index.html ファイルは、アプリの開始ページにリダイレクトします。

config.xml ファイルには、content 要素が含まれています。

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

PhoneGap ドキュメントでは、この要素を「このオプションの <content> 要素では、トップレベルの Web アセットディレクトリにアプリの開始ページを定義します。デフォルト値は index.html です。これは、プロジェクトのトップレベルの www ディレクトリに配置されるのが通例です」と説明しています。

index.html ファイルが存在しない場合、PhoneGap Build は失敗します。このため、このファイルがインクルードされています。

www/res

res ディレクトリには、スプラッシュスクリーンの画像およびアイコンが含まれています。copy_resource_files.js スクリプトは、after_prepare ビルドフェーズでこれらのファイルをプラットフォーム固有の場所にコピーします。

www/etc

慣例により、AEM では /etc ノードに静的 clientlib コンテンツが含まれています。etc ディレクトリには、Topcoat、AngularJS および Geometrixx ng-clientlibsall ライブラリが含まれています。

www/apps

apps ディレクトリには、スプラッシュページに関連するコードが含まれています。AEM アプリのスプラッシュページが備える固有の特性は、ユーザーとの対話なしでアプリを初期化することです。このため、パフォーマンスを最大限に高めるために、アプリの clientlib コンテンツ(CSS と JS の両方)が最小化されます。 

www/content

content ディレクトリには、アプリの残りの Web コンテンツが含まれています。主に次のファイルをインクルードできます。

  • HTML ページコンテンツ(AEM に直接作成されます)
  • AEM コンポーネントに関連付けられた画像アセット
  • サーバー側スクリプトが生成する JavaScript コンテンツ
  • ページまたはコンポーネントコンテンツを説明する JSON ファイル

www/package.json

package.json ファイルは、完全コンテンツ同期ダウンロードに含まれるファイルをリストするマニフェストファイルです。このファイルには、コンテンツ同期ペイロードが生成されたタイムスタンプ(lastModified)も含まれています。このプロパティは、AEM にアプリの部分的更新を要求するときに使用されます。

www/package-update.json

このペイロードがアプリ全体のダウンロードである場合、このマニフェストには全ファイルを記載した正確なリストが package.json として含まれています。

一方、このペイロードが部分更新である場合、package-update.json にはこの特定のペイロードに含まれているファイルのみが含まれています。

次のステップ

アプリの詳細な構造について学習したら、シングルページアプリケーションを参照してください。

本作品は Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License によってライセンス許可を受けています。  Twitter™ および Facebook の投稿には、Creative Commons の規約内容は適用されません。

法律上の注意   |   プライバシーポリシー