microCMSｘWebARで作る何処でもPRTIMES

# はじめに
この記事は、「microCMSでこんなことができた！あなたのユースケースを大募集 by microCMS Advent Calendar 2024」の17日目です。

microCMSとは、APIをベースとした国産のヘッドレスCMSの一種です。 
ヘッドレスCMSとはフロントエンドがないタイプのCMSであり、バックエンドを分離することでサイトの修正をスピーディーにし、より効率的に管理できるようにしています。

microCMSで、更新要素のある記事を記載することで、常に最新記事を取得できることが魅力に感じます。
何か面白いことができそうな、わくわく感があり、挑戦することにしました。

自社サービスを紹介する、PRTIMESなどのサイトがありますが、
これをmicroCMSを使えば、サイネージ的に、スマホのブラウザで表示することは、直ぐに思いつくところだと思います。
ここでは、もう少し捻って、２次元表現ではなく、３次元のＡＲで表示することにしてみました。
スマホのカメラでＱＲコードを読み込み、好きなところに配置し、どこでも最新記事が見られる！
近未来感を感じませんでしょうか。
興味を少しでも、持たれた方は、しばしお時間を頂ければと思います。

# イメージ動画
まずは、動作動画を見てください。
<iframe width="560" height="315" src="https://www.youtube.com/embed/YLFXL9CHnaE?si=AhrpUrSg8hVkzhKJ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

ブラウザから、記事一覧をAR召喚し、タップすることで、詳細を確認できます。
更に、URLボタンを押すと、元記事に、ジャンプします。

記事一覧は、microCMSで、更新できるので、同じURLで、いつでも最新情報が、見られる！
推し情報を載せるもよし、特定の場所（GPS連動）でないと見られない内容にするも良し、
使い方はあなた次第！
ワクワクしませんか！？、ワタクシは、脳汁でました（笑）

# 全体イメージ図
![スライド1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/8660a23b-84a8-b35f-7ecf-9bf26f81ac26.jpeg)



##
以降は、技術的な情報となります。
どうやって、作っているのか、流れを掴んでもらえれば幸いです。

# 配信記事のための準備
microCMSの設定を行い、記事を配信する方法を解説します。
[microCMSのサイト](https://microcms.io/)にアクセスしてアカウントを作成してください。

サービス管理の画面を表示し、追加ボタンを押して、新規サービスを作成してください。
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/23f01616-f87d-d97c-f02f-c3527da26037.png)

今回は、「一から作成する」を選択します。
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/a5c3cfa0-dbb6-8b47-354e-3b5e2abdd87d.png)

自分が決めた好きな「サービス名」、「サービスID」を適切に入力し、サービスを作成してください。
![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/15f59cd4-bfc1-dcab-43c2-e60a1be7a61b.png)

サービス管理に、先ほど作成したサービスが表示されるので、選択してください。
![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/19272aaa-49e8-05b4-ff42-133af5ac9613.png)

まだ、配信する情報が無いため、「コンテンツ（API）」を選択して、新規に作成します。
![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/52fbdb2d-8672-e101-3632-25a3b5d6dc13.png)

今回は、「自分で決める」を選択します。
![006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/c69f8d33-7dd0-4c00-dfa3-5aebdb9f0ee2.png)

自分が決めた好きな「API名」、「エンドポイント」名を適切に入力し、次へすすんでください。
![007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/4522421e-e586-ee49-1c99-f4836c0c6109.png)

APIの型は、ニュース記事を、都度投稿したいため、「リスト形式」を選択し、次へすすんでください。
![008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/ad7dfcdb-0502-c55d-f533-b8a37052750e.png)

配信する記事の入力情報を決めます。
PRTIMESのRSSを意識して、ここでは、３つ追加します。
| フィールドID | 表示名 | 種類 |
| :---: | :---: | :---: |
| title | タイトル | テキストフィールド |
| link | リンク | テキストフィールド |
| description | 詳細 | テキストフィールド |

入力の上、作成をしてください。

![009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/d7b0ed22-693a-c675-fcd4-e61e8bb7a474.png)

以上で、記事を投稿する準備ができました。

# 配信記事の設定

配信したい記事を１つずつ入力します。
「タイトル」、「リンク」、「詳細」を入力の上、「公開」ボタンを押してください。
![010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/dcc72091-99db-15a4-12f1-11b5079bfe78.png)

ステータスが、「公開中」になっていることを確認してください。
更に記事を追加したい場合は、「追加」ボタンを押して、入力を続けてください。
![011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/f89d0ff4-57eb-78e8-da7e-fdc39f9f1349.png)

以上で、記事に公開ができました。

# クライアントのWebアプリケーション
今回は、クライアントのWebアプリケーションの開発に、HTML、CSS、WebGLを使います。
そして、ブラウザでのARを実現します。
WebGL開発のには、Unityを使用しました。（WebGLファイルを出力させます）
全部を記載すると、大量な情報量となるため、ここでは、microCMSとの連携に重要なUnityからのアクセス方法のみを記載することにします。

# シーケンス図
ブラウザから、該当ページにアクセスして、microCMSから記事を取得するためのシーケンス図を載せておきます。

![シーケンス図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76959/4151a730-e242-39db-0185-5337124fb312.png)


# サンプルコード
シーケンス図の内容を実現するためのUnityのサンプルコードを以下に記載します。
実装の参考にしてください。

Hierarchyに、CreateEmptyで、GameObjectを作成し、Nameを「Manager」にしてください。
下記、スクリプト「MicroCMSDataFetcherScript.cs」を追加してください。
Unityのスクリプトを起点として、microCMSのデータを、JSLIBを通過し、HTML内のJavaScript経由で取得します。

```[Unity]Assets/Scripts/MicroCMSDataFetcherScript.cs
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;

/// <summary>
/// MicroCMSDataFetcherScript
/// </summary>
public class MicroCMSDataFetcherScript : MonoBehaviour
{
#if UNITY_WEBGL && !UNITY_EDITOR
    [DllImport("__Internal")]
    private static extern void FetchMicroCMSData(string callbackFunction);
#endif

    public UnityEngine.UI.Text textNews;
    protected bool _isUpdateNews = false;
    protected string _resultText = string.Empty;

    /// <summary>
    /// ResultText
    /// </summary>
    public string ResultText
    {
        get { return _resultText; }
    }

    /// <summary>
    /// Start
    /// </summary>
    void Start()
    {
        StartCoroutine(FetchDataFromMicroCMS());
    }

    /// <summary>
    /// Update
    /// </summary>
    public void Update()
    {
        if (_isUpdateNews)
        {
            _isUpdateNews = false;
            SetDebugText(_resultText);
        }
    }

    /// <summary>
    /// FetchDataFromMicroCMS
    /// </summary>
    public IEnumerator FetchDataFromMicroCMS()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        FetchMicroCMSData("OnDataReceived");
#else
        Debug.LogWarning("FetchMicroCMSData is only supported in WebGL builds.");
#endif
    }

    /// <summary>
    ///  コールバックとして呼び出される関数
    /// </summary>
    /// <param name="tsdata"></param>
    public void OnDataReceived(string tsdata)
    {
        _resultText = tsdata;
        Debug.Log(_resultText);
        _isUpdateNews = true;
    }

    /// <summary>
    /// SetDebugText
    /// </summary>
    /// <param name="strJson"></param>
    protected void SetDebugText(string strJson)
    {
        try
        {
            var dataUnity = JsonUtility.FromJson<PriTimeInfos>(strJson);
            if (dataUnity.infos== null)
            {
                return;
            }

            if (textNews != null)
            {
                var text = string.Empty;

                foreach (var info in dataUnity.infos)
                {
                    text += string.Format("{0}, {1}, {2}", info.title, info.link, info.description);
                }

                textNews.text = text;
            }
        }
        catch (System.Exception e)
        {
            if (textNews != null)
            {
                textNews.text = e.Message + "\n" + strJson;
            }
        }
    }
}
```

Unityのコードから、「FetchMicroCMSData」APIが呼び出され、HTML内の関数を呼び出します。

```[Unity]Plugins/microcms.jslib
mergeInto(LibraryManager.library, {
  FetchMicroCMSData: function (callbackPointer) {
    // Unityから渡されたコールバックを文字列で受け取る
    const callbackFunction = UTF8ToString(callbackPointer);
    
    // Unityから渡された関数名でFetchMicroCMSDataを呼び出す
    window.FetchMicroCMSData(callbackFunction);
  }
});
```

JavaScript経由で、microCMSのデータを取得します。
ここでは、microCMSから取得したデータを、作成アプリ向けのJSONデータに加工しています。
このようにすることで、システム間の仕様を疎結合にしています。

```[Unity]Assets/WebGLTemplates/index.html
追加要素

<!-- microcms-js-sdkの読み込み -->
<script src="https://unpkg.com/microcms-js-sdk@latest/dist/umd/microcms-js-sdk.js"></script>
<script>
    // Unityから呼び出される関数
    function FetchMicroCMSData(callbackFunction) {
        const { createClient } = microcms;
        const client = createClient({
            serviceDomain: 'XXXXX',
            apiKey: 'XXXXXXXXXXXXXX',
        });

        client.get({ endpoint: 'news' }).then((res) => {
            const contents = res.contents;

            let tsdata = '{"infos":[';

            contents.forEach((content, index) => {
                tsdata += '{"title":"';
                tsdata += content.title;

                tsdata += '","link":"';
                tsdata += content.link;

                tsdata += '","description":"';
                tsdata += content.description;
                tsdata += '"}';

                // 最後の要素以外にカンマを追加
                if (index < contents.length - 1) {
                    tsdata += ',';
                }
            });

            tsdata += "]}";

            if (window.unityInstance && window.unityInstance.SendMessage) {
                window.unityInstance.SendMessage("Manager", callbackFunction, tsdata);
            }
        }).catch((error) => {
            console.error(error);
            if (window.unityInstance && window.unityInstance.SendMessage) {
                window.unityInstance.SendMessage("Manager", callbackFunction, "Error fetching data");
            }
        });
    }
</script>
```

# おわりに
いかがでしたでしょうか。
micro CMSを、WebGLで、導入するイメージを持っていただけたのではないでしょうか。
今回は、クライアントに、Unityを用いたものとなります。
Unityは、最新版であるUnity6の登場により、今後、ブラウザアプリの火付け役が期待されます。
そのため、microCMSとの連携サービスが、使われる機会が増えてくるのではないでしょうか。
本記事が、皆様の快適なライフハックに繋がれば幸いです。

よりよいご意見有りましたらお待ちしております。
お仕事依頼も、承っております。