From af619c29310ece481a80b9d0597fe5371ff6979c Mon Sep 17 00:00:00 2001 From: Harrison Hough Date: Tue, 5 Sep 2023 09:12:58 +0300 Subject: [PATCH 1/6] [SDK-348] chore: added URL tests and renamed fields (#20) - Small cleanup and added extra tests --- .github/workflows/pr-test-runner.yml | 57 ++++++++++++++++++++++++++++ Tests/Editor/UrlConfigTests.cs | 51 +++++++++++++++++-------- 2 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/pr-test-runner.yml diff --git a/.github/workflows/pr-test-runner.yml b/.github/workflows/pr-test-runner.yml new file mode 100644 index 0000000..c18632e --- /dev/null +++ b/.github/workflows/pr-test-runner.yml @@ -0,0 +1,57 @@ +name: Run Tests + +on: + pull_request: + types: [ opened, reopened ] + workflow_dispatch: + +jobs: + runAllTests: + name: ${{ matrix.unityVersion }} ${{ matrix.testMode }} tests + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + testMode: + - playmode + - editmode + unityVersion: + - 2020.3.0f1 + steps: + - name: Checkout Unity-SDK Repository + uses: actions/checkout@v3 + with: + repository: "readyplayerme/Unity-SDK" + submodules: true + fetch-depth: 0 + ref: develop + token: ${{ secrets.DEV_SDK_TOKEN }} + + - name: Checkout submodule branch + run: | + cd Assets/Ready\ Player\ Me/WebView + git fetch -a + git checkout ${{ github.event.pull_request.head.ref }} + git pull origin ${{ github.event.pull_request.head.ref }} + - name: Cache Project + uses: actions/cache@v3 + with: + path: Library + key: Library-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }} + restore-keys: | + Library- + + - name: Run Tests + uses: game-ci/unity-test-runner@v2 + env: + UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} + UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} + UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }} + with: + unityVersion: ${{ matrix.unityVersion }} + testMode: ${{ matrix.testMode }} + projectPath: ${{ matrix.projectPath }} + checkName: ${{ matrix.unityVersion }} ${{ matrix.testMode }} tests result + githubToken: ${{ secrets.GITHUB_TOKEN }} + coverageOptions: "generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:+my.assembly.*" diff --git a/Tests/Editor/UrlConfigTests.cs b/Tests/Editor/UrlConfigTests.cs index 56019db..e1e65a9 100644 --- a/Tests/Editor/UrlConfigTests.cs +++ b/Tests/Editor/UrlConfigTests.cs @@ -5,18 +5,21 @@ namespace ReadyPlayerMe.WebView.Tests { public class UrlConfigTests : MonoBehaviour { - private const string LANG_GERMAN = "https://demo.readyplayer.me/de/avatar?frameApi&selectBodyType"; - private const string LANG_BRAZIL = "https://demo.readyplayer.me/pt-BR/avatar?frameApi&selectBodyType"; + private const string URL_DEFAULT = "https://demo.readyplayer.me/avatar?frameApi&selectBodyType"; + private const string URL_LANG_GERMAN = "https://demo.readyplayer.me/de/avatar?frameApi&selectBodyType"; + private const string URL_LANG_BRAZIL = "https://demo.readyplayer.me/pt-BR/avatar?frameApi&selectBodyType"; - private const string GENDER_MALE = "https://demo.readyplayer.me/avatar?frameApi&gender=male&selectBodyType"; - private const string GENDER_NONE = "https://demo.readyplayer.me/avatar?frameApi&gender=male&selectBodyType"; + private const string URL_GENDER_MALE = "https://demo.readyplayer.me/avatar?frameApi&gender=male&selectBodyType"; + private const string URL_GENDER_NONE = "https://demo.readyplayer.me/avatar?frameApi&gender=male&selectBodyType"; - private const string TYPE_FULLBODY = "https://demo.readyplayer.me/avatar?frameApi&bodyType=fullbody"; - private const string TYPE_HALFBODY = "https://demo.readyplayer.me/avatar?frameApi&bodyType=halfbody"; + private const string URL_TYPE_FULLBODY = "https://demo.readyplayer.me/avatar?frameApi&bodyType=fullbody"; + private const string URL_TYPE_HALFBODY = "https://demo.readyplayer.me/avatar?frameApi&bodyType=halfbody"; - private const string CLEAR_CACHE = "https://demo.readyplayer.me/avatar?frameApi&clearCache&selectBodyType"; + private const string URL_CLEAR_CACHE = "https://demo.readyplayer.me/avatar?frameApi&clearCache&selectBodyType"; - private const string QUICK_START = "https://demo.readyplayer.me/avatar?frameApi&quickStart"; + private const string URL_QUICK_START = "https://demo.readyplayer.me/avatar?frameApi&quickStart"; + private const string URL_TOKEN = "https://demo.readyplayer.me/avatar?frameApi&token=TOKEN&selectBodyType"; + private const string LOGIN_TOKEN = "TOKEN"; public UrlConfig config; @@ -31,7 +34,7 @@ public void Url_Name_Change_German() { config.language = Language.German; var res = config.BuildUrl(); - Assert.AreEqual(LANG_GERMAN, res); + Assert.AreEqual(URL_LANG_GERMAN, res); } [Test] @@ -39,7 +42,7 @@ public void Url_Name_Change_Brazil() { config.language = Language.PortugueseBrazil; var res = config.BuildUrl(); - Assert.AreEqual(LANG_BRAZIL, res); + Assert.AreEqual(URL_LANG_BRAZIL, res); } [Test] @@ -47,7 +50,7 @@ public void Url_Gender_Change_Male() { config.gender = Gender.Male; var res = config.BuildUrl(); - Assert.AreEqual(GENDER_MALE, res); + Assert.AreEqual(URL_GENDER_MALE, res); } [Test] @@ -55,7 +58,7 @@ public void Url_Gender_Change_None() { config.gender = Gender.Male; var res = config.BuildUrl(); - Assert.AreEqual(GENDER_NONE, res); + Assert.AreEqual(URL_GENDER_NONE, res); } [Test] @@ -63,7 +66,7 @@ public void Url_BodyType_Change_Fullbody() { config.bodyType = BodyType.FullBody; var res = config.BuildUrl(); - Assert.AreEqual(TYPE_FULLBODY, res); + Assert.AreEqual(URL_TYPE_FULLBODY, res); } [Test] @@ -71,7 +74,7 @@ public void Url_BodyType_Change_Halfbody() { config.bodyType = BodyType.HalfBody; var res = config.BuildUrl(); - Assert.AreEqual(TYPE_HALFBODY, res); + Assert.AreEqual(URL_TYPE_HALFBODY, res); } [Test] @@ -79,7 +82,7 @@ public void Url_ClearCache_Change() { config.clearCache = true; var res = config.BuildUrl(); - Assert.AreEqual(CLEAR_CACHE, res); + Assert.AreEqual(URL_CLEAR_CACHE, res); } [Test] @@ -87,7 +90,23 @@ public void Url_QuickStart_Change() { config.quickStart = true; var res = config.BuildUrl(); - Assert.AreEqual(QUICK_START, res); + Assert.AreEqual(URL_QUICK_START, res); + } + + [Test] + public void Url_With_Token() + { + var testConfig = new UrlConfig(); + var res = testConfig.BuildUrl(LOGIN_TOKEN); + Assert.AreEqual(URL_TOKEN, res); + } + + [Test] + public void Url_Default() + { + var testConfig = new UrlConfig(); + var res = testConfig.BuildUrl(); + Assert.AreEqual(URL_DEFAULT, res); } } } From bf6be05e53bde7c0695cbcd20f0d39f5fcd1624e Mon Sep 17 00:00:00 2001 From: Harrison Hough Date: Thu, 28 Sep 2023 07:21:45 +0300 Subject: [PATCH 2/6] [SDK-414] feat: extract shared functionality (#21) - moved shared data and classes to Core package - - this is linked to this PR for Core https://github.com/readyplayerme/rpm-unity-sdk-core/pull/125 --- Editor.meta | 8 - Editor/WebViewBuildPostprocessor.cs | 239 ------------------ Editor/WebViewBuildPostprocessor.cs.meta | 11 - Editor/WebViewEditor.cs | 25 -- Editor/WebViewEditor.cs.meta | 11 - Runtime/Data/Enums.cs | 96 ------- Runtime/Data/Enums.cs.meta | 2 +- Runtime/Data/ScreenPadding.cs | 14 - Runtime/Data/ScreenPadding.cs.meta | 11 - Runtime/Data/UrlConfig.cs | 68 ----- Runtime/Data/UrlConfig.cs.meta | 11 - Runtime/Data/WebMessage.cs | 12 - Runtime/Data/WebMessage.cs.meta | 11 - Runtime/MessagePanel.cs | 52 ---- Runtime/MessagePanel.cs.meta | 11 - Runtime/Native/WebViewBase.cs | 1 + Runtime/WebMessageHelper.cs | 38 --- Runtime/WebMessageHelper.cs.meta | 11 - Runtime/WebViewEvents.cs | 23 -- Runtime/WebViewEvents.cs.meta | 11 - Runtime/WebViewPanel.cs | 1 + Tests/Editor.meta | 8 - .../ReadyPlayerMe.WebView.Editor.Tests.asmdef | 22 -- ...yPlayerMe.WebView.Editor.Tests.asmdef.meta | 7 - Tests/Editor/UrlConfigTests.cs | 112 -------- Tests/Editor/UrlConfigTests.cs.meta | 11 - 26 files changed, 3 insertions(+), 824 deletions(-) delete mode 100644 Editor.meta delete mode 100644 Editor/WebViewBuildPostprocessor.cs delete mode 100644 Editor/WebViewBuildPostprocessor.cs.meta delete mode 100644 Editor/WebViewEditor.cs delete mode 100644 Editor/WebViewEditor.cs.meta delete mode 100644 Runtime/Data/ScreenPadding.cs delete mode 100644 Runtime/Data/ScreenPadding.cs.meta delete mode 100644 Runtime/Data/UrlConfig.cs delete mode 100644 Runtime/Data/UrlConfig.cs.meta delete mode 100644 Runtime/Data/WebMessage.cs delete mode 100644 Runtime/Data/WebMessage.cs.meta delete mode 100644 Runtime/MessagePanel.cs delete mode 100644 Runtime/MessagePanel.cs.meta delete mode 100644 Runtime/WebMessageHelper.cs delete mode 100644 Runtime/WebMessageHelper.cs.meta delete mode 100644 Runtime/WebViewEvents.cs delete mode 100644 Runtime/WebViewEvents.cs.meta delete mode 100644 Tests/Editor.meta delete mode 100644 Tests/Editor/ReadyPlayerMe.WebView.Editor.Tests.asmdef delete mode 100644 Tests/Editor/ReadyPlayerMe.WebView.Editor.Tests.asmdef.meta delete mode 100644 Tests/Editor/UrlConfigTests.cs delete mode 100644 Tests/Editor/UrlConfigTests.cs.meta diff --git a/Editor.meta b/Editor.meta deleted file mode 100644 index 088d0ea..0000000 --- a/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 26c29dd5c4e5b44da83fe6d7f7501b48 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/WebViewBuildPostprocessor.cs b/Editor/WebViewBuildPostprocessor.cs deleted file mode 100644 index 703632d..0000000 --- a/Editor/WebViewBuildPostprocessor.cs +++ /dev/null @@ -1,239 +0,0 @@ -#if UNITY_EDITOR -using System.IO; -using System.Xml; -using UnityEditor; -using System.Text; -using UnityEditor.Android; -using UnityEditor.Callbacks; - -#if UNITY_IOS -using UnityEditor.iOS.Xcode; -#endif - -namespace ReadyPlayerMe.WebView.Editor -{ - /// - /// Receives a callback after the Android Gradle project is generated, - /// and the callback is used for generating a manifest file with required permissions. - /// - public class WebViewBuildPostprocessor : IPostGenerateGradleAndroidProject - { - public int callbackOrder => 1; - - public void OnPostGenerateGradleAndroidProject(string basePath) - { - var manifestPath = GetManifestPath(basePath); - var androidManifest = new AndroidManifest(manifestPath); - - androidManifest - .SetHardwareAccelerated(true) - .SetUsesCleartextTraffic(true) - .UseCamera() - .UseMicrophone() - .UseGallery() - .AllowBackup(); - - androidManifest.Save(); - } - - private string GetManifestPath(string basePath) - { - var pathBuilder = new StringBuilder(basePath); - pathBuilder.Append(Path.DirectorySeparatorChar).Append("src"); - pathBuilder.Append(Path.DirectorySeparatorChar).Append("main"); - pathBuilder.Append(Path.DirectorySeparatorChar).Append("AndroidManifest.xml"); - return pathBuilder.ToString(); - } - - [PostProcessBuild(100)] - public static void OnPostprocessBuild(BuildTarget buildTarget, string path) - { -#if UNITY_IOS - if (buildTarget == BuildTarget.iOS) { - string projPath = path + "/Unity-iPhone.xcodeproj/project.pbxproj"; - PBXProject proj = new PBXProject(); - proj.ReadFromString(File.ReadAllText(projPath)); - proj.AddFrameworkToProject(proj.GetUnityFrameworkTargetGuid(), "WebKit.framework", false); - File.WriteAllText(projPath, proj.WriteToString()); - } -#endif - } - } - - /// - /// AndroidManifest.xml file that is created with necessary permissions. - /// - internal class AndroidXmlDocument : XmlDocument - { - private string manifestPath; - protected XmlNamespaceManager namespaceManager; - public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android"; - public readonly string ToolsXmlNamespace = "http://schemas.android.com/tools"; - - public AndroidXmlDocument(string path) - { - manifestPath = path; - using (var reader = new XmlTextReader(manifestPath)) - { - reader.Read(); - Load(reader); - } - - namespaceManager = new XmlNamespaceManager(NameTable); - namespaceManager.AddNamespace("android", AndroidXmlNamespace); - namespaceManager.AddNamespace("tools", ToolsXmlNamespace); - } - - public string Save() - { - return SaveAs(manifestPath); - } - - public string SaveAs(string path) - { - using (var writer = new XmlTextWriter(path, new UTF8Encoding(false))) - { - writer.Formatting = Formatting.Indented; - Save(writer); - } - - return path; - } - } - - internal class AndroidManifest : AndroidXmlDocument - { - private const string NodeKey = "name"; - private const string UsesFeature = "uses-feature"; - private const string UsesPermission = "uses-permission"; - - private const string CameraPermission = "android.permission.CAMERA"; - private const string CameraFeature = "android.hardware.camera"; - - private const string MicrophonePermission = "android.permission.MICROPHONE"; - private const string MicrophoneFeature = "android.hardware.microphone"; - - private const string ReadExternalStoragePermission = "android.permission.READ_EXTERNAL_STORAGE"; - private const string WriteExternalStoragePermission = "android.permission.Write_EXTERNAL_STORAGE"; - - private const string UsesCleartextTrafficAttribute = "usesCleartextTraffic"; - private const string HardwareAcceleratedAttribute = "hardwareAccelerated"; - - private const string XPath = "/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and intent-filter/category/@android:name='android.intent.category.LAUNCHER']"; - - private static XmlNode ActivityWithLaunchIntent = null; - - private readonly XmlElement ManifestElement; - - public AndroidManifest(string path) : base(path) - { - ManifestElement = SelectSingleNode("/manifest") as XmlElement; - } - - internal XmlNode GetActivityWithLaunchIntent() - { - return ActivityWithLaunchIntent ?? SelectSingleNode(XPath, namespaceManager); - } - - #region Node Edit Methods - - private XmlAttribute CreateAndroidAttribute(string key, string value) - { - XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace); - attr.Value = value; - return attr; - } - - private XmlAttribute CreateToolsAttribute(string key, string value) - { - XmlAttribute attr = CreateAttribute("tools", key, ToolsXmlNamespace); - attr.Value = value; - return attr; - } - - internal void UpdateAttribute(XmlElement activity, string attribute, bool enabled) - { - var value = enabled.ToString(); - - if (activity.GetAttribute(attribute, AndroidXmlNamespace) != value) - { - activity.SetAttribute(attribute, AndroidXmlNamespace, value); - } - } - - internal void UpdateNode(string nodeName, string nodeValue) - { - XmlNodeList node = SelectNodes($"/manifest/{nodeName}[@android:{NodeKey}='{nodeValue}']", namespaceManager); - if (node?.Count == 0) - { - XmlElement elem = CreateElement(nodeName); - elem.Attributes.Append(CreateAndroidAttribute(NodeKey, nodeValue)); - ManifestElement.AppendChild(elem); - } - } - - internal void UseFeature(string feature) - { - UpdateNode(UsesFeature, feature); - } - - internal void UsePermission(string permission) - { - UpdateNode(UsesPermission, permission); - } - - #endregion - - #region AndroidManifest Options - - internal AndroidManifest SetUsesCleartextTraffic(bool enabled) - { - var activity = GetActivityWithLaunchIntent() as XmlElement; - UpdateAttribute(activity, UsesCleartextTrafficAttribute, enabled); - return this; - } - - internal AndroidManifest AllowBackup() - { - XmlNode elem = SelectSingleNode("/manifest/application"); - if (elem?.Attributes != null) - { - elem.Attributes.Append(CreateAndroidAttribute("allowBackup", "false")); - elem.Attributes.Append(CreateToolsAttribute("replace", "android:allowBackup")); - } - - return this; - } - - internal AndroidManifest SetHardwareAccelerated(bool enabled) - { - var activity = GetActivityWithLaunchIntent() as XmlElement; - UpdateAttribute(activity, HardwareAcceleratedAttribute, enabled); - return this; - } - - internal AndroidManifest UseCamera() - { - UsePermission(CameraPermission); - UseFeature(CameraFeature); - return this; - } - - internal AndroidManifest UseMicrophone() - { - UsePermission(MicrophonePermission); - UseFeature(MicrophoneFeature); - return this; - } - - internal AndroidManifest UseGallery() - { - UsePermission(ReadExternalStoragePermission); - UsePermission(WriteExternalStoragePermission); - return this; - } - - #endregion - } -} -#endif diff --git a/Editor/WebViewBuildPostprocessor.cs.meta b/Editor/WebViewBuildPostprocessor.cs.meta deleted file mode 100644 index 9eded63..0000000 --- a/Editor/WebViewBuildPostprocessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0856672d812a15e459cee5e879c109d7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/WebViewEditor.cs b/Editor/WebViewEditor.cs deleted file mode 100644 index 6c1af45..0000000 --- a/Editor/WebViewEditor.cs +++ /dev/null @@ -1,25 +0,0 @@ -#if UNITY_EDITOR -using UnityEditor; -using UnityEngine; - -namespace ReadyPlayerMe.WebView.Editor -{ - public class WebViewEditor : UnityEditor.Editor - { - private const string WEB_VIEW_CANVAS_FILE_NAME = "WebView Canvas"; - - /// - /// Loads a WebView Canvas prefab to the current scene. - /// - [MenuItem("GameObject/UI/Ready Player Me/WebView Canvas", false)] - private static void LoadWebViewCanvas() - { - var prefab = Resources.Load(WEB_VIEW_CANVAS_FILE_NAME); - GameObject instance = Instantiate(prefab); - instance.name = WEB_VIEW_CANVAS_FILE_NAME; - Selection.activeGameObject = instance; - EditorUtility.SetDirty(instance); - } - } -} -#endif diff --git a/Editor/WebViewEditor.cs.meta b/Editor/WebViewEditor.cs.meta deleted file mode 100644 index 6784b0b..0000000 --- a/Editor/WebViewEditor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 055a341980f246a47b8227fd1ae60f27 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Data/Enums.cs b/Runtime/Data/Enums.cs index 8087f1c..40a46a5 100644 --- a/Runtime/Data/Enums.cs +++ b/Runtime/Data/Enums.cs @@ -1,6 +1,3 @@ -using System; -using System.Reflection; - namespace ReadyPlayerMe.WebView { /// @@ -22,97 +19,4 @@ public enum WebkitContentMode Mobile = 1, Desktop = 2 } - - /// - /// Defines all the options for the language translation of the Ready Player Me website. - /// - public enum Language - { - [StringValue("")] Default, - [StringValue("ch")] Chinese, - [StringValue("de")] German, - [StringValue("en-IE")] EnglishIreland, - [StringValue("en")] English, - [StringValue("es-MX")] SpanishMexico, - [StringValue("es")] Spanish, - [StringValue("fr")] French, - [StringValue("it")] Italian, - [StringValue("jp")] Japanese, - [StringValue("kr")] Korean, - [StringValue("pt-BR")] PortugueseBrazil, - [StringValue("pt")] Portuguese, - [StringValue("tr")] Turkish - } - - /// - /// Defines the options for the avatar body type. - /// - public enum BodyType - { - Selectable, - [StringValue("fullbody")] FullBody, - [StringValue("halfbody")] HalfBody - } - - /// - /// Defines the options used for the avatars gender. - /// - public enum Gender - { - None, - [StringValue("male")] Male, - [StringValue("female")] Female - } - - /// - /// Defines the options used for the WebView and Message panel UI. - /// - public enum MessageType - { - [StringValue("Loading...")] - Loading, - [StringValue("Network is not reachable.")] - NetworkError, - [StringValue("WebView is only supported on Android and iOS.\nBuild and run on a mobile device.")] - NotSupported - } - - // Attribute for storing a string value in the enum field - public class StringValueAttribute : Attribute - { - - public StringValueAttribute(string value) - { - Value = value; - } - - public string Value { get; } - } - - // Extension methods and helpers for enums - public static class EnumHelpers - { - // Helps extracting the string value stored in the StringValue attribute of the enum field - public static string GetValue(this T enumerationValue) where T : struct - { - Type type = enumerationValue.GetType(); - if (!type.IsEnum) - { - throw new ArgumentException("EnumerationValue must be of Enum type", nameof(enumerationValue)); - } - - MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString()); - if (memberInfo.Length > 0) - { - var attrs = memberInfo[0].GetCustomAttributes(typeof(StringValueAttribute), false); - - if (attrs.Length > 0) - { - return ((StringValueAttribute) attrs[0]).Value; - } - } - - return enumerationValue.ToString(); - } - } } diff --git a/Runtime/Data/Enums.cs.meta b/Runtime/Data/Enums.cs.meta index 9504841..1f7ef85 100644 --- a/Runtime/Data/Enums.cs.meta +++ b/Runtime/Data/Enums.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 852f772df746d354090fa33a897207f1 +guid: 273ee7af478906247bc2bb04ca620999 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/Data/ScreenPadding.cs b/Runtime/Data/ScreenPadding.cs deleted file mode 100644 index cfb2805..0000000 --- a/Runtime/Data/ScreenPadding.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace ReadyPlayerMe.WebView -{ - /// - /// A simple class used to define the padding properties used by the WebView UI. - /// - [System.Serializable] - public class ScreenPadding - { - public int left = 0; - public int top = 0; - public int right = 0; - public int bottom = 0; - } -} diff --git a/Runtime/Data/ScreenPadding.cs.meta b/Runtime/Data/ScreenPadding.cs.meta deleted file mode 100644 index 06af241..0000000 --- a/Runtime/Data/ScreenPadding.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d156c0f4d728b8f4493c7664a4473772 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Data/UrlConfig.cs b/Runtime/Data/UrlConfig.cs deleted file mode 100644 index 34237fd..0000000 --- a/Runtime/Data/UrlConfig.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Text; -using Newtonsoft.Json; -using ReadyPlayerMe.Core; -using UnityEngine; - -namespace ReadyPlayerMe.WebView -{ - /// - /// This class is used to define all the settings related to the URL that is used for creating the URL to be loaded in the WebView browser. - /// - [System.Serializable] - public class UrlConfig - { - private const string TAG = nameof(UrlConfig); - private const string CLEAR_CACHE_PARAM = "clearCache"; - private const string FRAME_API_PARAM = "frameApi"; - private const string QUICK_START_PARAM = "quickStart"; - private const string SELECT_BODY_PARAM = "selectBodyType"; - private const string LOGIN_TOKEN_PARAM = "token"; - - [Tooltip("Language of the RPM website.")] - public Language language = Language.Default; - - [Tooltip("Check if you want user to create a new avatar every visit. If not checked, avatar editor will continue from previously created avatar.")] - public bool clearCache; - - [Tooltip("Start with preset full-body avatars. Checking this option makes avatar editor ignore Gender and Body Type options.")] - public bool quickStart; - - [Tooltip("Skip gender selection and create avatars with selected gender. Ignored if Quick Start is checked.")] - public Gender gender = Gender.None; - - [Tooltip("Skip body type selection and create avatars with selected body type. Ignored if Quick Start is checked.")] - public BodyType bodyType = BodyType.Selectable; - - /// - /// Builds RPM website URL for partner with given parameters. - /// - /// The Url to load in the WebView. - public string BuildUrl(string loginToken = "") - { - var builder = new StringBuilder($"https://{CoreSettingsHandler.CoreSettings.Subdomain}.readyplayer.me/"); - builder.Append(language != Language.Default ? $"{language.GetValue()}/" : string.Empty); - builder.Append($"avatar?{FRAME_API_PARAM}"); - builder.Append(clearCache ? $"&{CLEAR_CACHE_PARAM}" : string.Empty); - if (loginToken != string.Empty) - { - builder.Append($"&{LOGIN_TOKEN_PARAM}={loginToken}"); - } - - if (quickStart) - { - builder.Append($"&{QUICK_START_PARAM}"); - } - else - { - builder.Append(gender != Gender.None ? $"&gender={gender.GetValue()}" : string.Empty); - builder.Append(bodyType == BodyType.Selectable ? $"&{SELECT_BODY_PARAM}" : $"&bodyType={bodyType.GetValue()}"); - } - - var url = builder.ToString(); - SDKLogger.AvatarLoaderLogger.Log(TAG, url); - - return url; - } - } -} diff --git a/Runtime/Data/UrlConfig.cs.meta b/Runtime/Data/UrlConfig.cs.meta deleted file mode 100644 index 0e0d185..0000000 --- a/Runtime/Data/UrlConfig.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 109e041e67cd7274c86eabd46af564ec -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Data/WebMessage.cs b/Runtime/Data/WebMessage.cs deleted file mode 100644 index daf3890..0000000 --- a/Runtime/Data/WebMessage.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace ReadyPlayerMe.WebView -{ - public struct WebMessage - { - public string type; - public string source; - public string eventName; - public Dictionary data; - } -} diff --git a/Runtime/Data/WebMessage.cs.meta b/Runtime/Data/WebMessage.cs.meta deleted file mode 100644 index 516925c..0000000 --- a/Runtime/Data/WebMessage.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 02b9cae38652cf34085cec61e073c265 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/MessagePanel.cs b/Runtime/MessagePanel.cs deleted file mode 100644 index 86553cf..0000000 --- a/Runtime/MessagePanel.cs +++ /dev/null @@ -1,52 +0,0 @@ -using UnityEngine; -using UnityEngine.UI; - -namespace ReadyPlayerMe.WebView -{ - /// - /// This class is responsible for displaying and updating a UI panel and message text. - /// - public class MessagePanel : MonoBehaviour - { - [SerializeField] private Text messageLabel; - - /// - /// Set message from a string value. - /// - /// Message to display. - public void SetMessage(string message) - { - messageLabel.text = message; - } - - /// - /// Set message from a message type. - /// - /// Describes the option for the message that is to be displayed. - public void SetMessage(MessageType type) - { - messageLabel.text = type.GetValue(); - } - - /// - /// Set message panel visibility. - /// - public void SetVisible(bool visible) - { - gameObject.SetActive(visible); - } - - /// - /// Set message panel padding in pixels. - /// - public void SetMargins(int left, int top, int right, int bottom) - { - var rect = transform as RectTransform; - if (rect != null) - { - rect.offsetMax = new Vector2(-right, -top); - rect.offsetMin = new Vector2(left, bottom); - } - } - } -} diff --git a/Runtime/MessagePanel.cs.meta b/Runtime/MessagePanel.cs.meta deleted file mode 100644 index 063383f..0000000 --- a/Runtime/MessagePanel.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: da6aecf803b15f446ad259836bb2cf4f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Native/WebViewBase.cs b/Runtime/Native/WebViewBase.cs index 1c243e9..9fdc4eb 100644 --- a/Runtime/Native/WebViewBase.cs +++ b/Runtime/Native/WebViewBase.cs @@ -1,4 +1,5 @@ using System; +using ReadyPlayerMe.Core.WebView; using UnityEngine; namespace ReadyPlayerMe.WebView diff --git a/Runtime/WebMessageHelper.cs b/Runtime/WebMessageHelper.cs deleted file mode 100644 index ce08b8b..0000000 --- a/Runtime/WebMessageHelper.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace ReadyPlayerMe.WebView -{ - public struct AssetRecord - { - public string UserId; - public string AssetId; - } - - public static class WebMessageHelper - { - private const string DATA_URL_FIELD_NAME = "url"; - private const string ID_KEY = "id"; - private const string USER_ID_KEY = "userId"; - private const string ASSET_ID_KEY = "assetId"; - - public static string GetAvatarUrl(this WebMessage webMessage) - { - webMessage.data.TryGetValue(DATA_URL_FIELD_NAME, out var avatarUrl); - return avatarUrl ?? string.Empty; - } - - public static string GetUserId(this WebMessage webMessage) - { - webMessage.data.TryGetValue(ID_KEY, out var userId); - return userId ?? string.Empty; - } - - public static AssetRecord GetAssetRecord(this WebMessage webMessage) - { - webMessage.data.TryGetValue(ASSET_ID_KEY, out var assetId); - webMessage.data.TryGetValue(USER_ID_KEY, out var userId); - var assetRecord = new AssetRecord(); - assetRecord.AssetId = assetId; - assetRecord.UserId = userId; - return assetRecord; - } - } -} diff --git a/Runtime/WebMessageHelper.cs.meta b/Runtime/WebMessageHelper.cs.meta deleted file mode 100644 index 92c464b..0000000 --- a/Runtime/WebMessageHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cc0f294ec3d9d994ead938c7159b55d9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/WebViewEvents.cs b/Runtime/WebViewEvents.cs deleted file mode 100644 index ed25006..0000000 --- a/Runtime/WebViewEvents.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using UnityEngine.Events; - -namespace ReadyPlayerMe.WebView -{ - // Event to call when avatar is created, receives GLB url. - [Serializable] public class WebViewEvent : UnityEvent - { - } - - // Event to call when avatar is created, receives GLB url. - [Serializable] public class AssetUnlockEvent : UnityEvent - { - } - - public static class WebViewEvents - { - public const string AVATAR_EXPORT = "v1.avatar.exported"; - public const string USER_SET = "v1.user.set"; - public const string USER_AUTHORIZED = "v1.user.authorized"; - public const string ASSET_UNLOCK = "v1.asset.unlock"; - } -} diff --git a/Runtime/WebViewEvents.cs.meta b/Runtime/WebViewEvents.cs.meta deleted file mode 100644 index 42ac6ad..0000000 --- a/Runtime/WebViewEvents.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9437fef0b1489a04c9d987396b9c08b1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/WebViewPanel.cs b/Runtime/WebViewPanel.cs index ee8c81e..17164b3 100644 --- a/Runtime/WebViewPanel.cs +++ b/Runtime/WebViewPanel.cs @@ -1,6 +1,7 @@ using System; using Newtonsoft.Json; using ReadyPlayerMe.Core; +using ReadyPlayerMe.Core.WebView; using UnityEngine; namespace ReadyPlayerMe.WebView diff --git a/Tests/Editor.meta b/Tests/Editor.meta deleted file mode 100644 index 1976200..0000000 --- a/Tests/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: eddad676e6e0cae4989e0d7c1449ba6f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Tests/Editor/ReadyPlayerMe.WebView.Editor.Tests.asmdef b/Tests/Editor/ReadyPlayerMe.WebView.Editor.Tests.asmdef deleted file mode 100644 index 0888c5d..0000000 --- a/Tests/Editor/ReadyPlayerMe.WebView.Editor.Tests.asmdef +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "ReadyPlayerMe.WebView.Editor.Tests", - "rootNamespace": "", - "references": [ - "GUID:292600d1b44837d4b8ce752a20ebe446", - "GUID:96af4ea235d92d245a095007c6ca3701", - "GUID:69ab3f10cf42d0b42a6cd1353c374377" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [ - "UNITY_INCLUDE_TESTS" - ], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/Tests/Editor/ReadyPlayerMe.WebView.Editor.Tests.asmdef.meta b/Tests/Editor/ReadyPlayerMe.WebView.Editor.Tests.asmdef.meta deleted file mode 100644 index db9663e..0000000 --- a/Tests/Editor/ReadyPlayerMe.WebView.Editor.Tests.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: b534849a0738e744780ff9f9eb311446 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Tests/Editor/UrlConfigTests.cs b/Tests/Editor/UrlConfigTests.cs deleted file mode 100644 index e1e65a9..0000000 --- a/Tests/Editor/UrlConfigTests.cs +++ /dev/null @@ -1,112 +0,0 @@ -using UnityEngine; -using NUnit.Framework; - -namespace ReadyPlayerMe.WebView.Tests -{ - public class UrlConfigTests : MonoBehaviour - { - private const string URL_DEFAULT = "https://demo.readyplayer.me/avatar?frameApi&selectBodyType"; - private const string URL_LANG_GERMAN = "https://demo.readyplayer.me/de/avatar?frameApi&selectBodyType"; - private const string URL_LANG_BRAZIL = "https://demo.readyplayer.me/pt-BR/avatar?frameApi&selectBodyType"; - - private const string URL_GENDER_MALE = "https://demo.readyplayer.me/avatar?frameApi&gender=male&selectBodyType"; - private const string URL_GENDER_NONE = "https://demo.readyplayer.me/avatar?frameApi&gender=male&selectBodyType"; - - private const string URL_TYPE_FULLBODY = "https://demo.readyplayer.me/avatar?frameApi&bodyType=fullbody"; - private const string URL_TYPE_HALFBODY = "https://demo.readyplayer.me/avatar?frameApi&bodyType=halfbody"; - - private const string URL_CLEAR_CACHE = "https://demo.readyplayer.me/avatar?frameApi&clearCache&selectBodyType"; - - private const string URL_QUICK_START = "https://demo.readyplayer.me/avatar?frameApi&quickStart"; - private const string URL_TOKEN = "https://demo.readyplayer.me/avatar?frameApi&token=TOKEN&selectBodyType"; - private const string LOGIN_TOKEN = "TOKEN"; - - public UrlConfig config; - - [SetUp] - public void Setup() - { - config = new UrlConfig(); - } - - [Test] - public void Url_Name_Change_German() - { - config.language = Language.German; - var res = config.BuildUrl(); - Assert.AreEqual(URL_LANG_GERMAN, res); - } - - [Test] - public void Url_Name_Change_Brazil() - { - config.language = Language.PortugueseBrazil; - var res = config.BuildUrl(); - Assert.AreEqual(URL_LANG_BRAZIL, res); - } - - [Test] - public void Url_Gender_Change_Male() - { - config.gender = Gender.Male; - var res = config.BuildUrl(); - Assert.AreEqual(URL_GENDER_MALE, res); - } - - [Test] - public void Url_Gender_Change_None() - { - config.gender = Gender.Male; - var res = config.BuildUrl(); - Assert.AreEqual(URL_GENDER_NONE, res); - } - - [Test] - public void Url_BodyType_Change_Fullbody() - { - config.bodyType = BodyType.FullBody; - var res = config.BuildUrl(); - Assert.AreEqual(URL_TYPE_FULLBODY, res); - } - - [Test] - public void Url_BodyType_Change_Halfbody() - { - config.bodyType = BodyType.HalfBody; - var res = config.BuildUrl(); - Assert.AreEqual(URL_TYPE_HALFBODY, res); - } - - [Test] - public void Url_ClearCache_Change() - { - config.clearCache = true; - var res = config.BuildUrl(); - Assert.AreEqual(URL_CLEAR_CACHE, res); - } - - [Test] - public void Url_QuickStart_Change() - { - config.quickStart = true; - var res = config.BuildUrl(); - Assert.AreEqual(URL_QUICK_START, res); - } - - [Test] - public void Url_With_Token() - { - var testConfig = new UrlConfig(); - var res = testConfig.BuildUrl(LOGIN_TOKEN); - Assert.AreEqual(URL_TOKEN, res); - } - - [Test] - public void Url_Default() - { - var testConfig = new UrlConfig(); - var res = testConfig.BuildUrl(); - Assert.AreEqual(URL_DEFAULT, res); - } - } -} diff --git a/Tests/Editor/UrlConfigTests.cs.meta b/Tests/Editor/UrlConfigTests.cs.meta deleted file mode 100644 index 6e24c63..0000000 --- a/Tests/Editor/UrlConfigTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e32128773bea8b447859a8c9fec9452d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From d848e887ec4f6feb6a134a82f56cab41a4cbae2a Mon Sep 17 00:00:00 2001 From: Harrison Hough Date: Wed, 4 Oct 2023 11:15:40 +0300 Subject: [PATCH 3/6] chore: prepare release --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 825cd85..0c5726e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [2.0.0] - 2023.20.04 + +### Updated +- moved core iframe and url logic to Core package @harrisonhough in [#21](https://github.com/readyplayerme/rpm-unity-sdk-webview/pull/21) + ## [1.2.1] - 2023.08.14 ### Fixed diff --git a/package.json b/package.json index 274441d..8d5feea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.readyplayerme.webview", - "version": "1.2.1", + "version": "2.0.0", "displayName": "Ready Player Me WebView", "description": "Ready Player Me WebView helps you display an in-engine browser that helps you load RPM website where you can create avatars and receive avatar URL at the end of the process.\nWebView is mobile only and works in Android and IOS builds.", "category": "tool", From 7fc77088e46dcd1cc33dd982bbfe6279e7212b52 Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Wed, 4 Oct 2023 15:19:32 +0700 Subject: [PATCH 4/6] Allow set urlConfig properties from other code (#16) Allow set urlConfig properties from other code (#16) --- CHANGELOG.md | 1 + Runtime/WebViewPanel.cs | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 825cd85..65520bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). + ## [1.2.1] - 2023.08.14 ### Fixed diff --git a/Runtime/WebViewPanel.cs b/Runtime/WebViewPanel.cs index 17164b3..f967749 100644 --- a/Runtime/WebViewPanel.cs +++ b/Runtime/WebViewPanel.cs @@ -18,6 +18,15 @@ public class WebViewPanel : MonoBehaviour [SerializeField] private ScreenPadding screenPadding; [SerializeField] private UrlConfig urlConfig; + public UrlConfig UrlConfig + { + get + { + urlConfig ??= new UrlConfig(); + return urlConfig; + } + } + [Space, SerializeField] public WebViewEvent OnAvatarCreated = new WebViewEvent(); [SerializeField] public WebViewEvent OnUserSet = new WebViewEvent(); [SerializeField] public WebViewEvent OnUserAuthorized = new WebViewEvent(); From d770cb8759910f225d541b5d50fdc0ece7738119 Mon Sep 17 00:00:00 2001 From: Harrison Hough Date: Thu, 5 Oct 2023 08:38:17 +0300 Subject: [PATCH 5/6] fix: moved editor scripts back to WebView --- Editor.meta | 8 + Editor/WebViewBuildPostprocessor.cs | 239 +++++++++++++++++++++++ Editor/WebViewBuildPostprocessor.cs.meta | 11 ++ Editor/WebViewEditor.cs | 25 +++ Editor/WebViewEditor.cs.meta | 11 ++ 5 files changed, 294 insertions(+) create mode 100644 Editor.meta create mode 100644 Editor/WebViewBuildPostprocessor.cs create mode 100644 Editor/WebViewBuildPostprocessor.cs.meta create mode 100644 Editor/WebViewEditor.cs create mode 100644 Editor/WebViewEditor.cs.meta diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..088d0ea --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 26c29dd5c4e5b44da83fe6d7f7501b48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/WebViewBuildPostprocessor.cs b/Editor/WebViewBuildPostprocessor.cs new file mode 100644 index 0000000..eb16960 --- /dev/null +++ b/Editor/WebViewBuildPostprocessor.cs @@ -0,0 +1,239 @@ +#if UNITY_EDITOR +using System.IO; +using System.Xml; +using UnityEditor; +using System.Text; +using UnityEditor.Android; +using UnityEditor.Callbacks; + +#if UNITY_IOS +using UnityEditor.iOS.Xcode; +#endif + +namespace ReadyPlayerMe.WebView +{ + /// + /// Receives a callback after the Android Gradle project is generated, + /// and the callback is used for generating a manifest file with required permissions. + /// + public class WebViewBuildPostprocessor : IPostGenerateGradleAndroidProject + { + public int callbackOrder => 1; + + public void OnPostGenerateGradleAndroidProject(string basePath) + { + var manifestPath = GetManifestPath(basePath); + var androidManifest = new AndroidManifest(manifestPath); + + androidManifest + .SetHardwareAccelerated(true) + .SetUsesCleartextTraffic(true) + .UseCamera() + .UseMicrophone() + .UseGallery() + .AllowBackup(); + + androidManifest.Save(); + } + + private string GetManifestPath(string basePath) + { + var pathBuilder = new StringBuilder(basePath); + pathBuilder.Append(Path.DirectorySeparatorChar).Append("src"); + pathBuilder.Append(Path.DirectorySeparatorChar).Append("main"); + pathBuilder.Append(Path.DirectorySeparatorChar).Append("AndroidManifest.xml"); + return pathBuilder.ToString(); + } + + [PostProcessBuild(100)] + public static void OnPostprocessBuild(BuildTarget buildTarget, string path) + { +#if UNITY_IOS + if (buildTarget == BuildTarget.iOS) { + string projPath = path + "/Unity-iPhone.xcodeproj/project.pbxproj"; + PBXProject proj = new PBXProject(); + proj.ReadFromString(File.ReadAllText(projPath)); + proj.AddFrameworkToProject(proj.GetUnityFrameworkTargetGuid(), "WebKit.framework", false); + File.WriteAllText(projPath, proj.WriteToString()); + } +#endif + } + } + + /// + /// AndroidManifest.xml file that is created with necessary permissions. + /// + internal class AndroidXmlDocument : XmlDocument + { + private string manifestPath; + protected XmlNamespaceManager namespaceManager; + public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android"; + public readonly string ToolsXmlNamespace = "http://schemas.android.com/tools"; + + public AndroidXmlDocument(string path) + { + manifestPath = path; + using (var reader = new XmlTextReader(manifestPath)) + { + reader.Read(); + Load(reader); + } + + namespaceManager = new XmlNamespaceManager(NameTable); + namespaceManager.AddNamespace("android", AndroidXmlNamespace); + namespaceManager.AddNamespace("tools", ToolsXmlNamespace); + } + + public string Save() + { + return SaveAs(manifestPath); + } + + public string SaveAs(string path) + { + using (var writer = new XmlTextWriter(path, new UTF8Encoding(false))) + { + writer.Formatting = Formatting.Indented; + Save(writer); + } + + return path; + } + } + + internal class AndroidManifest : AndroidXmlDocument + { + private const string NodeKey = "name"; + private const string UsesFeature = "uses-feature"; + private const string UsesPermission = "uses-permission"; + + private const string CameraPermission = "android.permission.CAMERA"; + private const string CameraFeature = "android.hardware.camera"; + + private const string MicrophonePermission = "android.permission.MICROPHONE"; + private const string MicrophoneFeature = "android.hardware.microphone"; + + private const string ReadExternalStoragePermission = "android.permission.READ_EXTERNAL_STORAGE"; + private const string WriteExternalStoragePermission = "android.permission.Write_EXTERNAL_STORAGE"; + + private const string UsesCleartextTrafficAttribute = "usesCleartextTraffic"; + private const string HardwareAcceleratedAttribute = "hardwareAccelerated"; + + private const string XPath = "/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and intent-filter/category/@android:name='android.intent.category.LAUNCHER']"; + + private static XmlNode ActivityWithLaunchIntent = null; + + private readonly XmlElement ManifestElement; + + public AndroidManifest(string path) : base(path) + { + ManifestElement = SelectSingleNode("/manifest") as XmlElement; + } + + internal XmlNode GetActivityWithLaunchIntent() + { + return ActivityWithLaunchIntent ?? SelectSingleNode(XPath, namespaceManager); + } + + #region Node Edit Methods + + private XmlAttribute CreateAndroidAttribute(string key, string value) + { + XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace); + attr.Value = value; + return attr; + } + + private XmlAttribute CreateToolsAttribute(string key, string value) + { + XmlAttribute attr = CreateAttribute("tools", key, ToolsXmlNamespace); + attr.Value = value; + return attr; + } + + internal void UpdateAttribute(XmlElement activity, string attribute, bool enabled) + { + var value = enabled.ToString(); + + if (activity.GetAttribute(attribute, AndroidXmlNamespace) != value) + { + activity.SetAttribute(attribute, AndroidXmlNamespace, value); + } + } + + internal void UpdateNode(string nodeName, string nodeValue) + { + XmlNodeList node = SelectNodes($"/manifest/{nodeName}[@android:{NodeKey}='{nodeValue}']", namespaceManager); + if (node?.Count == 0) + { + XmlElement elem = CreateElement(nodeName); + elem.Attributes.Append(CreateAndroidAttribute(NodeKey, nodeValue)); + ManifestElement.AppendChild(elem); + } + } + + internal void UseFeature(string feature) + { + UpdateNode(UsesFeature, feature); + } + + internal void UsePermission(string permission) + { + UpdateNode(UsesPermission, permission); + } + + #endregion + + #region AndroidManifest Options + + internal AndroidManifest SetUsesCleartextTraffic(bool enabled) + { + var activity = GetActivityWithLaunchIntent() as XmlElement; + UpdateAttribute(activity, UsesCleartextTrafficAttribute, enabled); + return this; + } + + internal AndroidManifest AllowBackup() + { + XmlNode elem = SelectSingleNode("/manifest/application"); + if (elem?.Attributes != null) + { + elem.Attributes.Append(CreateAndroidAttribute("allowBackup", "false")); + elem.Attributes.Append(CreateToolsAttribute("replace", "android:allowBackup")); + } + + return this; + } + + internal AndroidManifest SetHardwareAccelerated(bool enabled) + { + var activity = GetActivityWithLaunchIntent() as XmlElement; + UpdateAttribute(activity, HardwareAcceleratedAttribute, enabled); + return this; + } + + internal AndroidManifest UseCamera() + { + UsePermission(CameraPermission); + UseFeature(CameraFeature); + return this; + } + + internal AndroidManifest UseMicrophone() + { + UsePermission(MicrophonePermission); + UseFeature(MicrophoneFeature); + return this; + } + + internal AndroidManifest UseGallery() + { + UsePermission(ReadExternalStoragePermission); + UsePermission(WriteExternalStoragePermission); + return this; + } + + #endregion + } +} +#endif diff --git a/Editor/WebViewBuildPostprocessor.cs.meta b/Editor/WebViewBuildPostprocessor.cs.meta new file mode 100644 index 0000000..9eded63 --- /dev/null +++ b/Editor/WebViewBuildPostprocessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0856672d812a15e459cee5e879c109d7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/WebViewEditor.cs b/Editor/WebViewEditor.cs new file mode 100644 index 0000000..339153e --- /dev/null +++ b/Editor/WebViewEditor.cs @@ -0,0 +1,25 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace ReadyPlayerMe.WebView +{ + public class WebViewEditor : Editor + { + private const string WEB_VIEW_CANVAS_FILE_NAME = "WebView Canvas"; + + /// + /// Loads a WebView Canvas prefab to the current scene. + /// + [MenuItem("GameObject/UI/Ready Player Me/WebView Canvas", false)] + private static void LoadWebViewCanvas() + { + var prefab = Resources.Load(WEB_VIEW_CANVAS_FILE_NAME); + GameObject instance = Instantiate(prefab); + instance.name = WEB_VIEW_CANVAS_FILE_NAME; + Selection.activeGameObject = instance; + EditorUtility.SetDirty(instance); + } + } +} +#endif diff --git a/Editor/WebViewEditor.cs.meta b/Editor/WebViewEditor.cs.meta new file mode 100644 index 0000000..6784b0b --- /dev/null +++ b/Editor/WebViewEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 055a341980f246a47b8227fd1ae60f27 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 2d4300c4dd5ffbd05ad60c205d82cdcc35f5ca4b Mon Sep 17 00:00:00 2001 From: Harrison Hough Date: Thu, 5 Oct 2023 08:39:00 +0300 Subject: [PATCH 6/6] chore: update README --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c45be25..f235dd2 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,6 @@ _NOTE: The WebView example scene will not load an avatar into the unity scene, i **_Alternatively, you can build the APK and deploy it on your own. For release builds, see the Unity and Android documentation._** -## Troubleshooting -- If you don't have a subdomain, this warning will pop up, and you can click Continue with 'demo' subdomain. -- If your package name does not comply with the required format, you will get this warning and can't continue until you fix it. - ## Deploy on iOS 1. In Build Settings, set the Platform to iOS. 2. Select Debug and check Development build. @@ -84,3 +80,22 @@ For release builds, see the Unity and Android documentation._** 6. Close Project Settings. 7. Click Build. 8. In the file explorer, find your Builds folder and in it the `Unity-iPhone.xcodeproj`. + + +## WebView 2.0 update + +As of WebView 2.0 a number of changes have been made to isolate the WebView module from the rest of the Ready Player Me Unity SDK. + +This means that the classes and logic required to work with an iFrame (AKA a WebView), that is running Web Avatar Creator have now been moved to the Ready Player Me Core module. +This change enables developers to utilize API's for working with any iFrame, without requiring the installation of our WebView package. + +As such the following classes are now located in the Ready Player Me Core module: +- WebViewMessageHelper +- UrlConfig +- WebMessage +- MessagePanel +- WebMessageHelper +- WebViewEvents + +If you have any scripts in your Unity project that reference these classes you will need to update the namespace to use ReadyPlayerMe.Core instead of ReadyPlayerMe.WebView, be sure to update the import statements in these scripts. +EG: `using ReadyPlayerMe.WebView;` should be changed to `using ReadyPlayerMe.Core;` \ No newline at end of file