UnityCloudBuildからAppCenterへipaをアップロード

2022/12/16 : 初稿
Unity : 2021.3.15f1

UnityCloudBuildの仕様がしれっと変わった模様です。
- 出力ipaファイル名がbuild.ipaから[ターゲット名].ipaに
- 出力ipaファイル名においてターゲット名にスペースがある場合はアンダースコアに
- build_manifest.jsonのbuildNumberが文字列から数値型に

ビルド成功したのにインストールボタン押しても反応がなくなったとか、
ビルド番号が取れなくなった、とかはこの辺りが原因と思われます。

これらに対応した
ビルド後のipaファイルをAppCenterにアップロードする
PostBuild.shを作りました。
なお、shの文法詳しくないので色々スマートではないですがご容赦を。

以下は、AppCenterでの登録内容を入れてください。
- APP_NAME
- OWNER_NAME
- DISTRIBUTION_GROUP

```sh
#!/bin/bash

echo *
pwd
cat ./build_manifest.json

# Environment Variables created by App Center
# $APPCENTER_SOURCE_DIRECTORY
# $APPCENTER_OUTPUT_DIRECTORY
# $APPCENTER_BRANCH

# Custom Environment Variables set in Build configuration
API_TOKEN='XXXXXXXXXXXXXXXXXXXXXXX'
APP_PACKAGE=(`echo "$2/*.ipa"`)
echo "APP_PACKAGE: $APP_PACKAGE"
APP_NAME='XXXXX'　
OWNER_NAME='xxxxxx@xxxxxxxxx'
TEAM_APP="${OWNER_NAME}/${APP_NAME}"
CONTENT_TYPE='application/octet-stream'
#   Android: "application/vnd.android.package-archive"
#   iOS: "application/octet-stream"
DISTRIBUTION_GROUP='Collaborators'

# Vars to simplify frequently used syntax
UPLOAD_DOMAIN="https://file.appcenter.ms/upload"
API_URL="https://api.appcenter.ms/v0.1/apps/$TEAM_APP"
AUTH="X-API-Token: $API_TOKEN"
ACCEPT_JSON="Accept: application/json"

# Body - Step 1/7
echo 'Creating release (1/7)'
request_url="$API_URL/uploads/releases"
upload_json=$(curl -s -X POST -H "Content-Type: application/json" -H "$ACCEPT_JSON" -H "$AUTH" "$request_url")

releases_id=$(echo $upload_json | jq -r '.id')
package_asset_id=$(echo $upload_json | jq -r '.package_asset_id')
url_encoded_token=$(echo $upload_json | jq -r '.url_encoded_token')

file_name=$(basename "$APP_PACKAGE" | sed 's/ /%20/g')
app_package_escaped=$( echo "$APP_PACKAGE" | sed 's/ /\\ /g' )
file_size=$(eval wc -c "$app_package_escaped" | awk '{print $1}')
echo "fileName: $file_name"
echo "fileSize: $file_size"

# Step 2/7
echo 'Creating metadata (2/7)'
metadata_url="$UPLOAD_DOMAIN/set_metadata/$package_asset_id?file_name=$file_name&file_size=$file_size&token=$url_encoded_token&content_type=$CONTENT_TYPE"

meta_response=$(curl -s -d POST -H "Content-Type: application/json" -H "$ACCEPT_JSON" -H "$AUTH" "$metadata_url")
chunk_size=$(echo $meta_response | jq -r '.chunk_size')

echo $meta_response
echo $chunk_size

mkdir ./tmp
cd ./tmp
split -b $chunk_size -a 3 "$APP_PACKAGE" tmp_
cd ..
echo 'ls..'
echo "$(ls -lf ./tmp/)"
echo 'ls..done'

# Step 3/7
echo 'Uploading chunked binary (3/7)'
binary_upload_url="$UPLOAD_DOMAIN/upload_chunk/$package_asset_id?token=$url_encoded_token"

block_number=1
for i in ./tmp/*
do
    echo "start uploading chunk $i"
    url="$binary_upload_url&block_number=$block_number"
    size=$(wc -c $i | awk '{print $1}')
    curl -X POST $url --data-binary "@$i" -H "Content-Length: $size" -H "Content-Type: $CONTENT_TYPE"
    block_number=$(($block_number + 1))
    printf "\n"
done

# Step 4/7
echo 'Finalising upload (4/7)'
finish_url="$UPLOAD_DOMAIN/finished/$package_asset_id?token=$url_encoded_token"
curl -d POST -H "Content-Type: application/json" -H "$ACCEPT_JSON" -H "$AUTH" "$finish_url"

# Step 5/7
echo 'Commit release (5/7)'
commit_url="$API_URL/uploads/releases/$releases_id"
curl -H "Content-Type: application/json" -H "$ACCEPT_JSON" -H "$AUTH" --data '{"upload_status": "uploadFinished","id": "$releases_id"}' -X PATCH $commit_url

# Step 6/7
echo 'Polling for release id (6/7)'
release_id=null
counter=0
max_poll_attempts=100

while [[ $release_id == null && ($counter -lt $max_poll_attempts)]]
do
    poll_result=$(curl -s -H "Content-Type: application/json" -H "$ACCEPT_JSON" -H "$AUTH" $commit_url)
    release_id=$(echo $poll_result | jq -r '.release_distinct_id')
    echo $counter $release_id
    counter=$((counter + 1))
    sleep 3
done

if [[ $release_id == null ]];
then
    echo "Failed to find release from appcenter"
    exit 1
fi

# Step 7/7
echo 'Applying destination to release (7/7)'
build_number=$(awk -F\" -v RS=, '/"buildNumber"/{print $3}' build_manifest.json | sed 's/: //g')
version_number=`awk -F: '/bundleVersion/{print $2}' ProjectSettings/ProjectSettings.asset | sed -e "s/ //g"`
commit_id=`awk -F\" '/"scmCommitId"/{print $4}' build_manifest.json`
comment=`git show ${commit_id} --no-patch --pretty=%B`
release_notes="[$build_number] $comment"
echo $comment
distribute_url="$API_URL/releases/$release_id"
curl -H "Content-Type: application/json" -H "$ACCEPT_JSON" -H "$AUTH" --data '{"destinations": [{ "name":"'"$DISTRIBUTION_GROUP"'"}],"release_notes":"'"$release_notes"'"}' -X PATCH $distribute_url

echo https://appcenter.ms/orgs/$OWNER_NAME/apps/$APP_NAME/distribute/releases/$release_id
```

ついでに備忘録ですが、メソッド呼び出しのサンプルを置いておきます。

```cs
///
/// @file   CloudBuild.cs
/// @author KYukimoto
/// @date   
///
/// @brief　CloudBuildからの呼び出し
///
#if UNITY_CLOUD_BUILD
using UnityEditor;
using UnityEngine;
using UnityEditor.iOS.Xcode;
using UnityEditor.Callbacks;
using System.IO;

namespace Utils
{
    public class CloudBuild
    {
        public static void PreExport(UnityEngine.CloudBuild.BuildManifestObject manifest)
        {
            string buildNumber = manifest.GetValue<int>("buildNumber").ToString();
            Debug.Log("BuildNumber: " + buildNumber);
            var path = "Assets/Wander/BuildNumber.txt";
            System.IO.File.WriteAllText(path, buildNumber);
            AssetDatabase.ImportAsset(path);
        }
        public static void PostExport(string exportPath)
        {
#if UNITY_IOS
            // UniWebView4がbitcodeに使っているXcodeのバージョンが現状UCBが対応している最新のXcodeより新しいので一時的にbitcodeコンパイルを無効化する
            // UCBのXcodeが13.4.1に対応したらここは外すこと。
            var projectPath = PBXProject.GetPBXProjectPath(exportPath);
            var content = File.ReadAllText(@projectPath);
            content = content.Replace("ENABLE_BITCODE = YES", "ENABLE_BITCODE = NO");
            File.WriteAllText(projectPath, content);
#endif
        }
    }
}
#endif
```