ヘッドレスのOracle Content Managementを使用したFlutterで最小限のサイトを構築

イントロダクション

Flutterは、Googleによるオープン・ソース・フレームワークで、ネイティブにコンパイルされた、単一コードベースからのマルチプラットフォーム・アプリケーションを構築します。Flutterコードは、任意のデバイスで高速パフォーマンスを実現するために、ARMまたはIntelマシン・コードおよびJavaScriptにコンパイルされます。Flutterは、Oracle Content Managementからコンテンツを消費するアプリケーションを構築するための強力なツールです。適切なコンテンツ・モデルを使用して、典型的なブログを構成するFlutter UIを迅速に構築できます。

このチュートリアルでは、Oracle Content ManagementをヘッドレスCMSとして活用することで、Flutterでシンプルな最小限のサイトを構築します。このFlutterサンプルは、GitHubで入手できます。

このチュートリアルは、次の3つのステップで構成されています。

  1. Oracle Content Managementの準備
  2. Flutterで最小限のサイトを構築
  3. デプロイメント用のアプリケーションの準備

前提条件

このチュートリアルに進む前に、最初に次の情報を読むことをお薦めします。

このチュートリアルに従うには、次のものが必要です。

構築内容

Flutterが最小限の場合は、イメージおよびその他のコンテンツをOracle Content Managementリポジトリから簡単に取得できます。

ビルドする内容を確認するには、Oracle Content Managementのコンテンツを使用する基本的なFlutter最小サイトであるチュートリアルの終了状態を次に示します。

ホーム画面はこのチュートリアルの最後に表示されます。

この図は、Flutter最小サイトのランディング・ページを示しています。

このチュートリアルの最後には、「contact us」画面は次のようになります。

この図は、Flutter最小サイトの「連絡先」ページを示しています。

続行するには、Oracle Content Managementへのアクティブなサブスクリプションがあり、コンテンツ管理者ロールでログインする必要があります。

タスク1: Oracle Content Managementの準備

Oracle Content Managementインスタンスがまだない場合は、クイック・スタートを参照して、Oracle Cloudに登録する方法、Oracle Content Managementインスタンスのプロビジョニング方法、およびOracle Content ManagementをヘッドレスCMSとして構成する方法を学習します。

このチュートリアルでは、コンテンツ・モデルを作成する必要があります。使用可能なダウンロード可能なアセット・パックがあり、コンテンツ・タイプおよび関連するコンテンツで空のリポジトリを埋めます。

Oracle Content Managementを準備するには:

  1. チャネルおよびアセット・リポジトリの作成
  2. Oracle Content Managementサンプル資産パックのインポート

チャネルおよびアセット・リポジトリの作成

コンテンツを公開するには、まずOracle Content Managementでチャネルおよびアセット・リポジトリを作成する必要があります。

Oracle Content Managementでチャネルおよびアセット・リポジトリを作成するには:

  1. Oracle Content Management Webインタフェースに管理者としてログインします。

  2. 左側のナビゲーション・メニューで「コンテンツ」を選択し、ページ・ヘッダーの選択リストから「チャネルの公開」を選択します。

    この図は、「コンテンツ」ページ・ヘッダーのドロップダウン・メニューで選択された「公開チャネル」オプションを示しています。

  3. 右上隅にある「Create」をクリックして、新しいチャネルを作成します。このチュートリアルの目的でチャネルにOCEMinimalChannelという名前を付け、アクセスをパブリックにしておきます。「保存」をクリックしてチャネルを作成します。

    この図は、チャネル名フィールドに'OCEMinimalChannel'がある公開チャネル定義パネルを示しています。

  4. 左側のナビゲーション・メニューで「コンテンツ」を選択し、ページ・ヘッダーの選択リストから「リポジトリ」を選択します。

    この図は、「コンテンツ」ページ・ヘッダーのドロップダウン・メニューで選択された「リポジトリ」オプションを示しています。

  5. 右上隅にある「作成」をクリックして、新しいアセット・リポジトリを作成します。このチュートリアルでは、アセット・リポジトリにOCEMinimalRepositoryという名前を付けます。

    この図は、リポジトリ名フィールドにOCEMinimalRepositoryが付いたリポジトリ定義パネルを示しています。

  6. 「公開チャネル」フィールドで、OCEMinimalChannelチャネルを選択して、OCEMinimalRepositoryリポジトリ内のコンテンツをOCEMinimalChannelチャネルに公開できることをOracle Content Managementに示します。終了したら、「Save」をクリックします。

    この図は、「公開チャネル」フィールドにOCEMinimalChannelが付いたリポジトリ定義パネルを示しています。

Oracle Content Managementサンプル資産パックのインポート

このチュートリアルに必要なすべてのコンテンツ・タイプおよびアセットを含む、事前構成されたOracle Content Managementサンプル・アセット・パックをダウンロードできます。

このチュートリアルで使用するコンテンツのコピーは、Oracle Content Management Samples Asset Packからアップロードできます。これにより、コンテンツ・タイプを試して内容を変更できます。Oracle Content Management Samples Asset Packをインポートする場合は、アセット・パック・アーカイブOCESamplesAssetPack.zipをダウンロードし、選択したディレクトリに抽出できます。

  1. Oracle Content Managementのダウンロード・ページからOracle Content Management Samples Asset Pack (OCESamplesAssetPack.zip)をダウンロードします。ダウンロードしたzipファイルをコンピュータ上の場所に抽出します。抽出後、この場所にはOCEMinimal_data.zipというファイルが含まれます。

  2. Oracle Content Management Webインタフェースに管理者としてログインします。

  3. 左側のナビゲーション・メニューで「コンテンツ」を選択し、ページ・ヘッダーの選択リストから「リポジトリ」を選択します。次に、OCEMinimalRepositoryを選択し、上部アクション・バーの「コンテンツのインポート」ボタンをクリックします。

    この図は、OCEMinimalRepositoryアイテムが選択された「リポジトリ」ページを示しています。

  4. OCEMinimal_data.zipをローカル・コンピュータから「ドキュメント」フォルダにアップロードします。

    この図は、OCEMinimal_data.zipファイルのアップロード確認画面を示しています。

  5. アップロードしたら、OCEMinimal_data.zipを選択し、「OK」をクリックしてコンテンツをアセット・リポジトリにインポートします。

    この図は、「OK」ボタンが有効になっている選択したOCEMinimal_data.zipファイルを示しています。

  6. コンテンツが正常にインポートされたら、「アセット」ページに移動し、OCEMinimalRepositoryリポジトリを開きます。すべての関連イメージおよびコンテンツ項目がアセット・リポジトリに追加されたことがわかります。

    このイメージは、OCEMinimalRepositoryリポジトリと、インポートされたばかりのすべてのアセットを示しています。

  7. 左上の「すべて選択」をクリックし、「公開」をクリックして、以前に作成した公開チャネル(OCEMinimalChannel)にインポートされたすべてのアセットを追加します。

    この図は、OCEMinimalRepositoryリポジトリを示しています。すべてのアセットが選択され、アクション・バーの「公開」オプションが表示されています。

  8. 公開する前に、すべての資産を検証する必要があります。最初に、選択したチャネルとしてOCEMinimalChannelを追加し、「検証」ボタンをクリックします。

    この図は、「検証結果」ページを示しています。このページには、「チャネル」フィールドにOCEMinimalChannelチャネルが追加され、検証されるすべてのアセット、および「検証」ボタンが有効になっています。

  9. アセットの検証後、右上隅にある「公開」ボタンをクリックして、選択したチャネルにすべてのアセットを公開できます。

    この図は、「検証結果」ページを示しています。「チャネル」フィールドにOCEMinimalChannelチャネルが追加され、すべてのアセットが検証され、「公開」ボタンが有効になっています。

完了すると、すべてのアセットが公開された「アセット」ページが表示されます。(アセット名の上にあるアイコンで確認できます。)

この図は、すべての資産が公開された「資産」ページを示しています。

タスク2: Flutterでの最小サイトの作成

FlutterアプリケーションでOracle Content Managementコンテンツを消費するには、GitHubでオープン・ソース・リポジトリとして使用できるFlutter最小サイト・サンプルを使用します。

ノート: Flutterサンプルの使用はオプションであり、このチュートリアルで使用してすぐに開始することに注意してください。独自のFlutterアプリケーションを作成することもできます。

Flutterでの最小サイトの作成は、次のステップで構成されます。

  1. Flutterのインストール
  2. サンプル・リポジトリのクローニングと依存関係のインストール
  3. Flutterアプリケーションの構成
  4. Oracle Content Management REST APIを使用したコンテンツのフェッチ

Flutterのインストール

Flutterを初めて使用する場合は、環境を設定します。それを設定する手順は、FlutterのWebサイトにあります。オペレーティング・システムに対応するオプションを使用します。インストール手順のサマリーを次に示します。

  1. Flutter SDKを入手しましょう。
  2. パス環境変数を更新します。
  3. flutter doctorを実行します。
  4. FlutterのWebサイトで説明されているステップに従って、選択したエディタをインストールします。
  5. Android Studio、IntelliJ、VSコードまたはEmacsのエディタ・プラグインを追加します。手順では、エディタにFlutterおよびDartプラグインをインストールする方法を指定します。
  6. 適切な場所、sdkおよびkotlinバージョンを参照するように、android.propertiesファイルの値を変更します。また、適切なバージョンのandroid.gradleファイルの値を変更する必要もあります。

サンプルリポジトリのクローニングと依存関係のインストール

Flutter最小サイト・サンプルは、GitHubでオープンソース・リポジトリとして使用できます。

まず、GitHubからローカル・コンピュータにサンプルをクローニングし、ディレクトリをリポジトリ・ルートに変更する必要があります:

git clone https://github.com/oracle-samples/oce-flutter-minimal-sample.git
cd oce-flutter-minimal-sample

Android Studioまたはその他の任意のエディタからプロジェクトを開きます。プロジェクトで使用されているすべてのパッケージを取得するには、「パッケージの取得」ボタンをクリックします。

Flutterアプリケーションの構成

このFlutterの最小サンプルでは、REST APIリクエストが適切なインスタンスURLおよびAPIバージョンを正しいチャネル・トークンでターゲットにできるように、いくつかの情報を構成する必要があります。lib/config/oce.dartで定義されたこれらの値は、REST APIのエンドポイントを確立するためにlib/networking/content.dartで定義された関数で使用されます。

lib/config/oce.dartに次の情報が表示されます。

const Map<String, String> config = <String, String>{
  'serverUrl': 'https://samples.mycontentdemo.com',
  'apiVersion': 'v1.1',
  'channelToken': 'ba0efff9c021422cb134c2fd5daf6015'
};

各キーと値のペアを、インスタンスURL、ターゲットにするAPIバージョンおよび公開チャネルに関連付けられたチャネル・トークンを反映するように変更します。このチュートリアルのチャネルはOCEMinimalChannelです。

また、アプリケーション全体で使用するイメージも構成する必要があります。同じファイルに次の内容が表示されます。

const Map<String, String> appConfig = <String, String>{
  'homePage': 'Banner1.jpg',
  'contactUs' : 'Banner2.jpg',
  'logo' : 'Logo.png',
  'footerLogo' : 'Powered_by_OCE.png',
};

インスタンスの値を反映するように各イメージの名前を変更します。

Oracle Content Management REST APIを使用したコンテンツのフェッチ

コンテンツ配信用のREST APIでは、Oracle Content Managementで公開されたアセットにアクセスできます。公開済アセットには、コンテンツ・アイテムやデジタル・アセット、およびそれらのレンディションが含まれます。これで、Oracle Content Management REST APIを使用してコンテンツをフェッチし、最小のFlutterアプリケーションでレンダリングできるようになりました。

lib/networking/content.dartファイルには、REST APIを使用してoce.dartファイルに指定されたサーバーに接続し、そこからレスポンスを返すメソッドがあります。

  //Utility method to build up the URL for published content.
  String _getPublishedContentServerURL() {
    final String? serverUrl = data['serverUrl'] as String?;
    final String? apiVersion = data['apiVersion'] as String?;
    return '$serverUrl/content/published/api/$apiVersion/';
  }

  // Adds the channel token to the URL
  String _addChannelToURL(String currUrl) {
    final String? channelToken = data['channelToken'] as String?;
    return '$currUrl?channelToken=$channelToken';
  }

  //Make an http get call and return the response if successful
  Future<dynamic> _get(String url) async {
    dynamic responseJson;
    try {
      final Response response = await get(Uri.parse(url));
      responseJson = _returnResponse(response);
    } on SocketException {
      throw FetchDataException(kConnectionError);
    }
    return responseJson;
  }

  //Return the json decoded response body if response status is successful
  dynamic _returnResponse(Response response) {
    switch (response.statusCode) {
      case 200:
        final Map<String, dynamic>? responseJson =
            json.decode(response.body.toString()) as Map<String, dynamic>?;
        return responseJson;
      case 400:
        throw BadRequestException(response.body.toString());
      case 401:
      case 403:
        throw UnauthorizedException(response.body.toString());
      case 500:
      default:
        throw FetchDataException('StatusCode : ${response.statusCode}');
    }
  }

イメージをレンダリングする場合、content.dartには、アセットの様々なレンディションを取得するためのヘルパー・メソッドも用意されています。

  String getMediumRenditionUrl(Map<String, String> args) {
    final String itemId = args['id'];
    if (itemId == null) return null;
    String url = _getPublishedContentServerURL();
    url = '${url}assets/$itemId/Medium';
    // add the channel token to the URL
    url = _addChannelToURL(url);
    url = '$url&format=jpg&&type=responsiveimage';
    return url;
  }

  String getRenditionURL(Map<String, String> args) {
    final String itemId = args['id'];
    if (itemId == null) return null;
    String url = _getPublishedContentServerURL();
    url = '${url}assets/$itemId/native';
    // add the channel token to the URL
    url = _addChannelToURL(url);
    return url;
  }

lib/networking/services.dartファイルには、アプリケーションのデータを取得するためのすべてのコードが含まれています。

イメージ・データのフェッチ中

lib/networking/services.dartを開き、このアプリケーションのすべてのイメージの取得に役立つ次の機能を見つけます。

  // Get all the images needed for the app
  Future<AppImages> getAppImages() async {
    final Content content = Content();
    final String homepageImage = appConfig['homePage'];
    final String contactUsImage = appConfig['contactUs'];
    final String logoImage = appConfig['logo'];
    final String footerImage = appConfig['footerLogo'];
    AppImages images;
    try {
      final dynamic data = await content.queryItems(<String, String>{
        'q':
            '(name eq "$homepageImage" OR name eq "$contactUsImage" OR name eq "$logoImage" OR name eq "$footerImage")',
        'fields': 'all',
        'expand': 'all',
      });
      final List<dynamic> items = data['items'] as List<dynamic>;
      String homePageImageGUID,
          contactUsImageGUID,
          headerLogoGUID,
          footerLogoGUID;
      for (int i = 0; i < items.length; i++) {
        final String name = items[i]['name'] as String;
        final String id = items[i]['id'] as String;
        if (name == homepageImage) {
          homePageImageGUID = id;
        } else if (name == contactUsImage) {
          contactUsImageGUID = id;
        } else if (name == logoImage) {
          headerLogoGUID = id;
        } else if (name == footerImage) {
          footerLogoGUID = id;
        }
      }
      //If any of the image ids are null, let the user know but continue loading the app
      if (homePageImageGUID == null ||
          contactUsImageGUID == null ||
          headerLogoGUID == null ||
          footerLogoGUID == null) {
        print(kFileNameError);
      }
      images = AppImages(
        headerLogoUrl: content.getRenditionURL(<String, String>{'id': headerLogoGUID}),
        footerLogoUrl: content.getRenditionURL(<String, String>{'id': footerLogoGUID}),
        contactUsImageUrl:
            content.getMediumRenditionUrl(<String, String>{'id': contactUsImageGUID}),
        homePageImageUrl: content.getMediumRenditionUrl(<String, String>{'id': homePageImageGUID}),
      );
    } catch (exception) {
      rethrow;
    }
    return images;
  }
;

これでデータ問合せができたので、Flutterコンポーネントでレスポンスをレンダリングできます。

フロッターコンポーネント

最小限のアプリケーションによって、各ページが複数の小さなコンポーネントに分割されます。

次のいくつかのセクションでは、各コンポーネントでFlutterがアプリケーションをどのようにレンダリングするかの概要を説明します。

LoadingScreenコンポーネント

LoadingScreenは、lib/screens/load_screen.dartにあるLoadingScreenコンポーネントによってレンダリングされるステートフル・ウィジェットです。

lib/screens/load_screen.dartファイルには、画面のデータを取得するためのすべてのコードが含まれており、service.dartに定義されている関数を呼び出します。

  Future<void> getData() async {
    final Services services = Services();
    try {
      final AppImages images = await services.getAppImages();
      if (images != null) {
        Navigator.push<dynamic>(context,
            MaterialPageRoute<dynamic>(builder: (BuildContext context) {
          return HomePage(appImages: images);
        }));
      }
    } catch (exception) {
      setState(() {
        this.exception = exception.toString();
      });
      print(exception.toString());
    }
  }

コンポーネントは、getDataメソッドを使用して、service.dartファイルに定義されているメソッドを使用してデータを取得します。

HomePageコンポーネント

ホーム画面は、lib/screens/home_page.dartにあるHomePageコンポーネントによってレンダリングされます。

HomePageコンポーネントは、データを渡すLoadingScreenコンポーネントによって起動されます。サーバーから追加データは取得されません。

また、lib/components/screen_layout.dartファイルで定義された ScreenLayoutコンポーネント、およびlib/components/image_stack.dartファイルで定義された ImageStackコンポーネントも使用します。

ContactUsコンポーネント

「Contact Us」画面は、lib/screens/contact_us.dartにあるContactUsコンポーネントによってレンダリングされます。

ContactUsコンポーネントは、データを渡すlib/components/navdrawer.dartファイルで定義されているNavDrawerコンポーネントによって起動されます。サーバーから追加データは取得されません。また、lib/components/image_stack.dartファイルで定義されているImageStackコンポーネントも使用します。

タスク3:アプリケーションのデプロイメントの準備

Flutter最小限のサイトを構築したので、エミュレータまたはデバイスに展開し、問題をデバッグしてアプリケーションをプレビューしてから稼働する必要があります。

エディタのFlutter Webサイトの手順に従ってアプリケーションを実行します。

  1. エディタとしてAndroid Studioを使用している場合は、Android Studioのメイン・ツールバーを探します。
  2. ターゲット・セレクタで、アプリケーションを実行するAndroidデバイスを選択します。使用可能なものとしてリストされていない場合は、「ツール」→「Android」→「AVD Manager」を選択して作成します。詳細については、Managing AVDsを参照してください。
  3. ツールバーの「実行」アイコンをクリックするか、メニュー項目「実行」→「実行」を起動します。

まとめ

このチュートリアルでは、Flutterで最小限のサイトを作成し、GitHubで入手できます。このサイトでは、Oracle Content ManagementをヘッドレスCMSとして使用しています。最小限サイト・チュートリアル用に公開されたコンテンツのチャネルを使用してOracle Content Managementを設定および構成した後、Flutterサイトをインストールして実行し、必要なコンテンツをフェッチしてサイトを構築しました。

Flutterの詳細は、FlutterのWebサイトを参照してください。

Oracle Content Managementの重要な概念については、ドキュメンテーションを参照してください。

このようなサンプルは、Oracle Help CenterOracle Content Managementサンプル・ページで確認できます。