Singularity/Assets/Plugins/ImaginationOverflow/UniversalDeepLinking/Editor/iOSPosBuild.cs
2024-05-06 11:45:45 -07:00

292 lines
9.8 KiB
C#

using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
#if UDL_DLL_BUILD
#endif
using UnityEditor;
#if (UNITY_EDITOR && (UNITY_IOS || UNITY_TVOS)) || UDL_DLL_BUILD
using UnityEngine;
#if !UDL_DLL_BUILD && !UNITY_2018_1_OR_NEWER
using UnityEditor.iOS.Xcode;
#else
using ImaginationOverflow.UniversalDeepLinking.Editor.Xcode;
#endif
namespace ImaginationOverflow.UniversalDeepLinking.Editor
{
/// <summary>
/// Pos Build script that configures the info.plist for Deep links and creates the entitlements file for Domain Association
/// </summary>
public class iOSBuilder : IPosBuilder
{
private const string PListName = "/Info.plist";
private const string EntitlementsExtension = ".entitlements";
private const string EntitlementFormat =
"<?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></dict></plist>";
private const string EntitlementsCodeSign = "CODE_SIGN_ENTITLEMENTS";
private const string AssociatedDomainsKey = "com.apple.developer.associated-domains";
private const string AppLinksKey = "applinks:";
private BuildTarget _target;
public iOSBuilder(BuildTarget target)
{
this._target = target;
}
public void PostBuildProcess(AppLinkingConfiguration configuration, string pathToBuiltProject)
{
ChangeIOSFlagsAndFrameworks(pathToBuiltProject);
AddDeepLinks(configuration, pathToBuiltProject);
AddDomainAssociation(pathToBuiltProject, configuration);
}
private void AddFrameworks(PBXProject project, string projectTarget)
{
//const string flags = "-all_load -ObjC";
const string flags = "-ObjC";
project.AddBuildProperty(projectTarget, "OTHER_LDFLAGS", flags);
try
{
var frameworkTarget = project.TargetGuidByName("UnityFramework");
if (frameworkTarget != null)
project.AddBuildProperty(frameworkTarget, "OTHER_LDFLAGS", flags);
}
catch (Exception e)
{
Debug.Log("UDL iOS Error " + e.ToString());
}
}
private void ChangeIOSFlagsAndFrameworks(string pathToBuiltProject)
{
string projectPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
PBXProject project = new PBXProject();
project.ReadFromString(File.ReadAllText(projectPath));
string targetName = PBXProject.GetUnityTargetName();
string projectTarget = project.TargetGuidByName(targetName);
AddFrameworks(project, projectTarget);
File.WriteAllText(projectPath, project.WriteToString());
}
private void AddDeepLinks(AppLinkingConfiguration configuration, string pathToBuiltProject)
{
var plistDocumentPath = pathToBuiltProject + PListName;
var plistDocument = new PlistDocument();
plistDocument.ReadFromString(File.ReadAllText(plistDocumentPath));
var rootElement = plistDocument.root;
var bundleIdentifier = Application.identifier;
var urlSchemeArrayElement = rootElement["CFBundleURLTypes"] as PlistElementArray;
var configuredDeepLinks = new string[0];
if (urlSchemeArrayElement == null)
urlSchemeArrayElement = rootElement.CreateArray("CFBundleURLTypes");
else
{
try
{
configuredDeepLinks = urlSchemeArrayElement.values
.Select(v => v.AsDict())
.Where(d => d.values.ContainsKey("CFBundleURLSchemes"))
.Select(d =>
{
PlistElement elem;
d.values.TryGetValue("CFBundleURLSchemes", out elem);
return elem != null ? elem.AsString() : string.Empty;
}).ToArray();
}
catch (Exception e)
{
}
}
var mtarget = _target == BuildTarget.iOS ? SupportedPlatforms.iOS : SupportedPlatforms.tvOS;
foreach (var configurationDeepLinkingProtocol in configuration.GetPlatformDeepLinkingProtocols(mtarget, true))
{
if (configuredDeepLinks.Contains(configurationDeepLinkingProtocol.Scheme))
continue;
var urlTypeDic = urlSchemeArrayElement.AddDict();
urlTypeDic.SetString("CFBundleURLName", bundleIdentifier);
urlTypeDic.SetString("CFBundleTypeRole", "Viewer");
var link = configurationDeepLinkingProtocol.Scheme;
urlTypeDic.CreateArray("CFBundleURLSchemes").AddString(link);
}
File.WriteAllText(plistDocumentPath, plistDocument.WriteToString());
}
private void AddDomainAssociation(string pathToBuiltProject, AppLinkingConfiguration configuration)
{
string entitlementFilePath = "";
var mtarget = _target == BuildTarget.iOS ? SupportedPlatforms.iOS : SupportedPlatforms.tvOS;
if (!configuration.GetPlatformDomainProtocols(mtarget, true).Select(d => d.Host).Any())
return;
var entitlementsFiles = new DirectoryInfo(pathToBuiltProject).GetFiles("*.entitlements", SearchOption.AllDirectories);
if (entitlementsFiles.Length == 0)
{
entitlementFilePath = CreateEntitlementsFile(pathToBuiltProject);
}
else
{
//
// Try to find the default entitlements file if any
//
var file = entitlementsFiles.FirstOrDefault(d => d.Name.ToLower().Contains("unity"));
if (file == null)
file = entitlementsFiles.First();
if (entitlementsFiles.Length > 1)
Debug.LogWarning("Attention, it seems that you have multiple entitlements file. Only one will be added the Project : " + file.Name);
entitlementFilePath = file.FullName;
}
ChangeEntitlementAssociatedDomains(entitlementFilePath, configuration);
}
private static string CreateEntitlementsFile(string pathToBuiltProject)
{
string entitlementFilePath = "";
//var productName = Application.productName;
var productName = "UnityUdl";
var entitlementFileName = productName + EntitlementsExtension;
var projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
var proj = new PBXProject();
proj.ReadFromString(File.ReadAllText(projPath));
var targetName = PBXProject.GetUnityTargetName();
var targetGuid = proj.TargetGuidByName(targetName);
var dst = CombinePaths(pathToBuiltProject, targetName, entitlementFileName);
File.WriteAllText(dst, EntitlementFormat);
proj.AddFile(CombinePaths(targetName, entitlementFileName), entitlementFileName, PBXSourceTree.Source);
var entitlementFile = CombinePaths(targetName, entitlementFileName);
proj.AddBuildProperty(targetGuid, EntitlementsCodeSign, entitlementFile.Replace("\\", "/"));
proj.WriteToFile(projPath);
entitlementFilePath = dst;
return entitlementFilePath;
}
private void ChangeEntitlementAssociatedDomains(string entitlementFilePath, AppLinkingConfiguration configuration)
{
PlistDocument entitlementFile = new PlistDocument();
entitlementFile.ReadFromString(File.ReadAllText(entitlementFilePath));
PlistElementDict rootElement = entitlementFile.root;
var mtarget = _target == BuildTarget.iOS ? SupportedPlatforms.iOS : SupportedPlatforms.tvOS;
var configs = configuration.GetPlatformDomainProtocols(mtarget, true).Select(d => d.Host)
.Distinct().ToArray();
if (configs.Length != 0)
{
var associatedDomainsArrayElement = rootElement[AssociatedDomainsKey] as PlistElementArray;
var alreadySetupDomains = new string[0];
if (associatedDomainsArrayElement == null)
associatedDomainsArrayElement = rootElement.CreateArray(AssociatedDomainsKey);
else
{
try
{
alreadySetupDomains = associatedDomainsArrayElement.values.Select(a => a.AsString()).ToArray();
}
catch (Exception e)
{
}
}
//
// The except removes any config when the Append is used in the generation
//
foreach (var domainProtocol in configs.Where(c => alreadySetupDomains.Any(d => d.Contains(c)) == false))
{
associatedDomainsArrayElement.AddString(AppLinksKey + domainProtocol);
}
}
else
{
if (rootElement.values.ContainsKey(AssociatedDomainsKey))
rootElement.values.Remove(AssociatedDomainsKey);
}
File.WriteAllText(entitlementFilePath, entitlementFile.WriteToString());
}
public static string CombinePaths(params string[] paths)
{
if (paths == null)
{
throw new ArgumentNullException("paths");
}
return paths.Aggregate(Path.Combine);
}
}
}
#endif