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