コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【Unity】An attribute list cannot appear here

概要

An attribute list cannot appear here

Firestore 9.6.0 を使用している Unity プロジェクトを
Xcode 15 でビルドしようとしたら上記のエラーが発生した

解決方法

Firestore を 10.0.0 以上にアップデートする

アップデート可能であればアップデートすることで解決可能

Firestore の「FIRFirestoreSettings.mm」を書き換える

アップデートが難しければ Xcode プロジェクトで「FIRFirestoreSettings.mm」を開いて

ABSL_CONST_INIT extern "C" const int64_t kFIRFirestoreCacheSizeUnlimited =

この行を

extern "C" const int64_t kFIRFirestoreCacheSizeUnlimited =

このように書き換える(ABSL_CONST_INIT を削除する)ことでも解決可能

Unity でビルドする時に自動で書き換えたい場合は以下のようなスクリプトを作成する

using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;

namespace Kogane.Internal
{
    /// <summary>
    /// Xcode 15 でビルドできるように iOS ビルド時に「FIRFirestoreSettings.mm」を自動で書き換えるエディタ拡張
    /// 参考サイト様:https://github.com/firebase/firebase-ios-sdk/issues/11840#issuecomment-1738875602
    /// </summary>
    // ReSharper disable once InconsistentNaming
    internal static class FixFIRFirestoreSettings_mm_OnPostProcessBuild
    {
        //================================================================================
        // 関数(static)
        //================================================================================
        /// <summary>
        /// ビルド完了時に呼び出されます
        /// </summary>
        [PostProcessBuild( 55 )] // この値を変えると動かなくなる可能性があるので注意
        private static void OnPostProcessBuild
        (
            BuildTarget buildTarget,
            string      pathToBuiltProject
        )
        {
            if ( buildTarget != BuildTarget.iOS ) return;

            var path = Path.Combine
            (
                pathToBuiltProject,
                "Pods/FirebaseFirestore/Firestore/Source/API/FIRFirestoreSettings.mm"
            );

            // UnauthorizedAccessException が出るため一時的に読み取り専用を解除する
            var fileInfo = new FileInfo( path )
            {
                IsReadOnly = false,
            };

            try
            {
                var contents = File
                        .ReadAllText( path )
                        .Replace
                        (
                            @"ABSL_CONST_INIT extern ""C"" const int64_t kFIRFirestoreCacheSizeUnlimited =",
                            @"extern ""C"" const int64_t kFIRFirestoreCacheSizeUnlimited ="
                        )
                    ;

                File.WriteAllText( path, contents );
            }
            finally
            {
                fileInfo.IsReadOnly = true;
            }
        }
    }
}

参考サイト様