diff --git a/.gitignore b/.gitignore index 8e32d447..163dd9be 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ */SwitchIL2CPPCache */SwitchIL2CPPStats /PubNubUnity/Library/ +/PubNubUnityUserSettings/ /PubNubUnity/Assets/Plugins* /PubNubUnity/Assets/ThirdParty* diff --git a/.pubnub.yml b/.pubnub.yml index 568af4d8..c371094f 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -776,53 +776,18 @@ sdks: is-required: "Required" - name: "JSON .NET For Unity" - min-version: "2.0.1" + min-version: "3.0.2" license: "Unity's standard Unity Asset Store End User License Agreement" license-url: "" location: "Shipped within package" is-required: "Optional, one JSON serialization library is required" - name: "PeterO.Cbor" - min-version: "" + min-version: "4.5.5" license: "Creative Commons" license-url: "" location: "Shipped within package" is-required: "Required" - - - name: "MiniJSON" - min-version: "" - license: "MIT" - license-url: "" - location: "Shipped within package" - is-required: "Optional, one JSON serialization library is required" - - - name: "MarkerMetro.Unity.WinLegacy" - min-version: "1.8.0.18" - license: "MIT" - license-url: "https://raw.githubusercontent.com/MarkerMetro/MarkerMetro.Unity.WinLegacy/master/LICENSE" - location: "Shipped within package" - is-required: "Optional, only applicable for Metro" - - - name: "BouncyCastle" - min-version: "1.8.1.0" - license: "MIT" - license-url: "" - location: "Shipped within package" - is-required: "Optional, only applicable for Metro" - - - name: "BouncyCastle.Crypto" - min-version: "1.8.1.0" - license: "MIT" - license-url: "" - location: "Shipped within package" - is-required: "Optional, only applicable for Metro" - - - name: "JsonFx.Json" - min-version: "" - license: "MIT" - license-url: "" - location: "Shipped within package" - is-required: "Optional, only applicable for Metro" supported-platforms: supported-operating-systems: Android: @@ -943,53 +908,18 @@ sdks: is-required: "Required" - name: "JSON .NET For Unity" - min-version: "2.0.1" + min-version: "3.0.2" license: "Unity's standard Unity Asset Store End User License Agreement" license-url: "" location: "Shipped within package" is-required: "Optional, one JSON serialization library is required" - name: "PeterO.Cbor" - min-version: "" + min-version: "4.5.5" license: "Creative Commons" license-url: "" location: "Shipped within package" is-required: "Required" - - - name: "MiniJSON" - min-version: "" - license: "MIT" - license-url: "" - location: "Shipped within package" - is-required: "Optional, one JSON serialization library is required" - - - name: "MarkerMetro.Unity.WinLegacy" - min-version: "1.8.0.18" - license: "MIT" - license-url: "https://raw.githubusercontent.com/MarkerMetro/MarkerMetro.Unity.WinLegacy/master/LICENSE" - location: "Shipped within package" - is-required: "Optional, only applicable for Metro" - - - name: "BouncyCastle" - min-version: "1.8.1.0" - license: "MIT" - license-url: "" - location: "Shipped within package" - is-required: "Optional, only applicable for Metro" - - - name: "BouncyCastle.Crypto" - min-version: "1.8.1.0" - license: "MIT" - license-url: "" - location: "Shipped within package" - is-required: "Optional, only applicable for Metro" - - - name: "JsonFx.Json" - min-version: "" - license: "MIT" - license-url: "" - location: "Shipped within package" - is-required: "Optional, only applicable for Metro" supported-platforms: supported-operating-systems: Android: diff --git a/PubNubUnity/Assets/PubNub/Editor/PNConfigAssetEditor.cs b/PubNubUnity/Assets/PubNub/Editor/PNConfigAssetEditor.cs index e32ccc03..bb7d9c0e 100644 --- a/PubNubUnity/Assets/PubNub/Editor/PNConfigAssetEditor.cs +++ b/PubNubUnity/Assets/PubNub/Editor/PNConfigAssetEditor.cs @@ -23,7 +23,8 @@ public class PNConfigAssetEditor : Editor { "EnableEventEngine", "EnableWebGLBuildMode", "LogToUnityConsole", - "LogVerbosity" + "LogVerbosity", + "LogLevel" }; private SerializedProperty externalJsonEnabled; diff --git a/PubNubUnity/Assets/PubNub/Runtime/Plugins/CBOR.dll b/PubNubUnity/Assets/PubNub/Runtime/Plugins/CBOR.dll index 84d924ed..5c06bec8 100644 Binary files a/PubNubUnity/Assets/PubNub/Runtime/Plugins/CBOR.dll and b/PubNubUnity/Assets/PubNub/Runtime/Plugins/CBOR.dll differ diff --git a/PubNubUnity/Assets/PubNub/Runtime/Plugins/CBOR.dll.meta b/PubNubUnity/Assets/PubNub/Runtime/Plugins/CBOR.dll.meta index 2d6fa6cf..241c4736 100644 --- a/PubNubUnity/Assets/PubNub/Runtime/Plugins/CBOR.dll.meta +++ b/PubNubUnity/Assets/PubNub/Runtime/Plugins/CBOR.dll.meta @@ -11,6 +11,17 @@ PluginImporter: isExplicitlyReferenced: 0 validateReferences: 1 platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 0 + Exclude Linux64: 0 + Exclude OSXUniversal: 0 + Exclude WebGL: 0 + Exclude Win: 0 + Exclude Win64: 0 - first: Any: second: @@ -19,9 +30,40 @@ PluginImporter: - first: Editor: Editor second: - enabled: 0 + enabled: 1 settings: + CPU: AnyCPU DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 1 + settings: + CPU: x86 + - first: + Standalone: Win64 + second: + enabled: 1 + settings: + CPU: x86_64 + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} - first: Windows Store Apps: WindowsStoreApps second: diff --git a/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll index b37679e9..2ebed403 100644 Binary files a/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll and b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll differ diff --git a/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll.meta b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll.meta index 24f0e8bf..e85f27c6 100644 --- a/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll.meta +++ b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll.meta @@ -9,7 +9,7 @@ PluginImporter: isPreloaded: 0 isOverridable: 0 isExplicitlyReferenced: 0 - validateReferences: 0 + validateReferences: 1 platformData: - first: : Any @@ -49,7 +49,7 @@ PluginImporter: second: enabled: 1 settings: - CPU: x86_64 + CPU: AnyCPU - first: Standalone: OSXUniversal second: diff --git a/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.xml b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.xml new file mode 100644 index 00000000..11147e22 --- /dev/null +++ b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.xml @@ -0,0 +1,526 @@ + + + + PubnubApiUnity + + + + + Convert the UTC/GMT DateTime to Unix Nano Seconds format + + + + + + + Convert the Unix Nano Seconds format time to UTC/GMT DateTime + + + + + + + The publish timetoken of a parent message + + + + + + + ttl in hours + + + + + + + The publish timetoken of a parent message + + + + + + + The publish timetoken of the action + + + + + + + Applies to APNS2 Only. Default = Development + + + + + + + Applies to APNS2 Only + + + + + + + Applies to APNS2 Only. Default = Development + + + + + + + Applies to APNS2 Only + + + + + + + Applies to APNS2 Only. Default = Development + + + + + + + Applies to APNS2 Only + + + + + + + Applies to APNS2 Only. Default = Development + + + + + + + Applies to APNS2 Only + + + + + + + Dispatch an invocation i.e. call a registered effect handler. + + + + + Assign a handler implementation to an invocation. + + + + + Subscribe to receive notification on effect dispatch + + + + + Subscribe to receive notification on state transition + + + + + Subscribe to receive notification on event being queued + + + + + Launch the invocations associated with transitioning between states + + + + + Generic effect handler. + + + + + Handler (implementation) for a given invocation. The invocation represents the input arguments of a handler. + + Associated invocation + + + + Implement a handler a cancellable invocation. + + Connect type invocation + Cancel running invocation + + + + Implement a handler for two invocations (meant for connect-reconnect pairs). Use EffectDoubleCancellableHandler to implement cancellable handler. + + Run type invocation + Retry type invocation + + + + Implement a handler for two invocations (meant for connect-reconnect pairs) with a cancel invocation + + Run type invocation + Retry type invocation + Cancel connecting invocation + + + + Implement a handler for two invocations (meant for connect-reconnect pairs) with a cancel invocation + + Run type invocation + Retry type invocation + Cancel run invocation + Cancel retry invocation + + + + An effect invocation. It represents calling Run() on a registered effect handler - calling it is orchestrated by the dispatcher. + + + + + A cancel effect invocation. It represents calling Cancel() on a registered effect handler - calling it is orchestrated by the dispatcher. + + + + + The EE transition pure function. + + Input event + Target state and invocation list, or null for no-transition + + + + Enqueue (fire) an event to the Event Engine. Handling that event is covered by the Engine itself. + + Event to be fired + + + + Create a state-invocation pair with empty invocations + + + + + Create a state-invocation pair + + + + + Create a state-invocation pair + + + + + Supports Only APNS2 + + + + + + + Read. Applies to Subscribe, History, Presence + + + + + Write. Applies to Publish + + + + + Manage. Applies to Channel-Groups, Objects + + + + + Delete. Applies to History, Objects + + + + + Create. Applies to Objects v1 + + + + + Get. Applies to Objects v2 + + + + + Update. Applies to Objects v2 + + + + + Join. Applies to Objects v2 + + + + + messages + + + + + subscribeMetadata + + + + + shard + + + + + subscriptionMatch + + + + + channel + + + + + payload + + + + + message type indicator + + + + + flags + + + + + issuingClientId + + + + + subscribeKey + + + + + sequenceNumber + + + + + originatingTimetoken + + + + + publishMetadata + + + + + userMetadata + + + + + timetoken + + + + + region + + + + + This property is obsolete. Use instead. + + + LogVerbosity is deprecated. Use LogLevel to enable logging. + LogLevel provides more granular control and supports different standard logging levels. + To migrate, replace LogVerbosity = X with LogLevel = (LogLevel)X. + + + + + This property is deprecated. Use method to configure custom logger. + + + PubnubLog is deprecated. Implement IPubnubLogger and Use SetLogger method to configure custom logger for improved flexibility and control. + + + + + Call this function to globally clean up all background threads running in the SDK. Note that this will unsubscribe all channels. + + + + + Parses the token and provides token details. This is client only method (works without secret key) + + string + PNTokenContent + + + + Sets the auth token. This is client only method (works without secret key) + + + + + + Configures a custom logger. + + The logger to use. + + + + Unique crypto algorithm identifier. + + Identifier will be encoded into crypto data header and passed along + with encrypted data. + + The identifier **must** be 4 bytes long. + + + + + MD5 Service provider + + + MD5 messaging-digest algorithm is a widely used cryptographic hash function that produces 128-bit hash value. + + + + + rotates x left n bits. + + + + + + + FF, GG, HH, and II transformations + for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent re-computation. + + + + state (ABCD) + + + + + number of bits, modulo 2^64 (LSB first) + + + + + input buffer + + + + + MD5 initialization. Begins an MD5 operation, writing a new context. + + + The RFC named it "MD5Init" + + + + + MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + + + + + The RFC Named it MD5Update + + + + MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + + message digest + The RFC named it MD5Final + + + + MD5 basic transformation. Transforms state based on 64 bytes block. + + + + + + + Encodes input (uint) into output (byte). Assumes len is + multiple of 4. + + + + + + + + + + Decodes input (byte) into output (uint). Assumes len is + a multiple of 4. + + + + + + + + + + Computes the hash using the specified algo + + + The hash. + + + Input string + + + Algorithm to use for Hashing + + + + EncryptOrDecrypt + + Basic function for encrypt or decrypt a string + for encrypt type = true + for decrypt type = false + + + + Converts the upper case hex to lower case hex. + + The lower case hex. + Hex Value. + + + + Encodes the non ASCII characters. + + + The non ASCII characters. + + + Value. + + + + diff --git a/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.xml.meta b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.xml.meta new file mode 100644 index 00000000..3d7a8368 --- /dev/null +++ b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4e01614121b17794d90656a21c2d9bda +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PubNubUnity/Assets/PubNub/Runtime/Util/PNConfigAsset.cs b/PubNubUnity/Assets/PubNub/Runtime/Util/PNConfigAsset.cs index 6810c00c..4cb97d9a 100644 --- a/PubNubUnity/Assets/PubNub/Runtime/Util/PNConfigAsset.cs +++ b/PubNubUnity/Assets/PubNub/Runtime/Util/PNConfigAsset.cs @@ -18,8 +18,10 @@ public class PNConfigAsset : ScriptableObject { public bool MaintainPresenceState = true; public bool EnableEventEngine = true; public bool EnableWebGLBuildMode; - public bool LogToUnityConsole; + public bool LogToUnityConsole = true; + [Tooltip("Obsolete and used in legacy logging, if you can please use LogLevel instead")] public PNLogVerbosity LogVerbosity; + public PubnubLogLevel LogLevel; [SerializeField] private bool externalJsonEnabled = false; [SerializeField] private UnityEngine.TextAsset externalJsonFile; @@ -43,6 +45,7 @@ public static implicit operator PNConfiguration(PNConfigAsset asset) { config.EnableEventEngine = asset.EnableEventEngine; config.Secure = asset.Secure; config.LogVerbosity = asset.LogVerbosity; + config.LogLevel = asset.LogLevel; return config; } } diff --git a/PubNubUnity/Assets/PubNub/Runtime/Util/UnityWebGLHttpClientService.cs b/PubNubUnity/Assets/PubNub/Runtime/Util/UnityWebGLHttpClientService.cs index 26a93e0b..e5212428 100644 --- a/PubNubUnity/Assets/PubNub/Runtime/Util/UnityWebGLHttpClientService.cs +++ b/PubNubUnity/Assets/PubNub/Runtime/Util/UnityWebGLHttpClientService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; @@ -11,6 +12,13 @@ namespace PubnubApi.Unity { /// This is an implementation of the PubNub Transport Layer created for Web GL builds compatibility /// public class UnityWebGLHttpClientService : IHttpClientService { + + private PubnubLogModule logger; + + public void SetLogger(PubnubLogModule logger) { + this.logger = logger; + } + private TransportResponse UnityRequestToResponse(UnityWebRequest request) { return new TransportResponse() { StatusCode = (int)request.responseCode, @@ -35,11 +43,52 @@ private void PrepareUnityRequest(UnityWebRequest request, TransportRequest trans } } + private TransportResponse GetTransportResponseForRequestException(Exception exception, TransportRequest transportRequest, + UnityWebRequest requestWithTimeout) + { + if (requestWithTimeout == null) { + logger?.Error($"HttpClient Service: UnityWebRequest for url {transportRequest.RequestUrl} was null!"); + return new TransportResponse() + { + RequestUrl = transportRequest.RequestUrl, + Error = exception, + }; + } + + TransportResponse transportResponse; + if (exception is TaskCanceledException taskCanceledException) { + logger?.Error($"HttpClient Service: TaskCanceledException for url {transportRequest.RequestUrl}"); + transportResponse = new TransportResponse() + { + RequestUrl = transportRequest.RequestUrl, + Error = taskCanceledException, + }; + logger?.Debug("HttpClient Service: Task cancelled due to cancellation request"); + transportResponse.IsCancelled = true; + } else { + logger?.Error( + $"HttpClient Service: Exception for http call url {transportRequest.RequestUrl}, exception message: {exception.Message}, stacktrace: {exception.StackTrace}"); + transportResponse = new TransportResponse() { + RequestUrl = transportRequest.RequestUrl, + Error = exception + }; + //Apparently error.Contains("Request timeout") is the only way to determine if request timed out + if (!string.IsNullOrEmpty(requestWithTimeout.error) && requestWithTimeout.error.Contains("Request timeout") && + !transportRequest.CancellationTokenSource.IsCancellationRequested) + { + logger?.Debug("HttpClient Service: Request cancelled due to timeout"); + transportResponse.IsTimeOut = true; + } + } + + return transportResponse; + } + public async Task DeleteRequest(TransportRequest transportRequest) { + var deleteRequest = UnityWebRequest.Delete(transportRequest.RequestUrl); + PrepareUnityRequest(deleteRequest, transportRequest); TransportResponse response; try { - var deleteRequest = UnityWebRequest.Delete(transportRequest.RequestUrl); - PrepareUnityRequest(deleteRequest, transportRequest); var taskCompletionSource = new TaskCompletionSource(); transportRequest.CancellationTokenSource.Token.Register(() => { deleteRequest.Abort(); @@ -50,20 +99,18 @@ public async Task DeleteRequest(TransportRequest transportReq }; response = await taskCompletionSource.Task.ConfigureAwait(false); } catch (Exception ex) { - Debug.LogError($"DELETE Error: {ex}"); - response = new TransportResponse() { - RequestUrl = transportRequest.RequestUrl, - Error = ex - }; + response = GetTransportResponseForRequestException(ex, transportRequest, deleteRequest); + } finally { + transportRequest.CancellationTokenSource?.Dispose(); } return response; } public async Task GetRequest(TransportRequest transportRequest) { + var getRequest = UnityWebRequest.Get(transportRequest.RequestUrl); + PrepareUnityRequest(getRequest, transportRequest); TransportResponse response; try { - var getRequest = UnityWebRequest.Get(transportRequest.RequestUrl); - PrepareUnityRequest(getRequest, transportRequest); var taskCompletionSource = new TaskCompletionSource(); transportRequest.CancellationTokenSource.Token.Register(() => { getRequest.Abort(); @@ -74,17 +121,16 @@ public async Task GetRequest(TransportRequest transportReques }; response = await taskCompletionSource.Task.ConfigureAwait(false); } catch (Exception ex) { - Debug.LogError($"GET Error: {ex}"); - response = new TransportResponse() { - RequestUrl = transportRequest.RequestUrl, - Error = ex - }; + response = GetTransportResponseForRequestException(ex, transportRequest, getRequest); + } finally { + transportRequest.CancellationTokenSource?.Dispose(); } return response; } public async Task PostRequest(TransportRequest transportRequest) { TransportResponse response; + UnityWebRequest postRequest = null; try { var formData = new List(); if (!string.IsNullOrEmpty(transportRequest.BodyContentString)) { @@ -93,7 +139,7 @@ public async Task PostRequest(TransportRequest transportReque formData.Add(new MultipartFormDataSection(transportRequest.BodyContentBytes)); } - var postRequest = UnityWebRequest.Post(transportRequest.RequestUrl, formData); + postRequest = UnityWebRequest.Post(transportRequest.RequestUrl, formData); PrepareUnityRequest(postRequest, transportRequest); var taskCompletionSource = new TaskCompletionSource(); transportRequest.CancellationTokenSource.Token.Register(() => { @@ -105,19 +151,18 @@ public async Task PostRequest(TransportRequest transportReque }; response = await taskCompletionSource.Task.ConfigureAwait(false); } catch (Exception ex) { - Debug.LogError($"POST Error: {ex}"); - response = new TransportResponse() { - RequestUrl = transportRequest.RequestUrl, - Error = ex - }; + response = GetTransportResponseForRequestException(ex, transportRequest, postRequest); + } finally { + transportRequest.CancellationTokenSource?.Dispose(); } return response; } public async Task PatchRequest(TransportRequest transportRequest) { TransportResponse response; + UnityWebRequest patchRequest = null; try { - UnityWebRequest patchRequest; + if (!string.IsNullOrEmpty(transportRequest.BodyContentString)) { patchRequest = UnityWebRequest.Put(transportRequest.RequestUrl, transportRequest.BodyContentString); } else if (transportRequest.BodyContentBytes != null) { @@ -138,20 +183,18 @@ public async Task PatchRequest(TransportRequest transportRequ }; response = await taskCompletionSource.Task.ConfigureAwait(false); } catch (Exception ex) { - Debug.LogError($"PATCH Error: {ex}"); - response = new TransportResponse() { - RequestUrl = transportRequest.RequestUrl, - Error = ex - }; + response = GetTransportResponseForRequestException(ex, transportRequest, patchRequest); + } finally { + transportRequest.CancellationTokenSource?.Dispose(); } return response; } public async Task PutRequest(TransportRequest transportRequest) { + UnityWebRequest putRequest = null; TransportResponse response; try { - UnityWebRequest putRequest; if (!string.IsNullOrEmpty(transportRequest.BodyContentString)) { putRequest = UnityWebRequest.Put(transportRequest.RequestUrl, transportRequest.BodyContentString); } else if (transportRequest.BodyContentBytes != null) { @@ -171,11 +214,9 @@ public async Task PutRequest(TransportRequest transportReques }; response = await taskCompletionSource.Task.ConfigureAwait(false); } catch (Exception ex) { - Debug.LogError($"PUT Error: {ex}"); - response = new TransportResponse() { - RequestUrl = transportRequest.RequestUrl, - Error = ex - }; + response = GetTransportResponseForRequestException(ex, transportRequest, putRequest); + } finally { + transportRequest.CancellationTokenSource?.Dispose(); } return response; diff --git a/PubNubUnity/Assets/PubNub/package.json b/PubNubUnity/Assets/PubNub/package.json index b56d0f4c..a3191be3 100644 --- a/PubNubUnity/Assets/PubNub/package.json +++ b/PubNubUnity/Assets/PubNub/package.json @@ -3,7 +3,7 @@ "version": "8.2.0", "displayName": "PubNub SDK", "description": "PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks", - "unity": "2021.3", + "unity": "2018.2", "documentationUrl": "https://www.pubnub.com/docs/sdks/unity", "changelogUrl": "https://github.com/pubnub/unity/.pubnub.yml", "licensesUrl": "https://github.com/pubnub/unity/blob/master/LICENSE", @@ -16,7 +16,7 @@ ], "author": { "name": "PubNub", - "email": "michal.dobrzanski@pubnub.com", + "email": "jakub.grzesiowski@pubnub.com", "url": "https://pubnub.com/" }, "samples": [ diff --git a/PubNubUnity/ProjectSettings/ProjectSettings.asset b/PubNubUnity/ProjectSettings/ProjectSettings.asset index 2a47e973..432652db 100644 --- a/PubNubUnity/ProjectSettings/ProjectSettings.asset +++ b/PubNubUnity/ProjectSettings/ProjectSettings.asset @@ -745,7 +745,7 @@ PlayerSettings: assemblyVersionValidation: 0 gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: - Standalone: 3 + Standalone: 6 m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: PubnubUnity