Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ crashlytics-build.properties
chaintest.out
TestResults_Edit.xml
TestResults_Play.xml
Builds/
PlatformCompileTestErrors/

# Temporary test files
Assets/InitTestScene*.unity*
Expand Down
8 changes: 8 additions & 0 deletions Assets/Plugins/Android/gradleTemplate.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
android.enableJetifier=true
android.useAndroidX=true
unityStreamingAssets=**STREAMING_ASSETS**
**ADDITIONAL_PROPERTIES**

android.enableR8=**MINIFY_WITH_R_EIGHT**

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions Assets/Plugins/Android/mainTemplate.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
apply plugin: 'com.android.library'
**APPLY_PLUGINS**

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.security:security-crypto:1.1.0-alpha03'

**DEPS**}

android {
compileSdkVersion **APIVERSION**
buildToolsVersion '**BUILDTOOLS**'

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
minSdkVersion **MINSDKVERSION**
targetSdkVersion **TARGETSDKVERSION**
ndk {
abiFilters **ABIFILTERS**
}
versionCode **VERSIONCODE**
versionName '**VERSIONNAME**'
consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
}

lintOptions {
abortOnError false
}

aaptOptions {
noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
}**PACKAGING_OPTIONS**
}**REPOSITORIES**
**IL_CPP_BUILD_SETUP**
**SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**
7 changes: 7 additions & 0 deletions Assets/Plugins/Android/mainTemplate.gradle.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Assets/SequenceSDK/Editor.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

182 changes: 182 additions & 0 deletions Assets/SequenceSDK/Editor/SequencePlatformCompileTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using NUnit.Framework;
using Sequence.Config;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

namespace Sequence.Editor
{
/// <summary>
/// This test will build the project for all platforms and check if the build is compiled successfully
/// </summary>
public static class SequencePlatformCompileTest
{
private const string BuildDirectory = "Builds";
private static List<string> _failedBuilds;

[MenuItem("Sequence Dev/Platform Compile Test")]
public static void RunBuildTest()
{
BigInteger startEpochTime = new BigInteger(DateTimeOffset.Now.ToUnixTimeSeconds());
ClearPreviousErrors();

string[] scenes = GetEnabledScenes();

#if UNITY_EDITOR_WIN
BuildPlatform(BuildTarget.StandaloneWindows64, $"{BuildDirectory}/WindowsBuild", scenes);
#endif
#if UNITY_EDITOR_OSX
BuildPlatform(BuildTarget.StandaloneOSX, $"{BuildDirectory}/MacOSBuild", scenes);
BuildPlatform(BuildTarget.iOS, $"{BuildDirectory}/iOSBuild", scenes);
#endif
BuildPlatform(BuildTarget.WebGL, $"{BuildDirectory}/WebGLBuild", scenes);
AndroidBuildTest($"{BuildDirectory}/AndroidBuild", scenes);

Debug.Log("Platform Compile Test Completed. Check the console for errors.");
foreach (var failedBuild in _failedBuilds)
{
Debug.LogError(failedBuild);
}

BigInteger endEpochTime = new BigInteger(DateTimeOffset.Now.ToUnixTimeSeconds());
Debug.Log($"Total Test Time: {endEpochTime - startEpochTime} seconds");
}

private static void ClearPreviousErrors()
{
_failedBuilds = new List<string>();

string errorDirectory = "PlatformCompileTestErrors";
if (Directory.Exists(errorDirectory))
{
var txtFiles = Directory.GetFiles(errorDirectory, "*.txt");
foreach (var file in txtFiles)
{
File.Delete(file);
}
}
else
{
Directory.CreateDirectory(errorDirectory);
}
}

private static string[] GetEnabledScenes()
{
return EditorBuildSettings.scenes
.Where(scene => scene.enabled)
.Select(scene => scene.path)
.ToArray();
}

private static void BuildPlatform(BuildTarget target, string path, string[] scenes)
{
try
{
BuildToPlatformAndCheckForSuccess(target, path, scenes);
}
finally
{
CleanupBuildDirectory();
}
}

private static void BuildToPlatformAndCheckForSuccess(BuildTarget target, string path, string[] scenes)
{
BuildReport report = BuildPipeline.BuildPlayer(scenes, path, target, BuildOptions.None);

if (report.summary.result != BuildResult.Succeeded)
{
_failedBuilds.Add($"{target} build failed with {report.summary.totalErrors} errors. Please see {BuildDirectory}/{target}.txt for details.");
LogErrorsToFile(report, target);
}
}

private static void CleanupBuildDirectory()
{
if (Directory.Exists(BuildDirectory))
{
Directory.Delete(BuildDirectory, true);
}
}

private static void LogErrorsToFile(BuildReport report, BuildTarget target)
{
string errorDirectory = "PlatformCompileTestErrors";
if (!Directory.Exists(errorDirectory))
{
Directory.CreateDirectory(errorDirectory);
}

string errorFilePath = Path.Combine(errorDirectory, $"{target}.txt");

using (StreamWriter writer = new StreamWriter(errorFilePath, false))
{
writer.WriteLine($"Build Time: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
writer.WriteLine($"Platform: {target}");
writer.WriteLine($"Build Errors Summary:");
writer.WriteLine($"Total Errors: {report.summary.totalErrors}");
writer.WriteLine();
writer.WriteLine("Detailed Errors:");

foreach (var step in report.steps)
{
foreach (var message in step.messages)
{
if (message.type == LogType.Error)
{
writer.WriteLine($"[{message.type}] {message.content}");
}
}
}
}
}

private static void AndroidBuildTest(string path, string[] scenes)
{
SequenceConfig config = SequenceConfig.GetConfig();
bool isSecureStorageEnabled = config.StoreSessionPrivateKeyInSecureStorage;
BuildTarget target = BuildTarget.Android;

try
{
BuildToPlatformAndCheckForSuccess(target, path, scenes);

AssertPluginCompatibility(config, target);
AssertAppropriateScriptingDefines(config, target);

config.StoreSessionPrivateKeyInSecureStorage = !config.StoreSessionPrivateKeyInSecureStorage;

BuildToPlatformAndCheckForSuccess(target, path, scenes);

AssertPluginCompatibility(config, target);
AssertAppropriateScriptingDefines(config, target);
}
finally
{
config.StoreSessionPrivateKeyInSecureStorage = isSecureStorageEnabled;

CleanupBuildDirectory();
}
}

private static void AssertPluginCompatibility(SequenceConfig config, BuildTarget target)
{
PluginImporter pluginImporter = AssetImporter.GetAtPath(AndroidDependencyManager.SecureStoragePluginPath) as PluginImporter;
Assert.IsNotNull(pluginImporter, "Plugin not found at path: " + AndroidDependencyManager.SecureStoragePluginPath);
Assert.AreEqual(config.StoreSessionPrivateKeyInSecureStorage, pluginImporter.GetCompatibleWithPlatform(target));
}

private static void AssertAppropriateScriptingDefines(SequenceConfig config, BuildTarget target)
{
string defines = PlayerSettings.GetScriptingDefineSymbols(NamedBuildTarget.FromBuildTargetGroup(BuildPipeline.GetBuildTargetGroup(target)));
Assert.AreEqual(config.StoreSessionPrivateKeyInSecureStorage, defines.Contains(AndroidScriptDefineSetup.EnableAndroidSecureStorage));
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

127 changes: 127 additions & 0 deletions Packages/Sequence-Unity/Editor/AndroidCustomGradleCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Sequence.Config;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor;
using UnityEngine;

namespace Sequence.Editor
{
public class AndroidCustomGradleCheck : IPreprocessBuildWithReport
{
public int callbackOrder => 0;

private static List<string> _cachedWarnings;

private const string _docsUrl = "https://docs.sequence.xyz/sdk/unity/recovering-sessions#android";

public void OnPreprocessBuild(BuildReport report)
{
if (report.summary.platform == BuildTarget.Android)
{
SequenceConfig config = SequenceConfig.GetConfig();
if (!config.StoreSessionPrivateKeyInSecureStorage)
{
return;
}

List<string> warnings = new List<string>();

if (!IsCustomGradlePropertiesTemplateEnabled())
{
warnings.Add(
"Sequence - Custom Gradle Properties Template is not enabled. This may cause issues with secure storage on Android. Refer to: " + _docsUrl);
}

if (!IsCustomMainGradleTemplateEnabled())
{
warnings.Add(
"Sequence - Custom Main Gradle Template is not enabled. This may cause issues with secure storage on Android. Refer to: " + _docsUrl);
}

foreach (var warning in warnings)
{
Debug.LogWarning(warning);
}

if (warnings.Count > 0)
{
WarningPopup.ShowWindow(warnings);
}
}
}

private bool IsCustomGradlePropertiesTemplateEnabled()
{
return GetProjectSettingsFlag("useCustomGradlePropertiesTemplate");
}

private bool IsCustomMainGradleTemplateEnabled()
{
return GetProjectSettingsFlag("useCustomMainGradleTemplate");
}

private bool GetProjectSettingsFlag(string key)
{
string projectSettingsPath = Path.Combine(Application.dataPath, "../ProjectSettings/ProjectSettings.asset");

if (!File.Exists(projectSettingsPath))
{
Debug.LogError("ProjectSettings.asset file not found.");
return false;
}

var lines = File.ReadAllLines(projectSettingsPath);
foreach (var line in lines)
{
if (line.Trim().StartsWith(key + ":"))
{
return line.Trim().EndsWith("1");
}
}

return false;
}

private class WarningPopup : EditorWindow
{
private static List<string> warnings;

public static void ShowWindow(List<string> warningsToShow)
{
if (warningsToShow == null || warningsToShow.Count == 0)
{
return;
}
warnings = warningsToShow;
var window = GetWindow<WarningPopup>("Sequence Build Warnings");
window.position = new Rect(Screen.width / 2, Screen.height / 2, 400, 200);
window.Show();
}

private void OnGUI()
{
GUILayout.Label("Warnings Detected", EditorStyles.boldLabel);

foreach (string warning in warnings)
{
EditorGUILayout.HelpBox(warning, MessageType.Warning);

if (GUILayout.Button("Learn More", GUILayout.Width(100)))
{
Application.OpenURL(_docsUrl);
}
}

GUILayout.FlexibleSpace();

if (GUILayout.Button("Dismiss", GUILayout.Height(30)))
{
Close();
}
}
}
}
}
Loading
Loading