灵光系统 临时记录_第二章.md 32 KB

FirebaseCloudMessage.cs

using System;
using Firebase.Extensions;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Firebase;
using UnityEngine;
using UnityEngine.Networking;
using Newtonsoft.Json;
using UnityEngine.Android;
using Firebase.Extensions;

/// <summary>
/// FCM推送插件 & 灵光系统
/// </summary>
public class FirebaseCloudMessage : MonoBehaviour
{

    private static string firebaseMessageReportUrl = String.Empty; //灵光平台 上报地址
    private static string firebaseMessageNotificationUrl = String.Empty; //灵光平台 触达率 上报地址
    
    private static string _android_channel; //安卓渠道号(和服务端确认即可)
    private static string _ios_channel; //ios渠道号(和服务端确认即可)
    private static string _language; //语言
    private static string _country; //国家
    private static string fcmToken = String.Empty; //token of fcm令牌
    
    private static GameObject firebaseMessageUtilGameObject;
    private static string userID; //玩家ID
    private static bool inited = false; //是否初始化完成

    private static string _platform; //移动平台
    private static string _channel; //渠道号

    private static bool isFirebaseEnable = false; //判断firebase依赖是否正常,云推送后是否可用

    // private static FirebaseApp app;

    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="appID">应用代号</param>
    /// <param name="ReportUrl">上报地址</param>
    /// <param name="android_channel">安卓渠道</param>
    /// <param name="ios_channel">ios渠道</param>
    /// <param name="language">语言</param>
    /// <param name="country">国家</param>
    public static void Init(string appID,string ReportUrl,string android_channel = "2001",string ios_channel = "1001",string language = "en",string country = "US")
    {
        Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => {
            var dependencyStatus = task.Result;
            if (dependencyStatus == Firebase.DependencyStatus.Available) {
                // Create and hold a reference to your FirebaseApp,
                // where app is a Firebase.FirebaseApp property of your application class.
                // app = Firebase.FirebaseApp.DefaultInstance;
                firebaseMessageReportUrl = $"{ReportUrl}/api/app/{appID}/user/update";
                firebaseMessageNotificationUrl = $"{ReportUrl}/api/app/{appID}/user/click";
                _android_channel = android_channel;
                _ios_channel = ios_channel;
                _language = language;
                _country = country;
        
                RequestNotificationPermission();
                isFirebaseEnable = true;

                // 如果已经有userID,立即初始化Firebase
                if (!string.IsNullOrEmpty(userID))
                {
                    GetInstance().InitializeFirebase();
                }

                // Set a flag here to indicate whether Firebase is ready to use by your app.
            } 
            else {
                Debug.Log("当前设备 谷歌框架等依赖缺失 不支持Firebase");
                isFirebaseEnable = false;
                // UnityEngine.Debug.LogError(System.String.Format(
                //     "Could not resolve all Firebase dependencies: {0}", dependencyStatus));
                // Firebase Unity SDK is not safe to use here.
            }
        });
    }

    /// <summary>
    /// 设置玩家ID
    /// </summary>w
    /// <param name="userid"></param>
    public static void SetUserID(string userid)
    {
#if Firebase_Debug
        Debug.Log($"Firebase 功能测试 设置玩家ID{userid}");
#endif
        userID = userid;
        
#if !UNITY_EDITOR
        // 如果Firebase可用,直接初始化;如果不可用,等依赖检查完成后再初始化
        // 如果Firebase还没初始化完成,userID已经缓存了,等Init完成后再调用InitializeFirebase
        if (isFirebaseEnable)
        {
            GetInstance().InitializeFirebase();
            
            if (!String.IsNullOrEmpty(fcmToken) && !String.IsNullOrEmpty(userID))
            {
                PostToServer();
            }
        }
#endif
    }
    /// <summary>
    /// 订阅消息主题,订阅成功后可以通过主题推送
    /// </summary>
    /// <param name="topic"></param>
    public static void SubscribeTopic(string topicJsonStr)
    {
        if (!isFirebaseEnable)
        {
            return;
        }
        
        if (String.IsNullOrEmpty(fcmToken))
        {
            Debug.LogError("灵光系统 无法获得fcm token令牌");
            return;
        }

        //检测json键值合法性
        Dictionary<string, string> paramsMap = JsonConvert.DeserializeObject<Dictionary<string, string>>(topicJsonStr);
        var (isValid, error) = CheckJsonDataValid(paramsMap);
        if (!isValid)
        {
            Debug.LogWarning($"Failed to subscribe to the topic: {error}");
            return;
        }

        foreach (string key in paramsMap.Keys)
        {
            Firebase.Messaging.FirebaseMessaging.SubscribeAsync(paramsMap[key]).ContinueWithOnMainThread(task =>
            {
                if (task.IsFaulted)
                    Debug.LogWarning($"Failed to subscribe to the topic: {task.Exception}");
            });
        }
    }

    /// <summary>
    /// 取消订阅消息主题
    /// </summary>
    /// <param name="topicJsonStr"></param>
    public static void unSubscribeTopic(string topicJsonStr)
    {
        if (!isFirebaseEnable)
        {
            return;
        }
        
        if (String.IsNullOrEmpty(fcmToken))
        {
            Debug.LogError("灵光系统 无法获得fcm token令牌");
            return;
        }

        //检测json键值合法性
        Dictionary<string, string> paramsMap = JsonConvert.DeserializeObject<Dictionary<string, string>>(topicJsonStr);
        var (isValid, error) = CheckJsonDataValid(paramsMap);
        if (!isValid)
        {
            Debug.LogWarning($"Failed to subscribe to the topic: {error}");
            return;
        }

        foreach (string key in paramsMap.Keys)
        {
            Firebase.Messaging.FirebaseMessaging.UnsubscribeAsync(paramsMap[key]).ContinueWithOnMainThread(task =>
            {
                if (task.IsFaulted)
                    Debug.LogWarning($"Failed to subscribe to the topic: {task.Exception}");
            });
        }
    }

    private void OnDestroy()
    {
        RemoveFirebase();
    }
    
    /// <summary>
    /// 获取单例实例
    /// </summary>
    private static FirebaseCloudMessage GetInstance()
    {
        if (firebaseMessageUtilGameObject == null)
        {
            firebaseMessageUtilGameObject = new GameObject();
            DontDestroyOnLoad(firebaseMessageUtilGameObject);
            firebaseMessageUtilGameObject.name = "firebaseMessage";
            firebaseMessageUtilGameObject.AddComponent<FirebaseCloudMessage>();
        }
        return firebaseMessageUtilGameObject.GetComponent<FirebaseCloudMessage>();
    }

    /// <summary>
    /// 初始化FirebaseCloudMessage消息推送
    /// </summary>
    private void InitializeFirebase()
    {
        if (!isFirebaseEnable)
        {
            return;
        }
        
        // 避免重复初始化
        if (inited)
        {
            return;
        }
        
        // 检查是否有userID,没有的话等待SetUserID调用
        if (string.IsNullOrEmpty(userID))
        {
            Debug.Log("等待userID设置后再初始化Firebase");
            return;
        }
        
        inited = true;
        
        Firebase.Messaging.FirebaseMessaging.MessageReceived += OnMessageReceived;
        Firebase.Messaging.FirebaseMessaging.TokenReceived += OnTokenReceived;
    }

    /// <summary>
    /// 移除FirebaseCloudMessage消息推送
    /// </summary>
    private void RemoveFirebase()
    {
        if (!isFirebaseEnable)
        {
            return;
        }
        
        Firebase.Messaging.FirebaseMessaging.MessageReceived -= OnMessageReceived;
        Firebase.Messaging.FirebaseMessaging.TokenReceived -= OnTokenReceived;
        inited = false;
    }
    
    private void OnMessageReceived(object sender, Firebase.Messaging.MessageReceivedEventArgs e)
    {
        Dictionary<string, object> args = new Dictionary<string, object>();
        // args.Add(NativeEventConst.EVENT_ID_KEY, NativeEventConst.FIREBASE_MESSAGE_RECEIVED);
        //
        var notification = e.Message.Notification;
        if (notification != null)
        {
            args.Add("title", notification.Title);
            args.Add("body", notification.Body);
        
#if !UNITY_EDITOR && UNITY_ANDROID
            var android = notification.Android;
            if (android != null)
            {
                args.Add("android channel_id", android.ChannelId);
            }
#endif
        }

        if (e.Message.From.Length > 0)
        {
            args.Add("from", e.Message.From);
        }
        
        if (e.Message.Link != null)
        {
            args.Add("link", e.Message.Link.ToString());
        }
        
        if (e.Message.Data.Count > 0)
        {
            foreach (KeyValuePair<string, string> item in e.Message.Data)
            {
                args.Add(item.Key, item.Value);
            }
        }
        
        //消息中获取traceId 发送给服务端 触达率
        if (e.Message.Data.Count > 0)
        {
            foreach (KeyValuePair<string, string> item in e.Message.Data)
            {
                if (item.Key.Equals("traceId"))
                {
                    string traceId = item.Value;
#if Firebase_Debug
                    Debug.Log($"Firebase 功能测试 触达率id:{traceId}");
#endif

                    // Debug.Log("OnMessageReceived traceId:" + traceId);
                    CoroutineManager.Instance.StartManagedCoroutine(NotificationPostRequest(firebaseMessageNotificationUrl, traceId));
                    
                }
            }
        }
        
    }

    private void OnTokenReceived(object sender, Firebase.Messaging.TokenReceivedEventArgs token)
    {
        fcmToken = token.Token;
        
        // 获取到token后,立即发送给服务器(此时已经有用户ID了)
        PostToServer();
    }


    /// <summary>
    /// 发送给灵光服务器
    /// </summary>
    private static void PostToServer()
    {
        SetPlatform();
        var deviceData = new
        {
            token = fcmToken,
            platform = _platform,
            channel = _channel,
            device = SystemInfo.deviceUniqueIdentifier,
            uid = userID,
            language = _language,
            country = _country,
        };

        string jsonString = JsonConvert.SerializeObject(deviceData);
        CoroutineManager.Instance.StartManagedCoroutine(PostRequest(firebaseMessageReportUrl, jsonString));
    }

    /// <summary>
    /// 设置 移动平台 & 渠道号相关(渠道号和服务端确认即可)
    /// </summary>
    private static void SetPlatform()
    {
        switch (Application.platform)
        {
            case RuntimePlatform.Android:
                _platform = "android";
                _channel = _android_channel;
                break;
            case RuntimePlatform.IPhonePlayer:
                _platform = "ios";
                _channel = _ios_channel;
                break;
        }
    }

    /// <summary>
    /// 检测json合法性
    /// </summary>
    /// <param name="jsonStr"></param>
    /// <returns></returns>
    private static (bool isValid, string error) CheckJsonDataValid<TKey, TValue>(Dictionary<TKey, TValue> jsonMap)
    {
        if (jsonMap == null)
            return (false, "The dictionary object is null");

        var emptyItems = jsonMap
            .Where(kv => IsInvalidValue(kv.Value))
            .Select(kv => kv.Key.ToString())
            .ToList();

        return emptyItems.Count == 0
            ? (true, null)
            : (false, $"The following key values are empty: {string.Join(", ", emptyItems)}");
    }

    private static bool IsInvalidValue<T>(T value)
    {
        if (value == null) return true;
        if (value is string str) return string.IsNullOrEmpty(str);
        return false;
    }
    
    
    /// <summary>
    /// 主动申请通知权限
    /// </summary>
    private static void RequestNotificationPermission()
    {
#if !UNITY_EDITOR
#if UNITY_ANDROID
        // 检查Android版本
        if (GetAndroidVersion() >= 33) // Android 13+
        {
            // 检查是否已经有通知权限
            if (!CheckNotificationPermissionStatus())
            {
                Debug.Log("请求通知权限...");
                // 请求通知权限
                Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS");
                
                // 添加权限回调
                PermissionCallbacks callbacks = new PermissionCallbacks();
                callbacks.PermissionGranted += (permissionName) => {
                    Debug.Log($"通知权限已授予: {permissionName}");
                };
                callbacks.PermissionDenied += (permissionName) => {
                    Debug.LogWarning($"通知权限被拒绝: {permissionName}");
                };
                callbacks.PermissionDeniedAndDontAskAgain += (permissionName) => {
                    Debug.LogWarning($"通知权限被拒绝且不再询问: {permissionName}");
                };
                
                Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS", callbacks);
            }
            else
            {
                Debug.Log("已有通知权限");
            }
        }
        else
        {
            Debug.Log("Android版本低于13,无需申请通知权限");
        }
#elif UNITY_IOS
        // 使用iOSNotificationPermission类处理iOS通知权限
        if (!iOSNotificationPermission.CheckPermission())
        {
            Debug.Log("请求iOS通知权限...");
            iOSNotificationPermission.RequestPermission();
        }
        else
        {
            Debug.Log("已有iOS通知权限");
        }
#else
        Debug.Log("其他平台,无需申请通知权限");
#endif
#else
        Debug.Log("Unity编辑器模式,跳过通知权限申请");
#endif
    }
    
    /// <summary>
    /// 获取Android版本
    /// </summary>
    private static int GetAndroidVersion()
    {
#if !UNITY_EDITOR && UNITY_ANDROID
        try
        {
            using (AndroidJavaClass buildVersion = new AndroidJavaClass("android.os.Build$VERSION"))
            {
                return buildVersion.GetStatic<int>("SDK_INT");
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"获取Android版本失败: {e.Message}");
            return 0;
        }
#else
        return 0; // 非Android平台返回0
#endif
    }
    
    /// <summary>
    /// 检查通知权限状态
    /// </summary>
    private static bool CheckNotificationPermissionStatus()
    {
#if !UNITY_EDITOR && UNITY_ANDROID
        if (GetAndroidVersion() >= 33)
        {
            try
            {
                using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
                using (AndroidJavaObject context = currentActivity.Call<AndroidJavaObject>("getApplicationContext"))
                using (AndroidJavaClass notificationManager = new AndroidJavaClass("android.app.NotificationManager"))
                using (AndroidJavaObject notificationService = context.Call<AndroidJavaObject>("getSystemService", "notification"))
                {
                    // 直接调用areNotificationsEnabled方法,因为Android 13+肯定支持这个方法
                    return notificationService.Call<bool>("areNotificationsEnabled");
                }
            }
            catch (Exception e)
            {
                Debug.LogError($"检查通知权限状态失败: {e.Message}");
            }
        }
        return true; // 低版本默认返回true
#elif !UNITY_EDITOR && UNITY_IOS
        // 使用iOSNotificationPermission类检查iOS通知权限状态
        return iOSNotificationPermission.CheckPermission();
#else
        // Unity编辑器或其他平台,默认返回true
        return true;
#endif
    }
    
    [System.Serializable]
    private class PostResponse
    {
        public int code;
        public string message;
        public string data;
    }

    /// <summary>
    /// 上报灵光事件
    /// </summary>
    /// <param name="url"></param>
    /// <param name="jsonData"></param>
    /// <returns></returns>
    private static IEnumerator PostRequest(string url,string jsonData)
    {

#if Firebase_Debug
        Debug.Log($"Firebase 功能测试,发送链接:{url}");
        Debug.Log($"Firebase 功能测试,发送数据:{jsonData}");
#endif

        using (UnityWebRequest request = UnityWebRequest.PostWwwForm(url, "POST"))
        {
            byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonData);

            request.uploadHandler = new UploadHandlerRaw(bodyRaw);
            request.downloadHandler = new DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "application/json");

            yield return request.SendWebRequest();

            if (request.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError($"灵光系统 错误信息:{request.error}");
                yield break;
            }

            var response = JsonUtility.FromJson<PostResponse>(request.downloadHandler.text);
            if (response.code != 0)
            {
                Debug.LogError($"灵光系统 错误码:{response.code}");
            }
            else
            {
#if Firebase_Debug
                Debug.Log($"Firebase 功能测试,发送回包:{request.downloadHandler.text}");
#endif
            }
        };
    }
    
    private IEnumerator NotificationPostRequest(string url,string traceId)
    {
        using (UnityWebRequest request = UnityWebRequest.PostWwwForm(url, "POST"))
        {
            byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(traceId);

            request.uploadHandler = new UploadHandlerRaw(bodyRaw);
            request.downloadHandler = new DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "text/plain");
            
            yield return request.SendWebRequest();

            if (request.result != UnityWebRequest.Result.Success)
            {
                Debug.LogWarning("灵光系统 触达率 错误信息:" + request.error);
                yield break;
            }

            var response = JsonUtility.FromJson<PostResponse>(request.downloadHandler.text);
            if (response.code != 0)
            {
                Debug.LogWarning("灵光系统 触达率 错误码:" + response.code);
            }
        };
    }
}

NotificationServiceExtensionCreator.cs

#if UNITY_IOS
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using UnityEditor.iOS.Xcode.Extensions;
using UnityEngine;
using UnityEditor.iOS.Xcode.PBX;
using System.Diagnostics;
using System.Threading;
using System;
using System.Text.RegularExpressions;
using Debug = UnityEngine.Debug;

public static class FirebaseNotificationServiceExtensionCreator
{
    private const string ExtensionName = "FirebaseNotificationService";

    [PostProcessBuild(99999)]
    public static void OnPostProcessBuild(BuildTarget target, string buildPath)
    {
        if (target != BuildTarget.iOS) return;
#if Firebase_Debug
        Debug.Log("FireBase功能测试 开始创建 Firebase Notification Service Extension...");
#endif

        string projPath = PBXProject.GetPBXProjectPath(buildPath);
        PBXProject proj = new PBXProject();
        proj.ReadFromFile(projPath);

#if UNITY_2019_3_OR_NEWER
        string mainTargetGuid = proj.GetUnityMainTargetGuid();
#else
        string mainTargetGuid = proj.TargetGuidByName(PBXProject.GetUnityTargetName());
#endif
        
        // 1. 创建 Extension Target(这会自动创建基础文件)
        string extGuid = proj.AddAppExtension(mainTargetGuid, ExtensionName, ExtensionName, 
            $"{ExtensionName}/Info.plist");

#if Firebase_Debug
        Debug.Log($" FireBase功能测试 创建 Extension Target: {extGuid}");
#endif
        

        // 2. 配置基本设置
        proj.SetBuildProperty(extGuid, "PRODUCT_BUNDLE_IDENTIFIER", 
            PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.iOS) + "." + ExtensionName);
        proj.SetBuildProperty(extGuid, "ENABLE_BITCODE", "NO");
        proj.SetBuildProperty(extGuid, "IPHONEOS_DEPLOYMENT_TARGET", "15.0");

        // 3. 配置签名
        ConfigureCodeSigning(proj, extGuid);

        // 4. 移动预制的代码文件到扩展目录
        MovePrebuiltSourceFiles(buildPath);

        // 5. 添加系统框架
        proj.AddFrameworkToProject(extGuid, "UserNotifications.framework", false);

        // 6. 配置 Push Notifications 能力
        ConfigurePushNotificationsCapability(proj, extGuid, buildPath);

        // 7. 关键修复:确保文件被添加到 Xcode 项目结构和编译阶段
        AddFilesToProjectStructure(proj, extGuid, buildPath);

        // 8. 配置 Podfile
        ConfigureFirebasePodfile(buildPath);

        // 9. 保存工程
        proj.WriteToFile(projPath);
        AssetDatabase.Refresh();

        // 10. 执行 pod install
        PodInstallFirebaseNotificationService(buildPath);

    }

    // 关键方法:确保文件被添加到 Xcode 项目结构
    private static void AddFilesToProjectStructure(PBXProject proj, string extGuid, string buildPath)
    {
#if Firebase_Debug
        Debug.Log("FireBase功能测试 开始添加文件到 Xcode 项目结构...");
#endif
    
        // 1. 获取或创建 Sources Build Phase
        var buildPhaseID = proj.AddSourcesBuildPhase(extGuid);
#if Firebase_Debug
        Debug.Log($"FireBase功能测试 Sources Build Phase ID: {buildPhaseID}");
#endif

        // 2. 添加 .h 文件到项目结构
        string headerPath = Path.Combine(ExtensionName, "FirebaseNotificationService.h");
        string headerGuid = proj.AddFile(headerPath, headerPath, PBXSourceTree.Source);
        
#if Firebase_Debug
        Debug.Log($"FireBase功能测试 Header 文件添加到项目: {headerGuid}");
#endif
    
        // 3. 添加 .m 文件到项目结构
        string sourcePath = Path.Combine(ExtensionName, "FirebaseNotificationService.m");
        string sourceGuid = proj.AddFile(sourcePath, sourcePath, PBXSourceTree.Source);
      
#if Firebase_Debug
        Debug.Log($"FireBase功能测试 Source 文件添加到项目: {sourceGuid}");
#endif
    
        // 4. 将文件添加到编译阶段(确保 Target Membership 正确)
        proj.AddFileToBuildSection(extGuid, buildPhaseID, headerGuid);
        proj.AddFileToBuildSection(extGuid, buildPhaseID, sourceGuid);
        
#if Firebase_Debug
        Debug.Log($"FireBase功能测试 文件已添加到编译阶段");
#endif
    
        // 5. 确保 Info.plist 也被添加到项目
        string plistPath = Path.Combine(ExtensionName, "Info.plist");
        string plistGuid = proj.AddFile(plistPath, plistPath, PBXSourceTree.Source);
        
#if Firebase_Debug
        Debug.Log($"FireBase功能测试 Info.plist 添加到项目: {plistGuid}");
        Debug.Log("FireBase功能测试 🎯 所有文件已成功添加到 Xcode 项目结构!");
#endif
    
    }

    private static void ConfigureCodeSigning(PBXProject proj, string extGuid)
    {
        string teamId = PlayerSettings.iOS.appleDeveloperTeamID;
        if (!string.IsNullOrEmpty(teamId))
        {
            proj.SetBuildProperty(extGuid, "DEVELOPMENT_TEAM", teamId);
            proj.SetBuildProperty(extGuid, "CODE_SIGN_STYLE", "Automatic");
        }
    }

    private static void MovePrebuiltSourceFiles(string buildPath)
    {
        string extDir = Path.Combine(buildPath, ExtensionName);
        
        // 确保目录存在
        if (!Directory.Exists(extDir))
            Directory.CreateDirectory(extDir);

        // 源文件路径(Plugins/iOS 目录)
        string sourceDir = Path.Combine(Application.dataPath, "Plugins", "iOS");
        
        // 移动 .h 文件
        string headerSource = Path.Combine(sourceDir, "FirebaseNotificationService.h");
        string headerDest = Path.Combine(extDir, "FirebaseNotificationService.h");
        if (File.Exists(headerSource))
        {
            // 如果目标文件已存在,先删除
            if (File.Exists(headerDest))
            {
                File.Delete(headerDest);
                
#if Firebase_Debug
                Debug.Log("FireBase功能测试 删除已存在的目标文件: " + headerDest);
#endif
            }
            
            File.Copy(headerSource, headerDest);
            
#if Firebase_Debug
            Debug.Log("FireBase功能测试 复制 FirebaseNotificationService.h 文件");
#endif
            
        }
        else
        {
            Debug.LogError("❌ 找不到源文件: " + headerSource);
        }

        // 移动 .m 文件
        string sourceSource = Path.Combine(sourceDir, "FirebaseNotificationService.m");
        string sourceDest = Path.Combine(extDir, "FirebaseNotificationService.m");
        if (File.Exists(sourceSource))
        {
            // 如果目标文件已存在,先删除
            if (File.Exists(sourceDest))
            {
                File.Delete(sourceDest);
                
#if Firebase_Debug
                Debug.Log("FireBase功能测试️ 删除已存在的目标文件: " + sourceDest);
#endif
            }
            
            File.Copy(sourceSource, sourceDest);
           
#if Firebase_Debug
            Debug.Log("FireBase功能测试 复制 FirebaseNotificationService.m 文件");
#endif
            
        }
        else
        {
            Debug.LogError("❌ 找不到源文件: " + sourceSource);
        }

        // 创建 Info.plist(如果需要)
        string plistPath = Path.Combine(extDir, "Info.plist");
        if (!File.Exists(plistPath))
        {
            File.WriteAllText(plistPath, FirebaseInfoPlistContent);
#if Firebase_Debug
            Debug.Log("FireBase功能测试 创建 Info.plist 文件");
#endif
        }
    }

    private static void ConfigurePushNotificationsCapability(PBXProject proj, string extGuid, string buildPath)
    {
        
#if Firebase_Debug
        Debug.Log("FireBase功能测试 开始配置 Push Notifications 能力...");
#endif
        
        
        // 1. 添加 Push Notifications 能力
        proj.AddCapability(extGuid, PBXCapabilityType.PushNotifications);
        
#if Firebase_Debug
        Debug.Log("FireBase功能测试 添加 Push Notifications 能力");
#endif
        
        
        // 2. 确保签名配置正确
        string teamId = PlayerSettings.iOS.appleDeveloperTeamID;
        if (!string.IsNullOrEmpty(teamId))
        {
            proj.SetBuildProperty(extGuid, "DEVELOPMENT_TEAM", teamId);
            proj.SetBuildProperty(extGuid, "CODE_SIGN_STYLE", "Automatic");
            
            
#if Firebase_Debug
            Debug.Log($"FireBase功能测试 配置开发团队: {teamId}");
#endif
            
        }
        
        
#if Firebase_Debug
        Debug.Log("FireBase功能测试 Push Notifications 能力配置完成");
#endif
        
    }

    /// <summary>
    /// 配置 Podfile,添加 Firebase 相关依赖
    /// </summary>
    private static void ConfigureFirebasePodfile(string buildPath)
    {
        string podfilePath = Path.Combine(buildPath, "Podfile");
        
        // 如果 Podfile 不存在,直接警告并返回
        if (!File.Exists(podfilePath))
        {
            Debug.LogWarning("FireBase功能测试 Podfile 不存在,跳过 Firebase 依赖配置");
            return;
        }
        
        // 检查是否包含 FirebaseNotificationService target
        string podfileContent = File.ReadAllText(podfilePath);
        
        if (!podfileContent.Contains("target 'FirebaseNotificationService'"))
        {
            // 查找 UnityFramework target 并添加子 target
            string pattern = @"(target\s+'UnityFramework'\s+do[^}]*?)(end)";
            string replacement = $"$1\n  target 'FirebaseNotificationService' do\n  end\n$2";
            
            if (System.Text.RegularExpressions.Regex.IsMatch(podfileContent, pattern, System.Text.RegularExpressions.RegexOptions.Singleline))
            {
                podfileContent = System.Text.RegularExpressions.Regex.Replace(podfileContent, pattern, replacement, System.Text.RegularExpressions.RegexOptions.Singleline);
                File.WriteAllText(podfilePath, podfileContent);
                
#if Firebase_Debug
                Debug.Log("FireBase功能测试 在 UnityFramework target 内添加 FirebaseNotificationService 子 target");
#endif
            }
            else
            {
                Debug.LogWarning("FireBase功能测试 未找到 UnityFramework target,无法添加子 target");
            }
        }
        else
        {
#if Firebase_Debug
            Debug.Log("FireBase功能测试 FirebaseNotificationService target 已存在于 Podfile 中");
#endif
        }
    }


    /// <summary>
    /// 执行 pod install 安装 Firebase 通知扩展组件
    /// </summary>
    private static void PodInstallFirebaseNotificationService(string buildPath)
    {
        Debug.Log("=== 开始执行 Pod 安装流程 ===");
        
        if (!Directory.Exists(buildPath))
        {
            Debug.LogError($"Xcode工程路径不存在: {buildPath}");
            return;
        }

        string podfilePath = Path.Combine(buildPath, "Podfile");
        if (!File.Exists(podfilePath))
        {
            Debug.LogError($"Podfile文件不存在: {podfilePath}");
            return;
        }

        try
        {
            // 转义路径中的单引号
            string escapedPath = buildPath.Replace("'", "'\\''");
            
            string appleScript = $@"
            tell application ""Terminal""
                activate
                do script ""cd '{escapedPath}' && pod install && exit""
            end tell";

            Debug.Log($"正在启动终端执行pod install...");
            
            using (Process process = new Process())
            {
                process.StartInfo = new ProcessStartInfo
                {
                    FileName = "/usr/bin/osascript",
                    Arguments = $"-e '{appleScript}'",
                    UseShellExecute = false,
                    RedirectStandardError = true,
                    CreateNoWindow = true
                };

                process.Start();
                process.WaitForExit();

                if (process.ExitCode != 0)
                {
                    string error = process.StandardError.ReadToEnd();
                    Debug.LogError($"启动终端失败: {error}");
                }
                else
                {
                    Debug.Log("已启动终端执行pod install,请稍后在终端中查看结果");
                }
            }
        }
        catch (Exception ex)
        {
            Debug.LogError($"执行命令时发生异常: {ex}");
        }
        
        Debug.Log("=== Pod安装流程结束 ===");
    }

    // Firebase 的 Info.plist 内容
    private static readonly string FirebaseInfoPlistContent =
@"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version=""1.0"">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>$(DEVELOPMENT_LANGUAGE)</string>
    <key>CFBundleDisplayName</key>
    <string>FirebaseNotificationService</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>XPC!</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>NSExtension</key>
    <dict>
        <key>NSExtensionPointIdentifier</key>
        <string>com.apple.usernotifications.service</string>
        <key>NSExtensionPrincipalClass</key>
        <string>FirebaseNotificationService</string>
    </dict>
</dict>
</plist>";

}

#endif