コンテンツにスキップ

着せ替えアプリとの接続

自社アプリから着せ替えアプリへのリンクを張り、ID連携を実装することで、エンドユーザは着せ替え操作を簡単に行えるようになります。本ページでは、接続用エンドポイントを使った連携方法について説明します。ウェブアプリケーションや、アプリ内ブラウザ(WebView)から接続用エンドポイントを呼び出すことを想定しています。

UI Kit をご利用の方

UI Kit の着せ替え画面を利用する場合、先に着せ替え画面との接続を参照ください。connectUrl パラメータに指定したエンドポイントで、本ページで説明する内容を実装します。

Unity SDK をご利用の方

Unity SDK を利用する場合、Unity SDK での着せ替えアプリとの接続を参照ください。

自社アプリ内でアバターを利用しない方

自社アプリ内でアバターを利用しない場合は、自社のウェブページなどから https://fit.avatarplay3d.com へのリンクを張ってください。リンク用のUIは、後述のUI実装の項を参照してください。

接続の流れ

自社アプリからエンドユーザを接続エンドポイントへ誘導し、その後、指定したリダイレクトURIへエンドユーザが来訪して接続が完了します。

接続フロー

自社アプリから着せ替えアプリのインストール画面へ進むまでの間、ウェブページが数回表示されます。この遷移は、アプリ内ブラウザ(WebView)含め、一般的なウェブ環境で動作します。

自社アプリ側のUI実装

UI Kit をご利用の方

UI Kit の着せ替え画面を利用する場合、本項目は読み飛ばしてください。UI Kit 内に着せ替えアプリへのリンクが設置されるため、自社アプリ側でUIを実装する必要はありません。

Avatar Play へのリンク用のUI(ボタン、テキストリンク、アイコンなど)を、自社アプリの設定画面などに配置します。

ボタン、テキストリンク

ボタンやテキストリンクを使う場合は、「Avatar Play を使う」という文言を利用してください。

ボタンリンク

アイコン

以下のアイコン画像を利用できます。

  1. 120x120ピクセルのアイコン
  2. 180x180ピクセルのアイコン

以下のように、アイコンの近くに「Avatar Play」という文言を配置してください。

アイコンリンク

RESTful API を有効化する

RESTful API の項を参考にAPIへの接続環境をセットアップしてください。

接続用エンドポイントを構成する

前述のリンクが押された後、接続用エンドポイントを構成してエンドユーザをそこへリダイレクトします。UI Kit の着せ替え画面を利用している場合、 connectUrl パラメータで指定したエンドポイントで接続用のURLを構成し、エンドユーザをリダイレクトします。

エンドポイント仕様

URL

https://fit.avatarplay3d.com/connect

パラメータ

パラメータ 必須 説明 値のサンプル
appId アプリID 1234567890
redirectUri 着せ替えアプリから戻ったときに呼び出される自社アプリのリダイレクトURI(エンドポイントURLまたはカスタムURLスキーム)です。事前にデベロッパーコンソールの「アプリ > アプリの設定 > 変更」から、指定するリダイレクトURLを登録しておく必要があります。 https://example.com/callback
scope パーミッション(後述)をカンマ区切りで連結した文字列 AvatarLoad,ItemGrant
codeChallenge 後述 abcdefghi...
avatarId アップグレード前のゲストユーザのアバターID。アップグレードの場合は指定必須。 1234567890

パーミッション

個別のアバターに対し、自社アプリに与えられた権限です。パーミッションをカンマ区切りで連結してスコープの値を作ります。デフォルトではアバターを表示するパーミッションのみが付与されますが、追加の権限を要求できます。

パーミッション コード 説明
アバターを表示する権限 AvatarLoad エンドユーザのアバターを自社アプリ内で利用する権限です。自社アプリは、アプリ内でエンドユーザ自身のアバターをロードすることはもちろんのこと、自社アプリを利用している他のユーザのアバターをロードすることも可能です。自社アプリを利用していないユーザのアバターをロードすることはできません。
アイテムを付与する権限 ItemGrant 自社アプリがエンドユーザにアバターアイテムを付与する権限です。
アバターを着せ替える権限 Fitting アプリのアバターを着せ替える権限です。着せ替えAPIを利用するために必要になります。

codeChallenge の生成

codeChallenge は、以下のパラメータを連結した文字列から作られるハッシュ値です。

パラメータ 説明 サンプル値
appId アプリID。自社アプリに割り振られたIDです。コンソールの「アプリ > アプリの設定」から確認できます。 1234567890
responseType レスポンスタイプ。「grant_token」という文字で固定です。 grant_token
redirectUri 前述の redirectUri と同じ値です。 https://example.com/callback
scope 前述の scope と同じ値です。 AvatarLoad,GrantItem
requestDate リクエスト時のUnixタイムスタンプ(秒)です。ユーザと紐付けてサーバ側に一時的に保持しておきます。後述の AccessToken API で必要になります。 1552893948
apiKey APIキーを指定します。 abcdefghi...
codeVerifier コード検証用の乱数です。48文字以上のランダム文字列を生成し、ユーザと紐付けてサーバ側に一時的に保持しておきます。後述の AccessToken API へのリクエストで必要になります。 qwertyuio...

これらの値を、半角コロン「:」区切りで上述の順に連結し、SHA256でハッシュ化します。

$ APP_ID={アプリID}
$ RESPONSE_TYPE=grant_token
$ REDIRECT_URI=https://example.com/callback
$ SCOPE=AvatarLoad,ItemGrant
$ REQUEST_DATE=`date +%s`
$ API_KEY={APIキー}

# codeVerifier
$ CODE_VERIFIER=`cat /dev/urandom | base64 | fold -w 48 | head -n 1`

# codeChallenge
$ CODE_CHALLENGE=`echo -n "$APP_ID:$RESPONSE_TYPE:$REDIRECT_URI:$SCOPE:$REQUEST_DATE:$API_KEY:$CODE_VERIFIER" | shasum -a 256 | cut -d' ' -f 1`
appID := "{アプリID}"
responseType := "grant_token"
redirectURI := "https://example.com/callback"
scope := "AvatarLoad,ItemGrant"
requestDate := time.Now().Unix()
apiKey := "{APIキー}"

// codeVerifier
codeVerifierBytes := make([]byte, 48)
if _, err := io.ReadFull(rand.Reader, codeVerifierBytes); err != nil {
    log.Fatal("code verifier generate failed")
    return err
}
codeVerifier = hex.EncodeToString(codeVerifierBytes)

// リダイレクトURI、スコープ、リクエスト日時、codeVerifier はユーザーと紐付けてキャッシュなどに保存しておく

// codeChallenge
codeChallenge := fmt.Sprintf(
    "%s:%s:%s:%s:%d:%s:%s",
    appID,
    responseType,
    redirectURI,
    scope,
    requestDate,
    apiKey,
    codeVerifier,
)
codeChallenge = fmt.Sprintf("%x", sha256.Sum256([]byte(codeChallenge)))
String appId = "{アプリID}";
String responseType = "grant_token";
String redirectUri = "https://example.com/callback";
String scope = "AvatarLoad,ItemGrant";
String requestDate = System.currentTimeMillis() / 1000L;
String apiKey = "{APIキー}";

// codeVerifier
StringBuffer sbCodeVerifier = new StringBuffer();
String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
for (int i = 0; i < 48; i++) {
    sbCodeVerifier.append(alphabet.charAt((int)(alphabet.length()*Math.random())));
}
codeVerifier = sbCodeVerifier.toString();

// リダイレクトURI、スコープ、リクエスト日時、codeVerifier はユーザーと紐付けてキャッシュなどに保存しておく

// codeChallenge
String codeChallenge = String.format(
    "%s:%s:%s:%s:%d:%s:%s",
    appId,
    responseType,
    redirectUri,
    scope,
    requestDate,
    apiKey,
    codeVerifier
);

MessageDigest sha256;
try {
    sha256 = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
    throw new ServletException(e);
}
codeChallenge = String.format("%040x", new BigInteger(1, sha256.digest(codeChallenge.getBytes())));

接続用エンドポイントのサンプル

次のようなURLになります。

https://fit.avatarplay3d.com/connect?appId=1234567890&redirectUri=https%3A%2F%2Fexample.com%2Fcallback&scope=AvatarLoad%2CItemGrant&codeChallenge=1147b6f3955a27a45fb731c24dcc73e68fa2d597d8c8c172fd4ddeb8fc5afa52&avatarId=1234567890

リダイレクトURIをハンドリングし、接続を完了する

ユーザは着せ替えアプリをインストールし、自社アプリでの利用許諾に同意した後、redirectUri へ遷移します。自社アプリ側では redirectUri に付与された「token」パラメータを取得し、redirectUri, scope, requestDate, codeVerifier と一緒に AccessToken API へ引き渡してアバターIDを取得します。

プラットフォーム別のハンドリング実装方法

カスタムURLスキームなどを使った、一般的な手法でハンドリングを実装します。

ウェブの場合

ウェブアプリケーションの場合、redirectUri に指定したURLをユーザから直接受信して「token」パラメータを取得します。

Androidアプリの場合

Android アプリケーションの場合、マニフェストにディープリンクまたはアプリリンクを定義し、そのリンクを redirectUri に指定します。redirectUri をアプリで受信した後は、インテントからデータを読み取り、「token」パラメータを取得します。

iOSアプリの場合

iOS アプリケーションの場合、カスタムURLスキームまたはユニバーサルリンクを設定し、そのリンクを redirectUri に指定します。 redirectUri をアプリで受信した後は、それぞれのハンドリング実装で「token」パラメータを取得します。

Unityアプリの場合

Unity アプリケーションの場合はプラットフォーム別のプラグインを実装することになります。Unity SDK にサンプル実装が同梱しています。

AccessToken API の呼び出し

Access Token API を呼び出し、接続を完了させます。API の利用方法については、RESTful API の概要を参照ください。

$ TOKEN={デコードされたtokenパラメータの値}
$ ENC_TOKEN=`ruby -r cgi -e "puts CGI.escape(\"$TOKEN\")"`
$ ENC_CODE_VERIFIER=`ruby -r cgi -e "puts CGI.escape(\"$CODE_VERIFIER\")"`
$ URL="https://api.avatarplay3d.com/v1/AccessToken?key=$API_KEY"
$ BODY="redirectUri=$ENC_REDIRECT_URI&scope=$ENC_SCOPE&requestDate=$REQUEST_DATE&codeVerifier=$ENC_CODE_VERIFIER&token=$ENC_TOKEN"
$ curl -X POST -H "Authorization: Bearer $JWT" $URL -d '$BODY'
{
 "avatarId": "1234567890",
 "accessToken": "affs3mqcdwqtlrjahxe6hy0cic6g0xfdwqi4hsnkq487i73o",
 "scope": "AvatarLoad,GrantItem",
 "tokenType": "Bearer"
}
func callback(w http.ResponseWriter, r *http.Request) {
    // 渡されたトークン
    token := r.URL.Query().Get("token")

    // リクエストURL
    requestURL := fmt.Sprintf("https://api.avatarplay3d.com/v1/AccessToken?key=%s", "{APIキー}")

    // リクエストボディ
    requestParams := url.Values{}
    requestParams.Add("token", token)
    requestParams.Add("redirectUri", redirectURI)
    requestParams.Add("scope", scope)
    requestParams.Add("requestDate", strconv.FormatInt(requestDate, 10))
    requestParams.Add("codeVerifier", codeVerifier)
    requestBody := strings.NewReader(requestParams.Encode())

    // リクエスト
    req, err := http.NewRequest(http.MethodPost, requestURL, requestBody)
    if err != nil {
        http.Error(w, "new request failed", http.StatusInternalServerError)
        return
    }

    // URLエンコードを指定する
    req.Header.Add("content-type", "application/x-www-form-urlencoded")

    // JWTを設定。JWTの生成方法は RESTful API の概要ページを参照。
    req.Header.Add("Authorization", "Bearer "+jwt)

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        http.Error(w, "api failed", http.StatusInternalServerError)
        return
    }

    // レスポンスボディ(JSON)をパース
    apiResponse := struct {
        AvatarID json.Number `json:"avatarId"`
    }{}
    if err := json.NewDecoder(res.Body).Decode(&apiResponse); err != nil {
        log.Printf("decode failed: %+v", err)
        http.Error(w, "decode failed", http.StatusInternalServerError)
        return
    }

    // 得られたアバターIDと自社アプリのユーザを紐付ける
    avatarID, _ = apiResponse.AvatarID.Int64()
}
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        // 渡されたトークン
        String token = request.getParameter("token");

        // リクエストURL
        String requestUrl = String.format("https://api.avatarplay3d.com/v1/AccessToken?key=%s", "{APIキー}");

        // リクエストボディ
        String requestBody = String.format(
                "token=%s&redirectUri=%s&scope=%s&requestDate=%d&codeVerifier=%s",
                URLEncoder.encode(token, "UTF-8"),
                URLEncoder.encode(redirectUri, "UTF-8"),
                URLEncoder.encode(scope, "UTF-8"),
                requestDate,
                codeVerifier);

        String res;
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(requestUrl).openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);

            // URLエンコードを指定する
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            // JWTを設定。JWTの生成方法は RESTful API の概要ページを参照。
            conn.setRequestProperty("Authorization", "Bearer " + jwt);

            // ボディ
            OutputStreamWriter writer = null;
            try {
                writer = new OutputStreamWriter(new BufferedOutputStream(conn.getOutputStream()));
                writer.write(requestBody);
            } finally {
                if (writer != null) {
                    writer.close();
                }
            }

            // リクエスト
            StringBuffer sb = new StringBuffer();
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                  sb.append(line);
                }
            } finally {
                if (reader != null) {
                    reader.close();
                }
            }

            res = sb.toString();
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }

        // 得られたアバターIDと自社アプリのユーザを紐付ける
        JSONObject o = new JSONObject(res);
        avatarId = o.getLong("avatarId");
    }

Info

ゲストユーザからのアップグレードの場合は、さらにゲストユーザのアバターIDを avatarId パラメータに指定します。

ここで得られる「avatarId」の値が連携済みユーザのアバターIDとなるため、自社アプリのユーザと紐づけ、以降ユーザのアバターIDとして利用します。RESTful API のみを利用する場合、アクセストークンは必要ありません。サーバ側で一時的に保持していた requestDate, codeVerifier は破棄します。

接続完了後の着せ替えアプリの起動

UI Kit をご利用の方

UI Kit の着せ替え画面を利用する場合、本項目は読み飛ばして下さい。UI Kit の着せ替え画面呼び出し時に、着せ替えアプリが自動起動します。

連携済みユーザに対しては、単純に着せ替えアプリを起動するエンドポイントへ誘導して下さい。

エンドポイント

URL

https://fit.avatarplay3d.com/launch

パラメータ

パラメータ名 説明 サンプル値
appId アプリID 1234567890

サンプル

https://fit.avatarplay3d.com/launch?appId=1234567890

ユーザステータスの判別

ユーザのステータスは、Avatar API から取得できます。毎度のAPI接続を回避する場合、アバターIDの紐づけ方で説明した紐付けテーブルに、ユーザステータスの列を加え、その値を参照するようにします。通常は、ゲストユーザかどうかを示す boolean 型のカラムを追加し、ゲストユーザの場合は false、連携済みユーザに切り替わったタイミングで true に更新します。

着せ替えアプリから戻った後のアバター再ロード

着せ替えアプリから自社アプリへ戻った際は、アバターが更新されている可能性があるため、再ロードすることが好ましいです。

// ウェブアプリケーション(JavaScript)の場合、タブのコンテンツが表示状態になったときに
// 発生するイベント visibilitychange をハンドリングして再ロードできます。
document.addEventListener("visibilitychange", function() {
    if (document.visibilityState == "visible") {
        window.location.reload();
    }
});
// Unity(C#)の場合、アプリがフォアグラウンドに復帰したときに
// 発生するイベント OnApplicationPause をハンドリングして再ロードできます。
void OnApplicationPause(bool pauseStatus)
{
    if (!pauseStatus)
    {
        StartCoroutine(InitializeSDKAndLoadAvatar());
    }
}

着せ替えアプリとの接続が解除された場合

エンドユーザは、ウェブ版の Avatar Play へサインインし、連携アプリ一覧から連携を解除できます(解除時の影響は後述)。自社アプリ側では、連携を解除した場合に再連携する手段を提供しておく必要があります。UI Kit、Unity SDK を利用している場合は自動で再連携が開始されますが、それ以外では連携用のリンクを自社アプリ側に入れておく必要があります。

再連携が実行された後も、同じアカウントで Avatar Play へサインインした場合はアバターIDは同じ値が返ります。

連携解除による影響

連携が解除されると、自社アプリから該当ユーザのアバター情報を取得できなくなり、具体的には次のような挙動となります。

  • RESTful API の場合、レスポンスコードが 401 を返すようになります
  • UI Kit の場合、ほとんどの機能が 401 エラーとなり使えなくなりますが、着せ替え画面へアクセスすると connectUrl を使って再連携が開始されるようになっています
  • Webhook は呼び出されなくなります
  • Unity SDK の場合、InitializeAsync の呼び出しのタイミングでゲストユーザに切り替わります

テスト方法

再連携をテストするには、ウェブ版の Avatar Play にサインインし、「連携アプリ一覧」ページからアプリとの連携を解除します。その後、自社アプリから再連携できることを確認します。

ユーザのアップグレードについて

自社アプリ側でゲストユーザを作成し、その後着せ替えアプリと接続して連携済みユーザになることを、アップグレードと呼びます。アップグレード時には、ゲストユーザの所持アイテムが連携済みユーザに引き継がれます。連携済みユーザは、Avatar Play で認証済みのユーザとして扱われ、アバターと所持アイテムをアプリ間で共有して利用できるようになります。

アップグレード済みのゲストユーザの扱い

連携処理が最終工程で失敗するケースを考慮し、アップグレード後もゲストユーザのアバターIDは利用可能にしています。ただし、アイテムを付与することはできません(アイテム付与APIを呼び出してもエラーが返ります)。連携処理の失敗を検知した後は、速やかに再度連携するようユーザーに促してください。

UI Kit をご利用の方

UI Kit 着せ替え画面を利用している場合、UI Kit の画面内で再連携へ誘導されます。

1ユーザの1アプリに対するアップグレード回数制限

アップグレード時にゲストユーザの所持アイテムを引き継げる仕様であるため、アプリのインストール・アンインストールを繰り返すことで、ゲストユーザ時に得たアイテムを一つの連携済みユーザに集約できてしまいます。一方で、アップグレードを1ユーザ1度きりに限定してしまうと、何らかしらの理由で前のユーザにログインできなくなり新規登録から始めることになった際に、前のアバターに復帰できなくなるリスクがあります。

この問題に対処するために、1ユーザの1アプリに対するアップグレード回数を制限することを可能にしています。デフォルトでは10が設定されていますが、アプリ毎に変更可能です。


最終更新日: 2023-10-27