三国卡牌客户端基础资源仓库
yyl
3 天以前 47921ce315e894bbbed712cbf04ee358be345113
Assets/Editor/XCodeProjectMod.cs
@@ -1,5 +1,4 @@
using DG.Tweening.Plugins.Core.PathCore;
using System;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
@@ -8,11 +7,8 @@
public class XCodeProjectMod
{
    private const string CODE_SIGN_DEVELOPER = "";
    private const string CODE_SIGN_DISTRIBUTION = "";
    private const string PROVISIONING_DEVELOPER = "";
    private const string PROVISIONING_DISTRIBUTION = "";
    private const string TEAM = "";
    // Channel 插件存放目录(BuildIpa 前由 ClientPackage.BuildIpa 从 _sdkPath 拷贝到 Assets/Plugins/iOS/Channel)
    private static readonly string iOSPluginPath = Application.dataPath + "/Plugins/iOS/Channel";
    [UnityEditor.Callbacks.PostProcessBuild(999)]
    public static void OnPostprocessBuild(BuildTarget buildTarget, string path)
@@ -27,8 +23,13 @@
        BuildPlist(path);
        ModifyFile(path);
        // 生成 .xcworkspace 结构,方便开发者在 Xcode 中手动 Add Package Dependency
        // SPM 依赖必须通过 .xcworkspace 管理,.xcodeproj 单独无法正确 resolve
        // 开发者需在 Xcode 中手动 File → Add Package Dependency 添加以下仓库,并选择所需的产品包:
        //   - Firebase:  https://github.com/firebase/firebase-ios-sdk
        //   - Facebook:  https://github.com/facebook/facebook-ios-sdk
        //   - Adjust:    https://github.com/adjust/ios_sdk
        CreateWorkspaceWithSPM(path);
    }
    static void DoPBXProject(string path)
@@ -41,48 +42,28 @@
        string targetGUID = project.TargetGuidByName(PBXProject.GetUnityTargetName());
        string fwTargetGUID = project.TargetGuidByName("UnityFramework");
        // BuildSetting里的相关设置
        project.SetBuildProperty(project.ProjectGuid(), "ENABLE_BITCODE", "NO");
        project.SetBuildProperty(targetGUID, "ENABLE_BITCODE", "NO");
        project.SetBuildProperty(targetGUID, "DEVELOPMENT_TEAM", TEAM);
        // 1.1 环境要求:iOS 13.0 及以上
        project.SetBuildProperty(targetGUID, "IPHONEOS_DEPLOYMENT_TARGET", "13.0");
        project.SetBuildProperty(fwTargetGUID, "IPHONEOS_DEPLOYMENT_TARGET", "13.0");
        project.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-ObjC");
        project.AddBuildProperty(targetGUID, "GCC_GENERATE_DEBUGGING_SYMBOLS", "NO");
        //wkwebview
        // Firebase 调试日志参数
        project.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-FIRAnalyticsDebugEnabled");
        project.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-FIRDebugEnabled");
        project.AddBuildProperty(targetGUID, "OTHER_LDFLAGS", "-FIRAnalyticsVerboseLoggingEnabled");
        // WebKit(文档要求)
        project.AddFrameworkToProject(fwTargetGUID, "WebKit.framework", true);
        project.AddFrameworkToProject(fwTargetGUID, "SystemConfiguration.framework", true);
        project.AddFrameworkToProject(fwTargetGUID, "Security.framework", true);
        project.AddFrameworkToProject(fwTargetGUID, "JavaScriptCore.framework", true);
        project.AddFrameworkToProject(fwTargetGUID, "Accelerate.framework", true);
        // fimpfunSDK.framework 添加到工程并设置为 Embed & Sign
        string fimpfunFrameworkPath = path + "/Frameworks/fimpfunSDK.framework";
        if (Directory.Exists(fimpfunFrameworkPath))
        {
            string fileGuid = project.AddFile(fimpfunFrameworkPath, "Frameworks/fimpfunSDK.framework", PBXSourceTree.Source);
            project.AddFileToBuild(fwTargetGUID, fileGuid);
            // Embed & Sign: 添加到 main target 的 Embed Frameworks
            project.AddFileToBuild(targetGUID, fileGuid);
        }
        // 处理 库文件
        project.AddFileToBuild(fwTargetGUID, project.AddFile("/usr/lib/libz.tbd", "Frameworks/libz.tbd", PBXSourceTree.Sdk));
        project.AddFileToBuild(fwTargetGUID, project.AddFile("/usr/lib/libsqlite3.tbd", "Frameworks/libsqlite3.tbd", PBXSourceTree.Sdk));
        project.AddFileToBuild(fwTargetGUID, project.AddFile("/usr/lib/libc++.tbd", "Frameworks/libc++.tbd", PBXSourceTree.Sdk));
        project.AddFileToBuild(fwTargetGUID, project.AddFile("/usr/lib/libiconv.tbd", "Frameworks/libiconv.tbd", PBXSourceTree.Sdk));
        project.AddFileToBuild(fwTargetGUID, project.AddFile("/usr/lib/libresolv.tbd", "Frameworks/libresolv.tbd", PBXSourceTree.Sdk));
        //UnityFramework
        project.AddBuildProperty(fwTargetGUID, "OTHER_LDFLAGS", "-ObjC");
        // 添加 GoogleService-Info.plist 和 funshine.plist 到工程
        string iosPluginPath = path + "/Libraries/Plugins/iOS/Channel";
        string[] configPlists = { "GoogleService-Info.plist", "funshine.plist" };
        foreach (var plistName in configPlists)
        {
            string srcPath = iosPluginPath + "/" + plistName;
            string srcPath = iOSPluginPath + "/" + plistName;
            if (File.Exists(srcPath))
            {
                string destPath = path + "/" + plistName;
@@ -90,9 +71,67 @@
                string fileGuid = project.AddFile(plistName, plistName, PBXSourceTree.Source);
                project.AddFileToBuild(targetGUID, fileGuid);
            }
            else
            {
                Debug.LogWarning("[XCodeProjectMod] " + plistName + " 未找到: " + srcPath);
            }
        }
        // hfsdk.xcframework 添加到工程并设置为 Embed & Sign
        string hfFrameworkPath = path + "/Frameworks/hfsdk.xcframework";
        if (Directory.Exists(hfFrameworkPath))
        {
            string fileGuid = project.AddFile(hfFrameworkPath, "Frameworks/hfsdk.xcframework", PBXSourceTree.Source);
            project.AddFileToBuild(fwTargetGUID, fileGuid);
            // Embed & Sign: 添加到 main target 的 Embed Frameworks
            project.AddFileToBuild(targetGUID, fileGuid);
        }
        // Adjust SDK 依赖的系统框架(文档要求 Status 设为 Optional)
        project.AddFrameworkToProject(fwTargetGUID, "AdServices.framework", true);
        project.AddFrameworkToProject(fwTargetGUID, "AdSupport.framework", true);
        project.AddFrameworkToProject(fwTargetGUID, "AppTrackingTransparency.framework", true);
        project.AddFrameworkToProject(fwTargetGUID, "StoreKit.framework", true);
        File.WriteAllText(_projectPath, project.WriteToString());
    }
    /// <summary>
    /// 生成 Unity-iPhone.xcworkspace 结构,仅包含 contents.xcworkspacedata。
    /// SPM 依赖由开发者在 Xcode 中手动 File → Add Package Dependency 添加并选择所需产品包:
    ///   - Firebase:  https://github.com/firebase/firebase-ios-sdk
    ///   - Facebook:  https://github.com/facebook/facebook-ios-sdk
    ///   - Adjust:    https://github.com/adjust/ios_sdk
    /// Package.resolved 由 Xcode 在 resolve 后自动生成,代码不做处理。
    /// </summary>
    private static void CreateWorkspaceWithSPM(string projectPath)
    {
        string workspacePath = projectPath + "/Unity-iPhone.xcworkspace";
        string xcodeprojAbsPath = projectPath + "/Unity-iPhone.xcodeproj";
        if (!Directory.Exists(xcodeprojAbsPath))
        {
            Debug.LogWarning("[XCodeProjectMod] xcodeproj not found, skip creating workspace: " + xcodeprojAbsPath);
            return;
        }
        Directory.CreateDirectory(workspacePath);
        string contentsXml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<Workspace
   version = ""1.0"">
   <FileRef
      location = ""group:Unity-iPhone.xcodeproj"">
   </FileRef>
</Workspace>
";
        File.WriteAllText(workspacePath + "/contents.xcworkspacedata", contentsXml);
        Debug.Log("[XCodeProjectMod] Unity-iPhone.xcworkspace created at: " + workspacePath);
        Debug.Log("[XCodeProjectMod] 请在 Xcode 中打开 .xcworkspace,手动 File → Add Package Dependency 添加 SPM 仓库:");
        Debug.Log("[XCodeProjectMod]   - Firebase:  https://github.com/firebase/firebase-ios-sdk");
        Debug.Log("[XCodeProjectMod]   - Facebook:  https://github.com/facebook/facebook-ios-sdk");
        Debug.Log("[XCodeProjectMod]   - Adjust:    https://github.com/adjust/ios_sdk");
    }
    private static void BuildPlist(string path)
@@ -103,23 +142,23 @@
        _plist.ReadFromString(File.ReadAllText(_plistPath));
        PlistElementDict _rootDict = _plist.root;
        PlistElementDict _nsAppTransportSecurity = _rootDict.CreateDict("NSAppTransportSecurity");
        _nsAppTransportSecurity.SetBoolean("NSAllowsArbitraryLoads", true);
        _rootDict.SetString("NSPhotoLibraryAddUsageDescription", "You must grant the photo album permission to take screenshots and save data for users");
        _rootDict.SetString("NSCameraUsageDescription", "Please allow application permission access, otherwise the function cannot be started");
        _rootDict.SetString("NSUserTrackingUsageDescription", "This guide will display personalized ads specifically for you");
        // Adjust (funshine.plist: kAdjustAppToken)
        _rootDict.SetString("AdjustAppToken", "nbevz727gy68");
        _rootDict.SetString("NSUserTrackingUsageDescription", "Please rest assured, granting permission will not access your private information on other websites. This permission is only used to identify the device and ensure service security and enhance browsing experience");
        // Facebook (funshine.plist: kFacebookAppID / kFacebookAppSecret)
        _rootDict.SetString("FacebookAppID", "1445747540428317");
        _rootDict.SetString("FacebookClientToken", "");
        _rootDict.SetString("FacebookDisplayName", "Legend of the Sword Master");
        _rootDict.SetString("FacebookClientToken", "1103765897fb67ffc898e6a8ee2d9aec");
        _rootDict.SetString("FacebookDisplayName", "EZ PZ: Byte Heroes");
        _rootDict.SetBoolean("FacebookAutoLogAppEventsEnabled", true);
        _rootDict.SetBoolean("FacebookAdvertiserIDCollectionEnabled", true);
        // 适配欧盟地区政策法规 - Google Analytics 默认允许
        _rootDict.SetBoolean("GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE", true);
        _rootDict.SetBoolean("GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE", true);
        _rootDict.SetBoolean("GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA", true);
        _rootDict.SetBoolean("GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS", true);
        // App 名称本地化
        _rootDict.SetBoolean("Application has localized display name", true);
        _rootDict.SetString("CFBundleDevelopmentRegion", "english");
        _rootDict.SetString("Localization native development region", "english");
        PlistElementArray nsURLTypes = _rootDict.CreateArray("CFBundleURLTypes");
        var dict0 = nsURLTypes.AddDict();
@@ -130,18 +169,7 @@
        var array1 = _rootDict.CreateArray("LSApplicationQueriesSchemes");
        array1.AddString("fbapi");
        array1.AddString("fbapi20130214");
        array1.AddString("fbapi20130410");
        array1.AddString("fbapi20130702");
        array1.AddString("fbapi20131010");
        array1.AddString("fbapi20131219");
        array1.AddString("fbapi20140410");
        array1.AddString("fbapi20140116");
        array1.AddString("fbapi20150313");
        array1.AddString("fbapi20150629");
        array1.AddString("fbapi20160328");
        array1.AddString("fbauth");
        array1.AddString("fb-messenger-share-api");
        array1.AddString("fb-messenger-api");
        array1.AddString("fbauth2");
        array1.AddString("fbshareextension");
@@ -170,6 +198,7 @@
        // fimpfunSDK 生命周期
        _xclass.WriteBelow("- (BOOL)application:(UIApplication*)app openURL:(NSURL*)url options:(NSDictionary<NSString*, id>*)options\n{", "\n    [_fimpfunBridge application:app openURL:url options:options];");
        _xclass.WriteBelow("::printf(\"-> applicationDidBecomeActive()\\n\");", "[_fimpfunBridge applicationDidBecomeActive:application];");
@@ -179,9 +208,126 @@
        _xclass.WriteBelow("DisplayConnection*  _mainDisplay;", "FimpfunBridge* _fimpfunBridge;");
        _xclass.WriteBelow("@property (readonly, copy, nonatomic) DisplayConnection*    mainDisplay;",
                           "@property (readonly, copy, nonatomic) FimpfunBridge*  fimpfunBridge;");
        // 3.1 适配欧盟政策:在 viewDidAppear 中调用 adaptingEUGDPR(文档要求)
        // UnityViewControllerBase.mm 在较新 Unity 版本(如 2022.3+)中可能不存在
        string viewControllerPath = projectPath + "/Classes/UnityViewControllerBase.mm";
        if (System.IO.File.Exists(viewControllerPath))
        {
            var _viewController = new XClass(viewControllerPath);
            _viewController.WriteBelow("@implementation UnityViewControllerBase",
                "\n- (void)viewDidAppear:(BOOL)animated {\n    [super viewDidAppear:animated];\n    [GetAppController().fimpfunBridge viewDidAppear];\n}\n");
        }
        else
        {
            Debug.LogWarning("[XCodeProjectMod] UnityViewControllerBase.mm 文件不存在,跳过 viewDidAppear 注入。此 Unity 版本可能已移除该文件。");
        }
        // 创建 InfoPlist.strings(App 名称本地化)
        CreateInfoPlistStrings(projectPath);
    }
    /// <summary>
    /// 创建 InfoPlist.strings 文件用于 App 名称本地化
    /// </summary>
    private static void CreateInfoPlistStrings(string projectPath)
    {
        // 英文(默认)
        string enDir = projectPath + "/English.lproj";
        if (!Directory.Exists(enDir))
        {
            Directory.CreateDirectory(enDir);
        }
        string enStringsPath = enDir + "/InfoPlist.strings";
        if (!File.Exists(enStringsPath))
        {
            File.WriteAllText(enStringsPath, "CFBundleDisplayName = \"EZ PZ\";\n");
        }
        // 中文
        string zhDir = projectPath + "/zh-Hans.lproj";
        if (!Directory.Exists(zhDir))
        {
            Directory.CreateDirectory(zhDir);
        }
        string zhStringsPath = zhDir + "/InfoPlist.strings";
        if (!File.Exists(zhStringsPath))
        {
            File.WriteAllText(zhStringsPath, "CFBundleDisplayName = \"懒人三国\";\n");
        }
        // 将 InfoPlist.strings 添加到 Xcode 工程
        string _projectPath = PBXProject.GetPBXProjectPath(projectPath);
        try
        {
            PBXProject project = new PBXProject();
            project.ReadFromString(File.ReadAllText(_projectPath));
            string targetGUID = project.TargetGuidByName(PBXProject.GetUnityTargetName());
            // 英文
            string enRelPath = "English.lproj/InfoPlist.strings";
            string enFileGuid = project.AddFile(enRelPath, enRelPath, PBXSourceTree.Source);
            project.AddFileToBuild(targetGUID, enFileGuid);
            // 中文
            string zhRelPath = "zh-Hans.lproj/InfoPlist.strings";
            string zhFileGuid = project.AddFile(zhRelPath, zhRelPath, PBXSourceTree.Source);
            project.AddFileToBuild(targetGUID, zhFileGuid);
            // 添加 Sign In with Apple entitlements
            AddEntitlements(projectPath, project, targetGUID);
            File.WriteAllText(_projectPath, project.WriteToString());
        }
        catch (System.Exception e)
        {
            Debug.LogError("[XCodeProjectMod] 将 InfoPlist.strings 添加到 Xcode 工程失败: " + e.Message);
        }
    }
    /// <summary>
    /// 添加 Sign In with Apple 等 entitlements
    /// </summary>
    private static void AddEntitlements(string projectPath, PBXProject project, string targetGUID)
    {
        string entPath = projectPath + "/" + PBXProject.GetUnityTargetName() + ".entitlements";
        // 如果 entitlements 文件不存在,创建
        if (!File.Exists(entPath))
        {
            string entContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +
                "<plist version=\"1.0\">\n" +
                "<dict>\n" +
                "\t<key>com.apple.developer.applesignin</key>\n" +
                "\t<array>\n" +
                "\t\t<string>Default</string>\n" +
                "\t</array>\n" +
                "</dict>\n" +
                "</plist>\n";
            File.WriteAllText(entPath, entContent);
        }
        else
        {
            // 已有 entitlements 文件,检查是否已有 Sign In with Apple
            string existingContent = File.ReadAllText(entPath);
            if (!existingContent.Contains("com.apple.developer.applesignin"))
            {
                existingContent = existingContent.Replace("</dict>",
                    "\t<key>com.apple.developer.applesignin</key>\n" +
                    "\t<array>\n" +
                    "\t\t<string>Default</string>\n" +
                    "\t</array>\n" +
                    "</dict>");
                File.WriteAllText(entPath, existingContent);
            }
        }
        // 设置 CODE_SIGN_ENTITLEMENTS build property(不加入 Copy Bundle Resources)
        // entitlements 文件只需要在 Build Settings 中引用,不需要加入任何 Build Phase
        string entFileName = PBXProject.GetUnityTargetName() + ".entitlements";
        project.SetBuildProperty(targetGUID, "CODE_SIGN_ENTITLEMENTS", entFileName);
    }
    private static string GetBuildPath()
    {
@@ -211,6 +357,21 @@
            }
        }
        return _sceneNames.ToArray();
    }
    private static void CopyDirectory(string sourceDir, string destDir)
    {
        Directory.CreateDirectory(destDir);
        foreach (var file in Directory.GetFiles(sourceDir))
        {
            string destFile = Path.Combine(destDir, Path.GetFileName(file));
            File.Copy(file, destFile, true);
        }
        foreach (var dir in Directory.GetDirectories(sourceDir))
        {
            string destSubDir = Path.Combine(destDir, Path.GetFileName(dir));
            CopyDirectory(dir, destSubDir);
        }
    }
    private static bool s_IsAppend = false;
@@ -250,5 +411,4 @@
        p.Start();
        p.WaitForExit();
    }
}