844 строки
32 KiB
C#
844 строки
32 KiB
C#
#addin nuget:?package=Cake.FileHelpers
|
|
#addin nuget:?package=Cake.AzureStorage
|
|
#addin nuget:?package=NuGet.Core
|
|
#addin nuget:?package=Cake.Xcode
|
|
#load "utility.cake"
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.Versioning;
|
|
using NuGet;
|
|
|
|
// Native SDK versions
|
|
var AndroidSdkVersion = "2.5.0";
|
|
var IosSdkVersion = "2.5.1";
|
|
var UwpSdkVersion = "2.5.1-r0008-5be3f46";
|
|
|
|
// URLs for downloading binaries.
|
|
/*
|
|
* Read this: http://www.mono-project.com/docs/faq/security/.
|
|
* On Windows,
|
|
* you have to do additional steps for SSL connection to download files.
|
|
* http://stackoverflow.com/questions/4926676/mono-webrequest-fails-with-https
|
|
* By running mozroots and install part of Mozilla's root certificates can make it work.
|
|
*/
|
|
|
|
var SdkStorageUrl = "https://mobilecentersdkdev.blob.core.windows.net/sdk/";
|
|
var AndroidUrl = SdkStorageUrl + "AppCenter-SDK-Android-" + AndroidSdkVersion + ".zip";
|
|
var IosUrl = SdkStorageUrl + "AppCenter-SDK-Apple-" + IosSdkVersion + ".zip";
|
|
|
|
var AppCenterModules = new [] {
|
|
new AppCenterModule("appcenter-release.aar", "AppCenter.framework", "Microsoft.AppCenter", "Core"),
|
|
new AppCenterModule("appcenter-analytics-release.aar", "AppCenterAnalytics.framework", "Microsoft.AppCenter.Analytics", "Analytics"),
|
|
new AppCenterModule("appcenter-auth-release.aar", "AppCenterAuth.framework", "Microsoft.AppCenter.Auth", "Auth"),
|
|
new AppCenterModule("appcenter-distribute-release.aar", new[] { "AppCenterDistribute.framework", "AppCenterDistributeResources.bundle" }, "Microsoft.AppCenter.Distribute", "Distribute"),
|
|
new AppCenterModule("appcenter-push-release.aar", "AppCenterPush.framework", "Microsoft.AppCenter.Push", "Push"),
|
|
new AppCenterModule("appcenter-crashes-release.aar", "AppCenterCrashes.framework", "Microsoft.AppCenter.Crashes", "Crashes")
|
|
};
|
|
|
|
var ExternalUnityPackages = new [] {
|
|
// From https://github.com/googlesamples/unity-jar-resolver#getting-started
|
|
// Import the play-services-resolver-*.unitypackage into your plugin project <...> ensuring that you add the -gvh_disable option.
|
|
// You must specify the -gvh_disable option in order for the Version Handler to work correctly!
|
|
new ExternalUnityPackage("play-services-resolver-" + ExternalUnityPackage.VersionPlaceholder + ".unitypackage",
|
|
"1.2.95.0",
|
|
SdkStorageUrl + ExternalUnityPackage.NamePlaceholder,
|
|
"-gvh_disable")
|
|
};
|
|
|
|
// UWP IL2CPP dependencies.
|
|
var UwpIL2CPPDependencies = new [] {
|
|
new NugetDependency("sqlite-net-pcl", "1.3.1", "UAP, Version=v10.0")
|
|
};
|
|
var UwpIL2CPPJsonUrl = SdkStorageUrl + "Newtonsoft.Json.dll";
|
|
|
|
// Unity requires a specific NDK version for building Android with IL2CPP.
|
|
// Download from a link here: https://developer.android.com/ndk/downloads/older_releases.html
|
|
// Unity 2017.3 requires NDK r13b.
|
|
// The destination for the NDK download.
|
|
var NdkFolder = "android_ndk";
|
|
|
|
// Task TARGET for build
|
|
var Target = Argument("target", Argument("t", "Default"));
|
|
|
|
// Available AppCenter modules.
|
|
// AppCenter module class definition.
|
|
class AppCenterModule
|
|
{
|
|
public string AndroidModule { get; private set; }
|
|
public string[] IosModules { get; private set; }
|
|
public string DotNetModule { get; private set; }
|
|
public string Moniker { get; private set; }
|
|
public bool UWPHasNativeCode { get; private set; }
|
|
public string[] NativeArchitectures { get; private set; }
|
|
|
|
public AppCenterModule(string android, string ios, string dotnet, string moniker, bool hasNative = false) :
|
|
this(android, new[] { ios }, dotnet, moniker, hasNative)
|
|
{
|
|
}
|
|
|
|
public AppCenterModule(string android, string[] ios, string dotnet, string moniker, bool hasNative = false)
|
|
{
|
|
AndroidModule = android;
|
|
IosModules = ios;
|
|
DotNetModule = dotnet;
|
|
Moniker = moniker;
|
|
UWPHasNativeCode = hasNative;
|
|
if (hasNative)
|
|
{
|
|
NativeArchitectures = new string[] {"x86", "x64", "arm"};
|
|
}
|
|
}
|
|
}
|
|
|
|
class ExternalUnityPackage
|
|
{
|
|
public static string NamePlaceholder = "<name>";
|
|
public static string VersionPlaceholder = "<version>";
|
|
|
|
public string Name { get; private set; }
|
|
public string Version { get; private set; }
|
|
public string Url { get; private set; }
|
|
public string AdditionalImportArgs { get; private set; }
|
|
|
|
public ExternalUnityPackage(string name, string version, string url, string additionalImportArgs = "")
|
|
{
|
|
AdditionalImportArgs = additionalImportArgs;
|
|
Version = version;
|
|
Name = name.Replace(VersionPlaceholder, Version);
|
|
Url = url.Replace(NamePlaceholder, Name).Replace(VersionPlaceholder, Version);
|
|
}
|
|
}
|
|
|
|
class NugetDependency
|
|
{
|
|
public string Name { get; set; }
|
|
public string Version { get; set; }
|
|
public string Framework { get; set; }
|
|
public bool IncludeDependencies { get; set; }
|
|
|
|
public NugetDependency(string name, string version, string framework, bool includeDependencies = true)
|
|
{
|
|
Name = name;
|
|
Version = version;
|
|
Framework = framework;
|
|
IncludeDependencies = includeDependencies;
|
|
}
|
|
}
|
|
|
|
// Spec files can have up to one dependency.
|
|
class UnityPackage
|
|
{
|
|
private string _packageName;
|
|
private string _packageVersion;
|
|
private List<string> _includePaths = new List<string>();
|
|
|
|
public UnityPackage(string specFilePath)
|
|
{
|
|
AddFilesFromSpec(specFilePath);
|
|
}
|
|
|
|
private void AddFilesFromSpec(string specFilePath)
|
|
{
|
|
var needsCore = Statics.Context.XmlPeek(specFilePath, "package/@needsCore") == "true";
|
|
if (needsCore)
|
|
{
|
|
var specFileDirectory = System.IO.Path.GetDirectoryName(specFilePath);
|
|
AddFilesFromSpec(specFileDirectory + "/AppCenter.unitypackagespec");
|
|
}
|
|
_packageName = Statics.Context.XmlPeek(specFilePath, "package/@name");
|
|
_packageVersion = Statics.Context.XmlPeek(specFilePath, "package/@version");
|
|
if (_packageName == null || _packageVersion == null)
|
|
{
|
|
Statics.Context.Error("Invalid format for UnityPackageSpec file '" + specFilePath + "': missing package name or version");
|
|
return;
|
|
}
|
|
|
|
var xpathPrefix = "/package/include/file[";
|
|
var xpathSuffix= "]/@path";
|
|
|
|
string lastPath = Statics.Context.XmlPeek(specFilePath, xpathPrefix + "last()" + xpathSuffix);
|
|
var currentIdx = 1;
|
|
var currentPath = Statics.Context.XmlPeek(specFilePath, xpathPrefix + currentIdx++ + xpathSuffix);
|
|
|
|
if (currentPath != null)
|
|
{
|
|
_includePaths.Add(currentPath);
|
|
}
|
|
while (currentPath != lastPath)
|
|
{
|
|
currentPath = Statics.Context.XmlPeek(specFilePath, xpathPrefix + currentIdx++ + xpathSuffix);
|
|
_includePaths.Add(currentPath);
|
|
}
|
|
}
|
|
|
|
public void CreatePackage(string targetDirectory)
|
|
{
|
|
// From https://github.com/googlesamples/unity-jar-resolver#getting-started
|
|
// Export your plugin <...> ensuring that you <...> Add the -gvh_disable option.
|
|
// You must specify the -gvh_disable option in order for the Version Handler to work correctly!
|
|
var args = "-gvh_disable -exportPackage ";
|
|
foreach (var path in _includePaths)
|
|
{
|
|
args += " " + path;
|
|
}
|
|
var fullPackageName = _packageName + "-v" + _packageVersion + ".unitypackage";
|
|
args += " " + targetDirectory + "/" + fullPackageName;
|
|
var result = ExecuteUnityCommand(args);
|
|
if (result != 0)
|
|
{
|
|
Statics.Context.Error("Something went wrong while creating Unity package '" + fullPackageName + "'");
|
|
}
|
|
}
|
|
|
|
public void CopyFiles(DirectoryPath targetDirectory)
|
|
{
|
|
foreach (var path in _includePaths)
|
|
{
|
|
if (Statics.Context.DirectoryExists(path))
|
|
{
|
|
Statics.Context.CopyDirectory(path, targetDirectory.Combine(path));
|
|
}
|
|
else
|
|
{
|
|
Statics.Context.CopyFile(path, targetDirectory.CombineWithFilePath(path));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Downloading Android binaries.
|
|
Task("Externals-Android")
|
|
.Does(() =>
|
|
{
|
|
CleanDirectory("./externals/android");
|
|
|
|
// Download zip file.
|
|
DownloadFile(AndroidUrl, "./externals/android/android.zip");
|
|
Unzip("./externals/android/android.zip", "./externals/android/");
|
|
|
|
// Copy files
|
|
foreach (var module in AppCenterModules)
|
|
{
|
|
var files = GetFiles("./externals/android/*/" + module.AndroidModule);
|
|
CopyFiles(files, "Assets/AppCenter/Plugins/Android/");
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
// Downloading iOS binaries.
|
|
Task("Externals-Ios")
|
|
.Does(() =>
|
|
{
|
|
CleanDirectory("./externals/ios");
|
|
|
|
// Download zip file containing AppCenter frameworks
|
|
DownloadFile(IosUrl, "./externals/ios/ios.zip");
|
|
Unzip("./externals/ios/ios.zip", "./externals/ios/");
|
|
|
|
// Copy files
|
|
foreach (var module in AppCenterModules)
|
|
{
|
|
foreach (var iosModule in module.IosModules)
|
|
{
|
|
var destinationFolder = "Assets/AppCenter/Plugins/iOS/" + module.Moniker + "/" + iosModule;
|
|
DeleteDirectoryIfExists(destinationFolder);
|
|
MoveDirectory("./externals/ios/AppCenter-SDK-Apple/iOS/" + iosModule, destinationFolder);
|
|
}
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
// Downloading UWP binaries.
|
|
Task ("Externals-Uwp")
|
|
.Does (() => {
|
|
var feedIdNugetEnv = Argument("NuGetFeedId", EnvironmentVariable("NUGET_FEED_ID"));
|
|
var userNugetEnv = EnvironmentVariable("NUGET_USER");
|
|
var passwordNugetEnv = Argument("NuGetPassword", EnvironmentVariable("NUGET_PASSWORD"));
|
|
var usePublicFeed = (string.IsNullOrEmpty (feedIdNugetEnv) || string.IsNullOrEmpty (userNugetEnv) || string.IsNullOrEmpty (passwordNugetEnv));
|
|
|
|
CleanDirectory ("externals/uwp");
|
|
EnsureDirectoryExists ("Assets/AppCenter/Plugins/WSA/");
|
|
foreach (var module in AppCenterModules) {
|
|
if (module.Moniker == "Auth") {
|
|
Warning ("Skipping 'Auth' for UWP.");
|
|
continue;
|
|
}
|
|
if (module.Moniker == "Distribute") {
|
|
Warning ("Skipping 'Distribute' for UWP.");
|
|
continue;
|
|
}
|
|
if (module.Moniker == "Crashes") {
|
|
Warning ("Skipping 'Crashes' for UWP.");
|
|
continue;
|
|
}
|
|
Information ("Downloading " + module.DotNetModule + "...");
|
|
// Download nuget package
|
|
|
|
GetUwpPackage (module, usePublicFeed);
|
|
}
|
|
}).OnError (HandleError);
|
|
|
|
// Builds the ContentProvider for the Android package and puts it in the
|
|
// proper folder.
|
|
Task("BuildAndroidContentProvider").Does(()=>
|
|
{
|
|
// Folder and script locations
|
|
var appName = "AppCenterLoaderApp";
|
|
var libraryName = "appcenter-loader";
|
|
BuildAndroidLibrary(appName, libraryName);
|
|
libraryName = "appcenter-push-delegate";
|
|
BuildAndroidLibrary(appName, libraryName);
|
|
|
|
// This is a workaround for NDK build making an error where it claims
|
|
// it can't find the built .so library (which is built successfully).
|
|
// This error is breaking the CI build on Windows. If you are seeing this,
|
|
// most likely we haven't found a fix and this is an NDK bug.
|
|
if (!IsRunningOnWindows())
|
|
{
|
|
appName = "BreakpadSupport";
|
|
BuildAndroidLibrary(appName, "", false);
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
void BuildAndroidLibrary(string appName, string libraryName, bool copyBinary = true) {
|
|
var libraryFolder = System.IO.Path.Combine(appName, libraryName);
|
|
var gradleScript = System.IO.Path.Combine(libraryFolder, "build.gradle");
|
|
|
|
// Compile the library
|
|
var gradleWrapper = System.IO.Path.Combine(appName, "gradlew");
|
|
if (IsRunningOnWindows())
|
|
{
|
|
gradleWrapper += ".bat";
|
|
}
|
|
var fullArgs = "-b " + gradleScript + " assembleRelease";
|
|
StartProcess(gradleWrapper, fullArgs);
|
|
|
|
if (copyBinary) {
|
|
// Source and destination of generated aar
|
|
var aarName = libraryName + "-release.aar";
|
|
var aarSource = System.IO.Path.Combine(libraryFolder, "build/outputs/aar/" + aarName);
|
|
var aarDestination = "Assets/AppCenter/Plugins/Android";
|
|
|
|
// Delete the aar in case it already exists in the Assets folder
|
|
var existingAar = System.IO.Path.Combine(aarDestination, aarName);
|
|
if (FileExists(existingAar))
|
|
{
|
|
DeleteFile(existingAar);
|
|
}
|
|
|
|
// Move the .aar to Assets/AppCenter/Plugins/Android
|
|
MoveFileToDirectory(aarSource, aarDestination);
|
|
}
|
|
}
|
|
|
|
// Install Unity Editor for Windows
|
|
Task("Install-Unity-Windows").Does(() => {
|
|
string unityDownloadUrl = EnvironmentVariable("EDITOR_URL_WIN");
|
|
string il2cppSupportDownloadUrl = EnvironmentVariable("IL2CPP_SUPPORT_URL");
|
|
// const string dotNetSupportDownloadUrl = @"https://netstorage.unity3d.com/unity/88933597c842/TargetSupportInstaller/UnitySetup-UWP-.NET-Support-for-Editor-2018.2.17f1.exe";
|
|
|
|
Information("Downloading Unity Editor...");
|
|
DownloadFile(unityDownloadUrl, "./UnitySetup64.exe");
|
|
Information("Installing Unity Editor...");
|
|
var result = StartProcess("./UnitySetup64.exe", " /S");
|
|
if (result != 0)
|
|
{
|
|
throw new Exception("Failed to install Unity Editor");
|
|
}
|
|
|
|
Information("Downloading IL2CPP support...");
|
|
DownloadFile(il2cppSupportDownloadUrl, "./UnityIl2CppSupport.exe");
|
|
Information("Installing IL2CPP support...");
|
|
result = StartProcess("./UnityIl2CppSupport.exe", " /S");
|
|
if (result != 0)
|
|
{
|
|
throw new Exception("Failed to install IL2CPP support");
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
// Downloading UWP IL2CPP dependencies.
|
|
Task ("Externals-Uwp-IL2CPP-Dependencies")
|
|
.Does (() => {
|
|
var targetPath = "Assets/AppCenter/Plugins/WSA/IL2CPP";
|
|
EnsureDirectoryExists (targetPath);
|
|
EnsureDirectoryExists (targetPath + "/ARM");
|
|
EnsureDirectoryExists (targetPath + "/X86");
|
|
EnsureDirectoryExists (targetPath + "/X64");
|
|
|
|
// NuGet.Core support only v2.
|
|
var packageSource = "https://www.nuget.org/api/v2/";
|
|
var repository = PackageRepositoryFactory.Default.CreateRepository (packageSource);
|
|
foreach (var i in UwpIL2CPPDependencies) {
|
|
var frameworkName = new FrameworkName (i.Framework);
|
|
var package = repository.FindPackage (i.Name, SemanticVersion.Parse (i.Version));
|
|
IEnumerable<IPackage> dependencies;
|
|
if (i.IncludeDependencies) {
|
|
dependencies = GetNuGetDependencies (repository, frameworkName, package);
|
|
} else {
|
|
dependencies = new [] { package };
|
|
}
|
|
var fileSystem = new PhysicalFileSystem (Environment.CurrentDirectory);
|
|
foreach (var depPackage in dependencies) {
|
|
Information ("Extract NuGet package: " + depPackage);
|
|
|
|
// Extract.
|
|
var path = "externals/uwp/" + depPackage.Id;
|
|
depPackage.ExtractContents (fileSystem, path);
|
|
|
|
ExtractNuGetPackage (depPackage, frameworkName, path, targetPath);
|
|
}
|
|
}
|
|
|
|
// Download patched Newtonsoft.Json library to avoid Unity issue.
|
|
// Details: https://forum.unity3d.com/threads/332335/
|
|
DownloadFile (UwpIL2CPPJsonUrl, targetPath + "/Newtonsoft.Json.dll");
|
|
|
|
// Process UWP IL2CPP dependencies.
|
|
Information ("Processing UWP IL2CPP dependencies. This could take a minute.");
|
|
ExecuteUnityCommand ("-executeMethod AppCenterPostBuild.ProcessUwpIl2CppDependencies");
|
|
}).OnError (HandleError);
|
|
|
|
// Download and install all external Unity packages required.
|
|
Task("Externals-Unity-Packages").Does(()=>
|
|
{
|
|
var directoryPath = new DirectoryPath("externals/unity-packages");
|
|
CleanDirectory(directoryPath);
|
|
foreach (var package in ExternalUnityPackages)
|
|
{
|
|
var destination = directoryPath.CombineWithFilePath(package.Name);
|
|
DownloadFile(package.Url, destination);
|
|
Information("Importing package " + package.Name + ". This could take a minute.");
|
|
var command = package.AdditionalImportArgs + " -importPackage " + destination.FullPath;
|
|
ExecuteUnityCommand(command);
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
// Add App Center packages to demo app.
|
|
Task("AddPackagesToDemoApp")
|
|
.IsDependentOn("CreatePackages")
|
|
.Does(()=>
|
|
{
|
|
var specFiles = GetFiles("UnityPackageSpecs/*.unitypackagespec");
|
|
foreach (var spec in specFiles)
|
|
{
|
|
Information("Add files from " + spec);
|
|
var package = new UnityPackage(spec.FullPath);
|
|
package.CopyFiles("AppCenterDemoApp");
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
// Remove package files from demo app.
|
|
Task("RemovePackagesFromDemoApp").Does(()=>
|
|
{
|
|
DeleteDirectoryIfExists("AppCenterDemoApp/Assets/AppCenter");
|
|
DeleteDirectoryIfExists("AppCenterDemoApp/Assets/Plugins");
|
|
}).OnError(HandleError);
|
|
|
|
// Create a common externals task depending on platform specific ones
|
|
// NOTE: It is important to execute Externals-Uwp-IL2CPP-Dependencies *last*
|
|
// or steps that run Unity commands might cause the *.meta files to be deleted!
|
|
// (Unity deletes meta data files when it is opened if the corresponding files are not on disk.)
|
|
Task("Externals")
|
|
.IsDependentOn("Externals-Uwp")
|
|
.IsDependentOn("Externals-Ios")
|
|
.IsDependentOn("Externals-Android")
|
|
.IsDependentOn("BuildAndroidContentProvider")
|
|
.IsDependentOn("Externals-Uwp-IL2CPP-Dependencies")
|
|
.IsDependentOn("Externals-Unity-Packages")
|
|
.Does(()=>
|
|
{
|
|
DeleteDirectoryIfExists("externals");
|
|
});
|
|
|
|
// Creates Unity packages corresponding to all ".unitypackagespec" files
|
|
// in "UnityPackageSpecs" folder.
|
|
Task("Package").Does(()=>
|
|
{
|
|
// Remove AndroidManifest.xml
|
|
var path = "Assets/Plugins/Android/appcenter/AndroidManifest.xml";
|
|
if (System.IO.File.Exists(path))
|
|
{
|
|
DeleteFile(path);
|
|
}
|
|
|
|
// Store packages in a clean folder.
|
|
const string outputDirectory = "output";
|
|
CleanDirectory(outputDirectory);
|
|
var specFiles = GetFiles("UnityPackageSpecs/*.unitypackagespec");
|
|
foreach (var spec in specFiles)
|
|
{
|
|
var package = new UnityPackage(spec.FullPath);
|
|
package.CreatePackage(outputDirectory);
|
|
}
|
|
});
|
|
|
|
Task("PrepareAssets").IsDependentOn("Externals");
|
|
|
|
// Creates Unity packages corresponding to all ".unitypackagespec" files
|
|
// in "UnityPackageSpecs" folder (and downloads binaries)
|
|
Task("CreatePackages").IsDependentOn("PrepareAssets").IsDependentOn("Package");
|
|
|
|
// Builds the puppet applications and throws an exception on failure.
|
|
Task("BuildPuppetApps")
|
|
.IsDependentOn("PrepareAssets")
|
|
.Does(()=>
|
|
{
|
|
BuildApps("Puppet");
|
|
}).OnError(HandleError);
|
|
|
|
// Builds the demo applications and throws an exception on failure.
|
|
Task("BuildDemoApps")
|
|
.IsDependentOn("AddPackagesToDemoApp")
|
|
.Does(()=>
|
|
{
|
|
BuildApps("Demo", "AppCenterDemoApp");
|
|
}).OnError(HandleError);
|
|
|
|
// Downloads the NDK from the specified location.
|
|
Task("DownloadNdk")
|
|
.Does(()=>
|
|
{
|
|
var ndkUrl = EnvironmentVariable("ANDROID_NDK_URL");
|
|
if (string.IsNullOrEmpty(ndkUrl))
|
|
{
|
|
throw new Exception("Ndk Url is empty string or null");
|
|
}
|
|
var zipDestination = Statics.TemporaryPrefix + "ndk.zip";
|
|
|
|
// Download required NDK
|
|
DownloadFile(ndkUrl, zipDestination);
|
|
|
|
// Something is buggy about the way Cake unzips, so use shell on mac
|
|
if (IsRunningOnUnix())
|
|
{
|
|
CleanDirectory(NdkFolder);
|
|
StartProcess("unzip", new ProcessSettings{ Arguments = $"{zipDestination} -d {NdkFolder}"});
|
|
}
|
|
else
|
|
{
|
|
Unzip(zipDestination, NdkFolder);
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
void GetUwpPackage (AppCenterModule module, bool usePublicFeed) {
|
|
// Prepare destination
|
|
var destination = "Assets/AppCenter/Plugins/WSA/" + module.Moniker + "/";
|
|
EnsureDirectoryExists (destination);
|
|
DeleteFiles (destination + "*.dll");
|
|
DeleteFiles (destination + "*.winmd");
|
|
var nupkgPath = "externals/uwp/";
|
|
if (usePublicFeed) {
|
|
var packageSource = "https://www.nuget.org/api/v2/";
|
|
var repository = PackageRepositoryFactory.Default.CreateRepository (packageSource);
|
|
|
|
var package = repository.FindPackage (module.DotNetModule, SemanticVersion.Parse (UwpSdkVersion));
|
|
IEnumerable<IPackage> dependencies = new [] { package };
|
|
var fileSystem = new PhysicalFileSystem (Environment.CurrentDirectory);
|
|
foreach (var depPackage in dependencies) {
|
|
Information ("Extract NuGet package: " + depPackage);
|
|
// Extract.
|
|
nupkgPath = "externals/uwp/" + depPackage.Id + "/";
|
|
depPackage.ExtractContents (fileSystem, nupkgPath);
|
|
|
|
// Move assemblies.
|
|
ExtractNuGetPackage (depPackage, new FrameworkName ("UAP, Version=v10.0"), nupkgPath, destination);
|
|
// Delete the package
|
|
DeleteFiles (nupkgPath);
|
|
}
|
|
} else {
|
|
nupkgPath = GetNuGetPackage (module.DotNetModule, UwpSdkVersion);
|
|
var tempContentPath = "externals/uwp/" + module.Moniker + "/";
|
|
DeleteDirectoryIfExists (tempContentPath);
|
|
// Unzip into externals/uwp/
|
|
Unzip (nupkgPath, tempContentPath);
|
|
ExtractNuGetPackage (null, new FrameworkName ("UAP, Version=v10.0"), tempContentPath, destination);
|
|
// Delete the package
|
|
DeleteFiles (nupkgPath);
|
|
}
|
|
}
|
|
|
|
void BuildApps(string type, string projectPath = ".")
|
|
{
|
|
if (Statics.Context.IsRunningOnUnix())
|
|
{
|
|
VerifyIosAppsBuild(type, projectPath);
|
|
VerifyAndroidAppsBuild(type, projectPath);
|
|
}
|
|
else
|
|
{
|
|
VerifyWindowsAppsBuild(type, projectPath);
|
|
}
|
|
}
|
|
|
|
void VerifyIosAppsBuild(string type, string projectPath)
|
|
{
|
|
VerifyAppsBuild(type, "ios", projectPath,
|
|
new string[] { "IosMono", "IosIl2CPP" },
|
|
outputDirectory =>
|
|
{
|
|
var directories = GetDirectories(outputDirectory + "/*/*.xcodeproj");
|
|
if (directories.Count == 0)
|
|
{
|
|
throw new Exception("No ios projects found in directory '" + outputDirectory + "'");
|
|
}
|
|
var xcodeProjectPath = directories.Single();
|
|
Statics.Context.Information("Attempting to build '" + xcodeProjectPath.FullPath + "'...");
|
|
BuildXcodeProject(xcodeProjectPath.FullPath);
|
|
Statics.Context.Information("Successfully built '" + xcodeProjectPath.FullPath + "'");
|
|
});
|
|
}
|
|
|
|
void VerifyAndroidAppsBuild(string type, string projectPath)
|
|
{
|
|
var extraArgs = "";
|
|
if (DirectoryExists(NdkFolder))
|
|
{
|
|
var absoluteNdkFolder = Statics.Context.MakeAbsolute(Statics.Context.Directory(NdkFolder));
|
|
extraArgs += "-NdkLocation \"" + absoluteNdkFolder + "\"";
|
|
}
|
|
VerifyAppsBuild(type, "android", projectPath,
|
|
new string[] { "AndroidMono", "AndroidIl2CPP" },
|
|
outputDirectory =>
|
|
{
|
|
// Verify that an APK was generated.
|
|
if (Statics.Context.GetFiles(outputDirectory + "/*.apk").Count == 0)
|
|
{
|
|
throw new Exception("No apk found in directory '" + outputDirectory + "'");
|
|
}
|
|
Statics.Context.Information("Found apk.");
|
|
}, extraArgs);
|
|
}
|
|
|
|
void VerifyWindowsAppsBuild(string type, string projectPath)
|
|
{
|
|
VerifyAppsBuild(type, "wsaplayer", projectPath,
|
|
new string[] { "WsaIl2CPPD3D" },
|
|
outputDirectory =>
|
|
{
|
|
Statics.Context.Information("Verifying app build in directory: " + outputDirectory);
|
|
var slnFiles = GetFiles(outputDirectory + "/*/*.sln");
|
|
if (slnFiles.Count() == 0)
|
|
{
|
|
throw new Exception("No .sln files found in the following directory and all it's subdirectories: " + outputDirectory);
|
|
}
|
|
if (slnFiles.Count() > 1)
|
|
{
|
|
throw new Exception(string.Format("Multiple .sln files found in directory {0}: {1}", outputDirectory, string.Join(", ", slnFiles)));
|
|
}
|
|
var solutionFilePath = slnFiles.Single();
|
|
Statics.Context.Information("Attempting to build '" + solutionFilePath.ToString() + "'...");
|
|
Statics.Context.MSBuild(solutionFilePath.ToString(), c => c
|
|
.SetConfiguration("Master")
|
|
.WithProperty("Platform", "x86")
|
|
.SetVerbosity(Verbosity.Minimal)
|
|
.SetMSBuildPlatform(MSBuildPlatform.x86));
|
|
Statics.Context.Information("Successfully built '" + solutionFilePath.ToString() + "'");
|
|
});
|
|
}
|
|
|
|
void VerifyAppsBuild(string type, string platformIdentifier, string projectPath, string[] buildTypes, Action<string> verificatonMethod, string extraArgs = "")
|
|
{
|
|
var outputDirectory = GetBuildFolder(type, projectPath);
|
|
var methodPrefix = "Build" + type + ".Build" + type + "Scene";
|
|
foreach (var buildType in buildTypes)
|
|
{
|
|
// Remove all existing builds and create new build.
|
|
Statics.Context.CleanDirectory(outputDirectory);
|
|
ExecuteUnityMethod(methodPrefix + buildType + " " + extraArgs, platformIdentifier);
|
|
verificatonMethod(outputDirectory);
|
|
|
|
// Remove all remaining builds.
|
|
Statics.Context.CleanDirectory(outputDirectory);
|
|
}
|
|
|
|
// Remove all remaining builds.
|
|
Statics.Context.CleanDirectory(outputDirectory);
|
|
}
|
|
|
|
Task("PublishPackagesToStorage").Does(()=>
|
|
{
|
|
// The environment variables below must be set for this task to succeed
|
|
var apiKey = Argument("AzureStorageAccessKey", EnvironmentVariable("AZURE_STORAGE_ACCESS_KEY"));
|
|
var accountName = EnvironmentVariable("AZURE_STORAGE_ACCOUNT");
|
|
var corePackageVersion = XmlPeek(File("UnityPackageSpecs/AppCenter.unitypackagespec"), "package/@version");
|
|
var zippedPackages = "AppCenter-SDK-Unity-" + corePackageVersion + ".zip";
|
|
var files = GetFiles("output/*.unitypackage");
|
|
Zip("./", zippedPackages, files);
|
|
Information("Publishing packages to blob storage: " + zippedPackages);
|
|
AzureStorage.UploadFileToBlob(new AzureStorageSettings
|
|
{
|
|
AccountName = accountName,
|
|
ContainerName = "sdk",
|
|
BlobName = zippedPackages,
|
|
Key = apiKey,
|
|
UseHttps = true
|
|
}, zippedPackages);
|
|
DeleteFiles(zippedPackages);
|
|
foreach (var package in GetBuiltPackages())
|
|
{
|
|
Information("Publishing packages to blob storage: " + package);
|
|
var fileName = System.IO.Path.GetFileNameWithoutExtension(package); // AppCenterAnalytics-v1.0.0
|
|
var index = fileName.IndexOf('-'); // 18
|
|
var fileNameLatest = fileName.Substring(0, index) + "Latest.unitypackage"; // AppCenterAnalyticsLatest.unitypackage
|
|
AzureStorage.UploadFileToBlob(new AzureStorageSettings
|
|
{
|
|
AccountName = accountName,
|
|
ContainerName = "sdk",
|
|
BlobName = fileNameLatest,
|
|
Key = apiKey,
|
|
UseHttps = true
|
|
}, package);
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
Task("RegisterUnity").Does(()=>
|
|
{
|
|
var serialNumber = Argument<string>("UnitySerialNumber");
|
|
var username = Argument<string>("UnityUsername");
|
|
var password = Argument<string>("UnityPassword");
|
|
|
|
// This will produce an error, but that's okay because the project "noproject" is used so that the
|
|
// root isn't opened by unity, which could potentially remove important .meta files.
|
|
ExecuteUnityCommand($"-serial {serialNumber} -username {username} -password {password}", "noproject");
|
|
var found = false;
|
|
if (Statics.Context.IsRunningOnUnix())
|
|
{
|
|
found = GetFiles("/Library/Application Support/Unity/*.ulf").Count > 0;
|
|
} else {
|
|
var localAppDataUnityPath = System.IO.Path.Combine(EnvironmentVariable("LOCALAPPDATA"), @"VirtualStore\ProgramData\Unity\*.ulf");
|
|
found = GetFiles(localAppDataUnityPath).Count + GetFiles(System.IO.Path.Combine(EnvironmentVariable("PROGRAMDATA"), @"Unity\*.ulf")).Count > 0;
|
|
}
|
|
if (!found)
|
|
{
|
|
throw new Exception("Failed to activate license.");
|
|
}
|
|
}).OnError(HandleError);
|
|
|
|
Task("UnregisterUnity").Does(()=>
|
|
{
|
|
ExecuteUnityCommand("-returnLicense", null);
|
|
}).OnError(HandleError);
|
|
|
|
|
|
// Default Task.
|
|
Task("Default").IsDependentOn("PrepareAssets");
|
|
|
|
// Clean up files/directories.
|
|
Task("clean")
|
|
.IsDependentOn("RemoveTemporaries")
|
|
.Does(() =>
|
|
{
|
|
DeleteDirectoryIfExists("externals");
|
|
DeleteDirectoryIfExists("output");
|
|
CleanDirectories("./**/bin");
|
|
CleanDirectories("./**/obj");
|
|
});
|
|
|
|
string GetNuGetPackage(string packageId, string packageVersion)
|
|
{
|
|
var nugetUser = EnvironmentVariable("NUGET_USER");
|
|
var nugetPassword = Argument("NuGetPassword", EnvironmentVariable("NUGET_PASSWORD"));
|
|
var nugetFeedId = Argument("NuGetFeedId", EnvironmentVariable("NUGET_FEED_ID"));
|
|
packageId = packageId.ToLower();
|
|
|
|
var url = "https://msmobilecenter.pkgs.visualstudio.com/_packaging/";
|
|
url += nugetFeedId + "/nuget/v3/flat2/" + packageId + "/" + packageVersion + "/" + packageId + "." + packageVersion + ".nupkg";
|
|
|
|
// Get the NuGet package
|
|
HttpWebRequest request = (HttpWebRequest)WebRequest.Create (url);
|
|
request.Headers["X-NuGet-ApiKey"] = nugetPassword;
|
|
request.Credentials = new NetworkCredential(nugetUser, nugetPassword);
|
|
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
|
var responseString = String.Empty;
|
|
var filename = packageId + "." + packageVersion + ".nupkg";
|
|
using (var fstream = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite))
|
|
{
|
|
response.GetResponseStream().CopyTo(fstream);
|
|
}
|
|
return filename;
|
|
}
|
|
|
|
void ExtractNuGetPackage (IPackage package, FrameworkName frameworkName, string tempContentPath, string destination) {
|
|
if (package != null) {
|
|
IEnumerable<IPackageAssemblyReference> assemblies;
|
|
VersionUtility.TryGetCompatibleItems (frameworkName, package.AssemblyReferences, out assemblies);
|
|
|
|
// Move assemblies.
|
|
foreach (var i in assemblies) {
|
|
if (!FileExists (destination + "/" + i.Name)) {
|
|
MoveFile (tempContentPath + "/" + i.Path, destination + "/" + i.Name);
|
|
}
|
|
}
|
|
|
|
}
|
|
// Move native binaries.
|
|
var contentPathSuffix = "lib/uap10.0/";
|
|
var runtimesPath = tempContentPath + "/runtimes";
|
|
if (DirectoryExists (runtimesPath)) {
|
|
var oneArch = "x86";
|
|
foreach (var runtime in GetDirectories (runtimesPath + "/win10-*")) {
|
|
var arch = runtime.GetDirectoryName ().ToString ().Replace ("win10-", "").ToUpper ();
|
|
oneArch = arch;
|
|
var nativeFiles = GetFiles (runtime + "/native/*");
|
|
var targetArchPath = destination + "/" + arch;
|
|
EnsureDirectoryExists (targetArchPath);
|
|
foreach (var nativeFile in nativeFiles) {
|
|
if (!FileExists (targetArchPath + "/" + nativeFile.GetFilename ())) {
|
|
MoveFileToDirectory (nativeFile, targetArchPath);
|
|
}
|
|
}
|
|
}
|
|
contentPathSuffix = "runtimes/win10-" + oneArch + "/" + contentPathSuffix;
|
|
}
|
|
|
|
if (package == null) {
|
|
var files = GetFiles (tempContentPath + contentPathSuffix + "*");
|
|
MoveFiles (files, destination);
|
|
}
|
|
}
|
|
|
|
IList<IPackage> GetNuGetDependencies(IPackageRepository repository, FrameworkName frameworkName, IPackage package)
|
|
{
|
|
var dependencies = new List<IPackage>();
|
|
GetNuGetDependencies(dependencies, repository, frameworkName, package);
|
|
return dependencies;
|
|
}
|
|
|
|
void GetNuGetDependencies(IList<IPackage> dependencies, IPackageRepository repository, FrameworkName frameworkName, IPackage package)
|
|
{
|
|
// Declaring this outside the method causes a parse error on Cake for Mac.
|
|
string[] IgnoreNuGetDependencies = {
|
|
"Microsoft.NETCore.UniversalWindowsPlatform",
|
|
"NETStandard.Library"
|
|
};
|
|
|
|
dependencies.Add(package);
|
|
foreach (var dependency in package.GetCompatiblePackageDependencies(frameworkName))
|
|
{
|
|
if (IgnoreNuGetDependencies.Contains(dependency.Id))
|
|
{
|
|
continue;
|
|
}
|
|
var subPackage = repository.ResolveDependency(dependency, false, true);
|
|
if (!dependencies.Contains(subPackage))
|
|
{
|
|
GetNuGetDependencies(dependencies, repository, frameworkName, subPackage);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BuildXcodeProject(string projectPath)
|
|
{
|
|
var projectFolder = System.IO.Path.GetDirectoryName(projectPath);
|
|
var buildOutputFolder = System.IO.Path.Combine(projectFolder, "build");
|
|
XCodeBuild(new XCodeBuildSettings {
|
|
Project = projectPath,
|
|
Scheme = "Unity-iPhone",
|
|
Configuration = "Release",
|
|
DerivedDataPath = buildOutputFolder
|
|
});
|
|
}
|
|
|
|
RunTarget(Target);
|