I notice that Parse Unity support still doesn't provide push notification for iOS.
Has anyone implemented a Unity plugin or another solution to support iOS Push Notifications via Parse?
(Cross posted on Unity Answers.)
It's actually possible now, using a ParseObject to mock up the ParseInstallation object.
Gist here: https://gist.github.com/gfosco/a3d092651c32ba3385e6
Explanation in the Parse Google Group: https://groups.google.com/d/msg/parse-developers/ku8-r91_o6s/6ioQ9T2TP7wJ
Attach this script to a GameObject, replace the important parts with your own:
using UnityEngine;
using System.Collections;
using Parse;
public class PushBehaviorScript : MonoBehaviour {
bool tokenSent = false;
public ParseObject currentInstallation = null;
void Start () {
if (PlayerPrefs.HasKey ("currentInstallation")) {
string objId = PlayerPrefs.GetString ("currentInstallation");
currentInstallation = ParseObject.CreateWithoutData ("_Installation", objId);
}
if (currentInstallation == null) {
#if UNITY_IPHONE && !UNITY_EDITOR
NotificationServices.RegisterForRemoteNotificationTypes (RemoteNotificationType.Alert | RemoteNotificationType.Badge | RemoteNotificationType.Sound);
#endif
}
}
void FixedUpdate () {
if (!tokenSent && currentInstallation == null) {
#if UNITY_IPHONE && !UNITY_EDITOR
byte[] token = NotificationServices.deviceToken;
if(token != null) {
tokenSent = true;
string tokenString = System.BitConverter.ToString(token).Replace("-", "").ToLower();
Debug.Log ("OnTokenReived");
Debug.Log (tokenString);
ParseObject obj = new ParseObject("_Installation");
obj["deviceToken"] = tokenString;
obj["appIdentifier"] = "com.parse.unitypush";
obj["deviceType"] = "ios";
obj["timeZone"] = "UTC";
obj["appName"] = "UnityPushTest";
obj["appVersion"] = "1.0.0";
obj["parseVersion"] = "1.3.0";
obj.SaveAsync().ContinueWith(t =>
{
if (obj.ObjectId != null) {
PlayerPrefs.SetString ("currentInstallation", obj.ObjectId);
}
});
}
#endif
}
}
}
To implement iOS push with parse.com You need to get the token from apple first. Then save Current instalation
Unity does have this functionality build in now.
//push notification
bool tokenSent = false;
void RegisterForPush()
{
Debug.Log("Register for push");
tokenSent = false;
#if UNITY_IOS
UnityEngine.iOS.NotificationServices.RegisterForNotifications(NotificationType.Alert |
NotificationType.Badge |
NotificationType.Sound, true);
#endif
}
void Update () {
if (!tokenSent) {
byte[] token = UnityEngine.iOS.NotificationServices.deviceToken;
if (token != null) {
// send token to a provider
tokenSent = true;
string hexToken = "%" + System.BitConverter.ToString(token).Replace('-', '%');
#if UNITY_IOS
ParseManager.instance.RegisterForPush(hexToken);
#endif
}
}
}
And inside ParseManager (or whatever class you use to manage parse>client communication)
public void RegisterForPush(string token) {
Debug.Log("Parse updating instalation");
ParseInstallation instalation = ParseInstallation.CurrentInstallation;
instalation["deviceToken"] = token;
instalation["user"] = ParseUser.CurrentUser.ObjectId;
instalation["timeZoneOffset"] = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
instalation.SaveAsync();
}
Tested on Unity 5.1.2 and iOS 8.4
Related
This is the code I am using for QR Scan. It uses XR for Camera input and ZXing to decode the QR Code. I have been at this for 3 days and still have no clue what I am doing wrong. I do not know whether it is that code isn't able to decode the QR, or it can but isn't able to print it out on Output text. Any help would be greatly appreciated. Thank you! :)
These are the libraries I am using :
using System.Collections;
using UnityEngine;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.XR.ARFoundation;
using ZXing;
using TMPro;
This is the code :
IBarcodeReader _reader;
ARCameraManager _arCam;
AudioSource _audioSrc;
ARRaycastManager _arRay;
private Texture2D _arTexture;
private TextMeshPro _outputText;
private void Awake()
{
_arCam = FindObjectOfType<ARCameraManager>();
_audioSrc = FindObjectOfType<AudioSource>();
_arRay = FindObjectOfType<ARRaycastManager>();
_reader = new BarcodeReader();
_arCam.frameReceived += OnCameraFrameReceived; //When camera receives frame.
}
//Fires off when Frame is received.
void OnCameraFrameReceived(ARCameraFrameEventArgs eventArgs)
{
if ((Time.frameCount % 15) == 0)
{
XRCpuImage _image;
if(_arCam.TryAcquireLatestCpuImage(out _image))
{
StartCoroutine(ProcessQRCode(_image));
_image.Dispose();
}
}
}
//Processes the QR Code in the _image.
IEnumerator ProcessQRCode(XRCpuImage _image)
{
var request = _image.ConvertAsync(new XRCpuImage.ConversionParams { inputRect = new RectInt(0, 0, _image.width, _image.height),
outputDimensions = new Vector2Int(_image.width / 2, _image.height / 2),
outputFormat = TextureFormat.RGB24
});
while (!request.status.IsDone())
yield return null;
if (request.status != XRCpuImage.AsyncConversionStatus.Ready)
{
Debug.LogErrorFormat("Request failed with status {0}", request.status);
request.Dispose();
yield break;
}
var rawData = request.GetData<byte>();
if(_arTexture == null)
{
_arTexture = new Texture2D(
request.conversionParams.outputDimensions.x,
request.conversionParams.outputDimensions.y,
request.conversionParams.outputFormat,
false
);
}
_arTexture.LoadRawTextureData(rawData);
_arTexture.Apply();
byte[] barcodeBitmap = _arTexture.GetRawTextureData();
LuminanceSource source = new RGBLuminanceSource(barcodeBitmap, _arTexture.width, _arTexture.height);
var result = _reader.Decode(source);
if(result != null)
{
var QRContents = result.Text;
_outputText.text = QRContents;
_audioSrc.Play();
}
}
https://github.com/googlevr/tilt-brush#enabling-native-oculus-support
If you open this project (Unity Version 2018.4.11f1) and upgrade to 2020.3.33f1
CS0117: 'VREditor' does not contain a definition for 'GetVREnabledDevicesOnTargetGroup'
The above error occurs, so I looked it up on Google: https://forum.unity.com/threads/steamvr-does-not-work.928503/
The solution is on this page? I found the solution on this page.
https://github.com/ValveSoftware/unity-xr-plugin
When I import this one and import the latest version of SteamVR, I get the error in the title.
Is there a solution?
Here is the code with error:cs0117
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
//
// Purpose: Prompt developers to use settings most compatible with SteamVR.
//
//=============================================================================
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
using System.Linq;
namespace Valve.VR
{
[InitializeOnLoad]
public class SteamVR_AutoEnableVR
{
static SteamVR_AutoEnableVR()
{
EditorApplication.update += Update;
}
protected const string openVRString = "OpenVR";
protected const string openVRPackageString = "com.unity.xr.openvr.standalone";
#if UNITY_2018_2_OR_NEWER
private enum PackageStates
{
None,
WaitingForList,
WaitingForAdd,
WaitingForAddConfirm,
Installed,
Failed,
}
private static UnityEditor.PackageManager.Requests.ListRequest listRequest;
private static UnityEditor.PackageManager.Requests.AddRequest addRequest;
private static PackageStates packageState = PackageStates.None;
private static System.Diagnostics.Stopwatch addingPackageTime = new System.Diagnostics.Stopwatch();
private static System.Diagnostics.Stopwatch addingPackageTimeTotal = new System.Diagnostics.Stopwatch();
private static float estimatedTimeToInstall = 80;
private static int addTryCount = 0;
#endif
public static void Update()
{
if (SteamVR_Settings.instance.autoEnableVR)
{
bool enabledVR = false;
if (UnityEditor.PlayerSettings.virtualRealitySupported == false)
{
UnityEditor.PlayerSettings.virtualRealitySupported = true;
enabledVR = true;
Debug.Log("<b>[SteamVR Setup]</b> Enabled virtual reality support in Player Settings. (you can disable this by unchecking Assets/SteamVR/SteamVR_Settings.autoEnableVR)");
}
UnityEditor.BuildTargetGroup currentTarget = UnityEditor.EditorUserBuildSettings.selectedBuildTargetGroup;
#if (UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
string[] devices = UnityEditorInternal.VR.VREditor.GetVREnabledDevices(currentTarget);
#else
string[] devices = UnityEditorInternal.VR.VREditor.GetVREnabledDevicesOnTargetGroup(currentTarget);
#endif
bool hasOpenVR = devices.Any(device => string.Equals(device, openVRString, System.StringComparison.CurrentCultureIgnoreCase));
if (hasOpenVR == false || enabledVR)
{
string[] newDevices;
if (enabledVR && hasOpenVR == false)
{
newDevices = new string[] { openVRString }; //only list openvr if we enabled it
}
else
{
List<string> devicesList = new List<string>(devices); //list openvr as the first option if it wasn't in the list.
if (hasOpenVR)
devicesList.Remove(openVRString);
devicesList.Insert(0, openVRString);
newDevices = devicesList.ToArray();
}
#if (UNITY_5_6 || UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
UnityEditorInternal.VR.VREditor.SetVREnabledDevices(currentTarget, newDevices);
#else
UnityEditorInternal.VR.VREditor.SetVREnabledDevicesOnTargetGroup(currentTarget, newDevices);
#endif
Debug.Log("<b>[SteamVR Setup]</b> Added OpenVR to supported VR SDKs list.");
}
#if UNITY_2018_2_OR_NEWER
//2018+ requires us to manually add the OpenVR package
switch (packageState)
{
case PackageStates.None:
//see if we have the package
listRequest = UnityEditor.PackageManager.Client.List(true);
packageState = PackageStates.WaitingForList;
break;
case PackageStates.WaitingForList:
if (listRequest.IsCompleted)
{
if (listRequest.Error != null || listRequest.Status == UnityEditor.PackageManager.StatusCode.Failure)
{
packageState = PackageStates.Failed;
break;
}
bool hasPackage = listRequest.Result.Any(package => package.name == openVRPackageString);
if (hasPackage == false)
{
//if we don't have the package - then install it
addRequest = UnityEditor.PackageManager.Client.Add(openVRPackageString);
packageState = PackageStates.WaitingForAdd;
addTryCount++;
Debug.Log("<b>[SteamVR Setup]</b> Installing OpenVR package...");
addingPackageTime.Start();
addingPackageTimeTotal.Start();
}
else
{
//if we do have the package do nothing
packageState = PackageStates.Installed; //already installed
}
}
break;
case PackageStates.WaitingForAdd:
if (addRequest.IsCompleted)
{
if (addRequest.Error != null || addRequest.Status == UnityEditor.PackageManager.StatusCode.Failure)
{
packageState = PackageStates.Failed;
break;
}
else
{
//if the package manager says we added it then confirm that with the list
listRequest = UnityEditor.PackageManager.Client.List(true);
packageState = PackageStates.WaitingForAddConfirm;
}
}
else
{
if (addingPackageTimeTotal.Elapsed.TotalSeconds > estimatedTimeToInstall)
estimatedTimeToInstall *= 2; // :)
string dialogText;
if (addTryCount == 1)
dialogText = "Installing OpenVR from Unity Package Manager...";
else
dialogText = "Retrying OpenVR install from Unity Package Manager...";
bool cancel = UnityEditor.EditorUtility.DisplayCancelableProgressBar("SteamVR", dialogText, (float)addingPackageTimeTotal.Elapsed.TotalSeconds / estimatedTimeToInstall);
if (cancel)
packageState = PackageStates.Failed;
if (addingPackageTime.Elapsed.TotalSeconds > 10)
{
Debug.Log("<b>[SteamVR Setup]</b> Waiting for package manager to install OpenVR package...");
addingPackageTime.Stop();
addingPackageTime.Reset();
addingPackageTime.Start();
}
}
break;
case PackageStates.WaitingForAddConfirm:
if (listRequest.IsCompleted)
{
if (listRequest.Error != null)
{
packageState = PackageStates.Failed;
break;
}
bool hasPackage = listRequest.Result.Any(package => package.name == openVRPackageString);
if (hasPackage == false)
{
if (addTryCount == 1)
{
addRequest = UnityEditor.PackageManager.Client.Add(openVRPackageString);
packageState = PackageStates.WaitingForAdd;
addTryCount++;
Debug.Log("<b>[SteamVR Setup]</b> Retrying OpenVR package install...");
}
else
{
packageState = PackageStates.Failed;
}
}
else
{
packageState = PackageStates.Installed; //installed successfully
Debug.Log("<b>[SteamVR Setup]</b> Successfully installed OpenVR package.");
}
}
break;
}
if (packageState == PackageStates.Failed || packageState == PackageStates.Installed)
{
addingPackageTime.Stop();
addingPackageTimeTotal.Stop();
UnityEditor.EditorUtility.ClearProgressBar();
UnityEditor.EditorApplication.update -= Update; //we're done trying to auto-enable vr
if (packageState == PackageStates.Failed)
{
string failtext = "The Unity Package Manager failed to automatically install the OpenVR package. Please open the Package Manager Window and try to install it manually.";
UnityEditor.EditorUtility.DisplayDialog("SteamVR", failtext, "Ok");
Debug.Log("<b>[SteamVR Setup]</b> " + failtext);
}
}
#else
UnityEditor.EditorApplication.update -= Update;
#endif
}
}
}
}
Here is the code with error:cs0234
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
//
// Purpose: Prompt developers to use settings most compatible with SteamVR.
//
//=============================================================================
#if (UNITY_2019_1_OR_NEWER)
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Reflection;
using Valve.VR.InteractionSystem;
using UnityEditor.Callbacks;
#if OPENVR_XR_API
using UnityEditor.XR.Management.Metadata;
using UnityEngine.XR.Management;
using UnityEditor.XR.Management;
#endif
#pragma warning disable CS0618
#pragma warning disable CS0219
#pragma warning disable CS0414
namespace Valve.VR
{
#if (UNITY_2019_1_OR_NEWER && !UNITY_2020_1_OR_NEWER)
public class SteamVR_AutoEnableVR_2019to2020
{
[DidReloadScripts]
private static void OnReload()
{
#if !OPENVR_XR_API
//if we don't have xr installed, check to see if we have vr installed. if we don't have vr installed, ask which they do want to install.
SteamVR_AutoEnableVR_2019.CheckAndAsk();
#else
//since we already have xr installed, we know we just want to enable it
SteamVR_AutoEnableVR_UnityXR.EnableUnityXR();
#endif
}
}
#endif
#if (UNITY_2020_1_OR_NEWER)
public class SteamVR_AutoEnableVR_2020Plus
{
[DidReloadScripts]
private static void OnReload()
{
#if !OPENVR_XR_API
SteamVR_AutoEnableVR_UnityXR.InstallAndEnableUnityXR();
#else
//since we already have xr installed, we know we just want to enable it
SteamVR_AutoEnableVR_UnityXR.EnableUnityXR();
#endif
}
}
#endif
#if (UNITY_2019_1_OR_NEWER && !UNITY_2020_1_OR_NEWER)
public class SteamVR_AutoEnableVR_2019
{
public static void CheckAndAsk()
{
EditorApplication.update += Update;
}
protected const string openVRString = "OpenVR";
protected const string unityOpenVRPackageString = "com.unity.xr.openvr.standalone";
protected const string valveOpenVRPackageString = "com.valvesoftware.unity.openvr";
private enum PackageStates
{
None,
WaitingForList,
Complete,
Failed,
}
private static UnityEditor.PackageManager.Requests.ListRequest listRequest;
private static PackageStates packageState = PackageStates.None;
private static void End()
{
packageState = PackageStates.None;
UnityEditor.EditorUtility.ClearProgressBar();
EditorApplication.update -= Update;
}
private static void ShowDialog()
{
int shouldInstall = UnityEditor.EditorUtility.DisplayDialogComplex("SteamVR", "The SteamVR Unity Plugin can be used with the legacy Unity VR API (Unity 5.4 - 2019) or with the Unity XR API (2019+). Would you like to install in legacy VR mode or for Unity XR?", "Legacy VR", "Cancel", "Unity XR");
switch (shouldInstall)
{
case 0: //legacy vr
SteamVR_AutoEnableVR_UnityPackage.InstallAndEnableUnityVR();
break;
case 1: //cancel
break;
case 2: //unity xr
SteamVR_AutoEnableVR_UnityXR.InstallAndEnableUnityXR();
break;
}
End();
}
public static void Update()
{
if (!SteamVR_Settings.instance.autoEnableVR || Application.isPlaying)
End();
if (UnityEditor.PlayerSettings.virtualRealitySupported == false)
{
ShowDialog();
return;
}
switch (packageState)
{
case PackageStates.None:
//see if we have the package
listRequest = UnityEditor.PackageManager.Client.List(true);
packageState = PackageStates.WaitingForList;
break;
case PackageStates.WaitingForList:
if (listRequest.IsCompleted)
{
if (listRequest.Error != null || listRequest.Status == UnityEditor.PackageManager.StatusCode.Failure)
{
packageState = PackageStates.Failed;
break;
}
string packageName = unityOpenVRPackageString;
bool hasPackage = listRequest.Result.Any(package => package.name == packageName);
if (hasPackage == false)
ShowDialog();
else //if we do have the package, do nothing
End();
}
break;
case PackageStates.Failed:
End();
string failtext = "The Unity Package Manager failed to verify the OpenVR package. If you were trying to install it you may need to open the Package Manager Window and try to install it manually.";
UnityEditor.EditorUtility.DisplayDialog("SteamVR", failtext, "Ok");
Debug.Log("<b>[SteamVR Setup]</b> " + failtext);
break;
}
}
}
#endif
// todo: split the below into an install and an enable section
public class SteamVR_AutoEnableVR_UnityXR
{
public static void InstallAndEnableUnityXR()
{
StartXRInstaller();
EditorApplication.update += Update;
}
public static void EnableUnityXR()
{
EditorApplication.update += Update;
}
protected const string openVRString = "OpenVR";
protected const string unityOpenVRPackageString = "com.unity.xr.openvr.standalone";
protected const string valveOpenVRPackageString = "com.valvesoftware.unity.openvr";
private enum PackageStates
{
None,
WaitingForList,
WaitingForAdd,
WaitingForAddConfirm,
Installed,
Failed,
}
private static UnityEditor.PackageManager.Requests.ListRequest listRequest;
private static UnityEditor.PackageManager.Requests.AddRequest addRequest;
private static PackageStates packageState = PackageStates.None;
private static System.Diagnostics.Stopwatch addingPackageTime = new System.Diagnostics.Stopwatch();
private static System.Diagnostics.Stopwatch addingPackageTimeTotal = new System.Diagnostics.Stopwatch();
private static float estimatedTimeToInstall = 80;
private static int addTryCount = 0;
private static string enabledLoaderKey = null;
private static MethodInfo isLoaderAssigned;
private static MethodInfo installPackageAndAssignLoaderForBuildTarget;
private static Type[] isLoaderAssignedMethodParameters;
private static object[] isLoaderAssignedCallParameters;
private static void End()
{
addingPackageTime.Stop();
addingPackageTimeTotal.Stop();
UnityEditor.EditorUtility.ClearProgressBar();
EditorApplication.update -= Update;
}
public static void Update()
{
if (!SteamVR_Settings.instance.autoEnableVR)
End();
#if OPENVR_XR_API
EnableLoader();
#endif
}
#if OPENVR_XR_API
private static EditorWindow settingsWindow = null;
private static int skipEditorFrames = 5;
public static void EnableLoader()
{
if (skipEditorFrames > 0)
{
skipEditorFrames--;
return;
}
if (enabledLoaderKey == null)
enabledLoaderKey = string.Format(valveEnabledLoaderKeyTemplate, SteamVR_Settings.instance.editorAppKey);
if (EditorPrefs.HasKey(enabledLoaderKey) == false)
{
if (UnityEditor.PlayerSettings.virtualRealitySupported == true)
{
UnityEditor.PlayerSettings.virtualRealitySupported = false;
Debug.Log("<b>[SteamVR Setup]</b> Disabled virtual reality support in Player Settings. <b>Because you're using XR Manager. Make sure OpenVR Loader is enabled in XR Manager UI.</b> (you can disable this by unchecking Assets/SteamVR/SteamVR_Settings.autoEnableVR)");
}
var generalSettings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(BuildTargetGroup.Standalone);
if (generalSettings == null)
{
if (settingsWindow == null)
{
settingsWindow = SettingsService.OpenProjectSettings("Project/XR Plug-in Management");
settingsWindow.Repaint();
return;
}
if (settingsWindow == null || generalSettings == null)
{
Debug.LogWarning("<b>[SteamVR Setup]</b> Unable to access standalone xr settings while trying to enable OpenVR Loader. <b>You may need to manually enable OpenVR Loader in XR Plug-in Management (Project Settings).</b> (you can disable this by unchecking Assets/SteamVR/SteamVR_Settings.autoEnableVR)");
return;
}
}
if (generalSettings.AssignedSettings == null)
{
var assignedSettings = ScriptableObject.CreateInstance<XRManagerSettings>() as XRManagerSettings;
generalSettings.AssignedSettings = assignedSettings;
EditorUtility.SetDirty(generalSettings);
}
bool existing = generalSettings.AssignedSettings.loaders.Any(loader => loader.name == valveOpenVRLoaderType);
foreach (var loader in generalSettings.AssignedSettings.loaders)
{
Debug.Log("loader: " + loader.name);
}
if (!existing)
{
bool status = XRPackageMetadataStore.AssignLoader(generalSettings.AssignedSettings, valveOpenVRLoaderType, BuildTargetGroup.Standalone);
if (status)
Debug.Log("<b>[SteamVR Setup]</b> Enabled OpenVR Loader in XR Management");
else
Debug.LogError("<b>[SteamVR Setup]</b> Failed to enable enable OpenVR Loader in XR Management. You may need to manually open the XR Plug-in Management tab in project settings and check the OpenVR Loader box.");
}
EditorPrefs.SetBool(enabledLoaderKey, true);
}
End();
}
#endif
protected const string valveEnabledLoaderKeyTemplate = "valve.enabledxrloader.{0}";
protected const string valveOpenVRLoaderType = "Unity.XR.OpenVR.OpenVRLoader";
private static void StartXRInstaller()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int assemblyIndex = 0; assemblyIndex < assemblies.Length; assemblyIndex++)
{
Assembly assembly = assemblies[assemblyIndex];
Type type = assembly.GetType("Unity.XR.OpenVR.OpenVRPackageInstaller");
if (type != null)
{
MethodInfo preinitMethodInfo = type.GetMethod("Start");
if (preinitMethodInfo != null)
{
preinitMethodInfo.Invoke(null, new object[] { true });
return;
}
}
}
}
}
}
#endif
I am using a non-consumable product to switch off ads for good, after purchasing.
When users buy pro everything works fine. Ads are switched off, also autorenewal in google store works fine after the user reinstalls the app.
My problem starts when the user wants a refund. After all, will be processed by Google and the customer will get his money. I don't know how where to subscribe to my function to turn off the pro version again on the users' app.
I am using IAPManager:
public class IAPManager : MonoBehaviour, IStoreListener
{
public List<Product> ProductList = new List<Product>();
public const string Pro = "pro";
private const string _androidPostFix = "_android";
[SerializeField] I18NText purchaseProBtnText;
public IAPManager Instance;
private void Awake()
{
if (Instance == null) Instance = this;
else Destroy(gameObject);
Init();
EventManager.PurchaseProduct += PurchaseProduct;
EventManager.GetProLocalizedPriceString += GetProLocalPriceString;
}
private void OnDestroy()
{
EventManager.PurchaseProduct -= PurchaseProduct;
EventManager.GetProLocalizedPriceString -= GetProLocalPriceString;
}
public List<Product> AllProducts { get { return m_Controller.products.all.ToList(); } }
private IStoreController m_Controller;
private ITransactionHistoryExtensions m_TransactionHistoryExtensions;
private IGooglePlayStoreExtensions m_GooglePlayStoreExtensions;
private bool m_IsGooglePlayStoreSelected;
private bool m_PurchaseInProgress;
#if RECEIPT_VALIDATION
private CrossPlatformValidator validator;
#endif
private string GetProLocalPriceString()
{
#if UNITY_ANDROID && !UNITY_EDITOR
foreach (Product product in ProductList)
{
if (product.metadata.localizedTitle == Pro)
{
return product.metadata.localizedPriceString;
}
}
return null;
#elif UNITY_EDITOR
foreach (Product product in ProductList)
{
if (product.metadata.localizedTitle == "Fake title for pro")
{
return product.metadata.localizedPriceString;
}
}
return null;
#endif
}
public void Init()
{
var module = StandardPurchasingModule.Instance();
module.useFakeStoreUIMode = FakeStoreUIMode.StandardUser;
var builder = ConfigurationBuilder.Instance(module);
// Set this to true to enable the Microsoft IAP simulator for local testing.
builder.Configure<IMicrosoftConfiguration>().useMockBillingSystem = false;
m_IsGooglePlayStoreSelected = Application.platform == RuntimePlatform.Android && module.appStore == AppStore.GooglePlay;
#if AGGRESSIVE_INTERRUPT_RECOVERY_GOOGLEPLAY
// For GooglePlay, if we have access to a backend server to deduplicate purchases, query purchase history
// when attempting to recover from a network-interruption encountered during purchasing. Strongly recommend
// deduplicating transactions across app reinstallations because this relies upon the on-device, deletable
// TransactionLog database.
builder.Configure<IGooglePlayConfiguration>().aggressivelyRecoverLostPurchases = true;
// Use purchaseToken instead of orderId for all transactions to avoid non-unique transactionIDs for a
// single purchase; two ProcessPurchase calls for one purchase, differing only by which field of the receipt
// is used for the Product.transactionID. Automatically true if aggressivelyRecoverLostPurchases is enabled
// and this API is not called at all.
builder.Configure<IGooglePlayConfiguration>().UsePurchaseTokenForTransactionId(true);
#endif
//builder.AddProduct(Pro, ProductType.NonConsumable);
builder.AddProduct(Pro, ProductType.NonConsumable, new IDs
{
{Pro, GooglePlay.Name},
//{Pro+_iosPostFix, AppleAppStore.Name}
}
);
#if INTERCEPT_PROMOTIONAL_PURCHASES
// On iOS and tvOS we can intercept promotional purchases that come directly from the App Store.
// On other platforms this will have no effect; OnPromotionalPurchase will never be called.
builder.Configure<IAppleConfiguration>().SetApplePromotionalPurchaseInterceptorCallback(OnPromotionalPurchase);
Debug.Log("Setting Apple promotional purchase interceptor callback");
#endif
#if RECEIPT_VALIDATION
string appIdentifier;
#if UNITY_5_6_OR_NEWER
appIdentifier = Application.identifier;
#else
appIdentifier = Application.bundleIdentifier;
#endif
try
{
validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(), appIdentifier);
}
catch (NotImplementedException exception)
{
Debug.Log("Cross Platform Validator Not Implemented: " + exception);
}
#endif
// Now we're ready to initialize Unity IAP.
UnityPurchasing.Initialize(this, builder);
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
m_Controller = controller;
m_TransactionHistoryExtensions = extensions.GetExtension<ITransactionHistoryExtensions>();
m_GooglePlayStoreExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();
#if SUBSCRIPTION_MANAGER
Dictionary<string, string> introductory_info_dict = m_AppleExtensions.GetIntroductoryPriceDictionary();
#endif
// Sample code for expose product sku details for apple store
//Dictionary<string, string> product_details = m_AppleExtensions.GetProductDetails();
Debug.Log("Available items:");
foreach (var item in controller.products.all)
{
if (item.availableToPurchase)
{
Debug.Log(string.Join(" - ",
new[]
{
item.metadata.localizedTitle,
item.metadata.localizedDescription,
item.metadata.isoCurrencyCode,
item.metadata.localizedPrice.ToString(),
item.metadata.localizedPriceString,
item.transactionID,
item.receipt
}));
ProductList.Add(item);
#if INTERCEPT_PROMOTIONAL_PURCHASES
// Set all these products to be visible in the user's App Store according to Apple's Promotional IAP feature
// https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/PromotingIn-AppPurchases/PromotingIn-AppPurchases.html
m_AppleExtensions.SetStorePromotionVisibility(item, AppleStorePromotionVisibility.Show);
#endif
#if SUBSCRIPTION_MANAGER
// this is the usage of SubscriptionManager class
if (item.receipt != null) {
if (item.definition.type == ProductType.Subscription) {
if (checkIfProductIsAvailableForSubscriptionManager(item.receipt)) {
string intro_json = (introductory_info_dict == null || !introductory_info_dict.ContainsKey(item.definition.storeSpecificId)) ? null : introductory_info_dict[item.definition.storeSpecificId];
SubscriptionManager p = new SubscriptionManager(item, intro_json);
SubscriptionInfo info = p.getSubscriptionInfo();
Debug.Log("product id is: " + info.getProductId());
Debug.Log("purchase date is: " + info.getPurchaseDate());
Debug.Log("subscription next billing date is: " + info.getExpireDate());
Debug.Log("is subscribed? " + info.isSubscribed().ToString());
Debug.Log("is expired? " + info.isExpired().ToString());
Debug.Log("is cancelled? " + info.isCancelled());
Debug.Log("product is in free trial peroid? " + info.isFreeTrial());
Debug.Log("product is auto renewing? " + info.isAutoRenewing());
Debug.Log("subscription remaining valid time until next billing date is: " + info.getRemainingTime());
Debug.Log("is this product in introductory price period? " + info.isIntroductoryPricePeriod());
Debug.Log("the product introductory localized price is: " + info.getIntroductoryPrice());
Debug.Log("the product introductory price period is: " + info.getIntroductoryPricePeriod());
Debug.Log("the number of product introductory price period cycles is: " + info.getIntroductoryPricePeriodCycles());
} else {
Debug.Log("This product is not available for SubscriptionManager class, only products that are purchase by 1.19+ SDK can use this class.");
}
} else {
Debug.Log("the product is not a subscription product");
}
} else {
Debug.Log("the product should have a valid receipt");
}
#endif
}
}
}
public void Restore()
{
m_GooglePlayStoreExtensions.RestoreTransactions(OnTransactionsRestored);
Debug.Log("Restore method");
}
private void OnTransactionsRestored(bool success)
{
Debug.Log("Transactions restored." + success);
}
public void OnPurchaseFailed(Product item, PurchaseFailureReason r)
{
Debug.Log("Purchase failed: " + item.definition.id);
Debug.Log(r);
// Detailed debugging information
Debug.Log("Store specific error code: " + m_TransactionHistoryExtensions.GetLastStoreSpecificPurchaseErrorCode());
if (m_TransactionHistoryExtensions.GetLastPurchaseFailureDescription() != null)
{
Debug.Log("Purchase failure description message: " +
m_TransactionHistoryExtensions.GetLastPurchaseFailureDescription().message);
}
m_PurchaseInProgress = false;
}
public void OnInitializeFailed(InitializationFailureReason error)
{
Debug.Log("Billing failed to initialize!");
switch (error)
{
case InitializationFailureReason.AppNotKnown:
Debug.LogError("Is your App correctly uploaded on the relevant publisher console?");
break;
case InitializationFailureReason.PurchasingUnavailable:
// Ask the user if billing is disabled in device settings.
Debug.Log("Billing disabled!");
break;
case InitializationFailureReason.NoProductsAvailable:
// Developer configuration error; check product metadata.
Debug.Log("No products available for purchase!");
break;
}
}
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
{
Debug.Log("Purchase OK: " + e.purchasedProduct.definition.id);
Debug.Log("Receipt: " + e.purchasedProduct.receipt);
m_PurchaseInProgress = false;
#if RECEIPT_VALIDATION // Local validation is available for GooglePlay, and Apple stores
if (m_IsGooglePlayStoreSelected ||
Application.platform == RuntimePlatform.IPhonePlayer ||
Application.platform == RuntimePlatform.OSXPlayer ||
Application.platform == RuntimePlatform.tvOS) {
try {
var result = validator.Validate(e.purchasedProduct.receipt);
Debug.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result) {
Debug.Log(productReceipt.productID);
Debug.Log(productReceipt.purchaseDate);
Debug.Log(productReceipt.transactionID);
GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
if (null != google) {
Debug.Log(google.purchaseState);
Debug.Log(google.purchaseToken);
}
AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
if (null != apple) {
Debug.Log(apple.originalTransactionIdentifier);
Debug.Log(apple.subscriptionExpirationDate);
Debug.Log(apple.cancellationDate);
Debug.Log(apple.quantity);
}
// For improved security, consider comparing the signed
// IPurchaseReceipt.productId, IPurchaseReceipt.transactionID, and other data
// embedded in the signed receipt objects to the data which the game is using
// to make this purchase.
}
}
catch (IAPSecurityException ex)
{
Debug.Log("Invalid receipt, not unlocking content. " + ex);
return PurchaseProcessingResult.Complete;
}
catch (NotImplementedException exception)
{
Debug.Log("Cross Platform Validator Not Implemented: " + exception);
}
}
#endif
// Unlock content from purchases here.
if (e.purchasedProduct.definition.id == Pro)
{
//PlayerPrefs.SetInt("pro", 1);
Debug.Log("PURCHASED PRODUCT!");
//AdsManager.Instance.ProActive = true;
AdsManager.Instance.HideAdsPro();
//EventBroker.CallOnProBought();
}
#if USE_PAYOUTS
if (e.purchasedProduct.definition.payouts != null) {
Debug.Log("Purchase complete, paying out based on defined payouts");
foreach (var payout in e.purchasedProduct.definition.payouts) {
Debug.Log(string.Format("Granting {0} {1} {2} {3}", payout.quantity, payout.typeString, payout.subtype, payout.data));
}
}
#endif
#if DELAY_CONFIRMATION
StartCoroutine(ConfirmPendingPurchaseAfterDelay(e.purchasedProduct));
return PurchaseProcessingResult.Pending;
#else
return PurchaseProcessingResult.Complete;
#endif
}
/// <summary>
/// Call this method to start purchase product.
/// </summary>
/// <param name="productID">Product ID from products on Google Dev Dashboard</param>
public void PurchaseProduct(string productID)
{
Debug.Log("PurchaseProduct");
if (m_PurchaseInProgress == true)
{
Debug.Log("Please wait, purchase in progress");
return;
}
if (m_Controller == null)
{
Debug.LogError("Purchasing is not initialized");
return;
}
if (m_Controller.products.WithID(productID) == null)
{
Debug.LogError("No product has id " + productID);
return;
}
m_PurchaseInProgress = true;
m_Controller.InitiatePurchase(m_Controller.products.WithID(productID), "developerPayload");
}
}
I found a solution myself.
I checked product.hasRecipt to get info if the product is bought.
So the receipt disappears after a successful revoke process in the google app store.
And every time the app is restarted this bool is sent to the app during IAP initialization.
I am working on an application for the HoloLens (1) based on Unity. I am trying to send data via TCP from a Qt-based application (Windows) to the HoloLens. Wireshark shows, that my test package is correctly sent and acknowledged by the HoloLens. The data starts with four bytes containing the length of the message, which starts right after those four bytes. In the following code, first, the four bytes are trying to be received, and afterwards, the message itself.
After executing the code for connecting and sending the data in the client application, StreamSocketListener_ConnectionReceived() is called on the HoloLens. In the next Update() call, ReadTcpData() is called. Now, execution 'stops' at the first call to
tcpMessageSizeBuffer[tcpMessageSizeBytesRead++] = (byte)stream.ReadByte();
At least the debugger jumps out of the code when I try to step over the line. There is no exception caught in the catch block.
I was expecting that the EndOfStream property of StreamReader would be false if there is nothing to read, and consequently, I would receive a valid byte from the stream when calling ReadByte when it was true. I have no clue what goes wrong here. Any hints would be greatly appreciated.
using System;
using System.IO;
using UnityEngine;
#if UNITY_WINRT && !UNITY_EDITOR
using Windows.Networking.Sockets;
using Windows.Networking;
using Windows.Networking.Connectivity;
using Windows.Storage.Streams;
using System.Runtime.InteropServices.WindowsRuntime;
#endif
public class NetworkManager : MonoBehaviour
{
public int tcpPort;
#if UNITY_WINRT && !UNITY_EDITOR
private StreamSocketListener streamSocketListener;
private StreamReader tcpStreamReader = null;
private StreamSocketListenerConnectionReceivedEventArgs connectionArgs;
private DatagramSocket datagramSocket;
private MemoryStream pendingDatagramSocketStream;
#endif
private UInt32 tcpMessageSizeByteCount;
private UInt32 tcpMessageSizeBytesRead;
private byte[] tcpMessageSizeBuffer;
private bool tcpMessageSizeReceived;
private UInt32 tcpMessageByteCount;
private UInt32 tcpMessageBytesRead;
private byte[] tcpMessageBuffer;
// Use this for initialization
void Start()
{
Application.runInBackground = true;
ResetTcpConnection();
}
public void ResetTcpConnection()
{
#if UNITY_WINRT && !UNITY_EDITOR
ResetTcpRead();
if (streamSocketListener != null)
{
tcpStreamReader.Dispose();
tcpStreamReader = null;
connectionArgs = null;
streamSocketListener.Dispose();
streamSocketListener = null;
}
streamSocketListener = new StreamSocketListener();
streamSocketListener.ConnectionReceived += this.StreamSocketListener_ConnectionReceived;
streamSocketListener.BindServiceNameAsync(tcpPort.ToString());
#endif
}
#if UNITY_WINRT && !UNITY_EDITOR
// Process the client connection.
private async void StreamSocketListener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
connectionArgs = args; // Keep this alive
tcpStreamReader = new StreamReader(connectionArgs.Socket.InputStream.AsStreamForRead());
}
#endif
// Update is called once per frame
void Update()
{
#if UNITY_WINRT && !UNITY_EDITOR
if (tcpStreamReader != null && !tcpStreamReader.EndOfStream)
{
Stream stream = tcpStreamReader.BaseStream;
ReadTcpData(ref stream);
}
#endif
}
private void ResetTcpRead()
{
tcpMessageSizeByteCount = sizeof(UInt32);
tcpMessageSizeBytesRead = 0;
tcpMessageSizeBuffer = new byte[tcpMessageSizeByteCount];
tcpMessageSizeReceived = false;
tcpMessageByteCount = 0;
tcpMessageBytesRead = 0;
tcpMessageBuffer = null;
}
private void ReadTcpData(ref Stream stream)
{
try
{
if (!tcpMessageSizeReceived)
{
#if UNITY_WINRT && !UNITY_EDITOR
while(tcpMessageSizeBytesRead < tcpMessageSizeByteCount && !tcpStreamReader.EndOfStream)
{
tcpMessageSizeBuffer[tcpMessageSizeBytesRead++] = (byte)stream.ReadByte();
}
if(tcpMessageSizeBytesRead == tcpMessageSizeByteCount)
{
tcpMessageByteCount = BitConverter.ToUInt32(tcpMessageSizeBuffer, 0);
}
#endif
if (tcpMessageByteCount > 0)
{
tcpMessageBuffer = new byte[tcpMessageByteCount];
tcpMessageSizeReceived = true;
}
}
else
{
// Read the message
int bytesToRead = (int)(tcpMessageByteCount - tcpMessageBytesRead);
bytesToRead = bytesToRead > 10000 ? 10000 : bytesToRead;
int bytesRead = stream.Read(tcpMessageBuffer, (int)tcpMessageBytesRead, bytesToRead);
tcpMessageBytesRead += (uint)bytesRead;
// Did we finish reading the message?
if (tcpMessageBytesRead >= tcpMessageByteCount)
{
ResetTcpRead();
}
}
}
catch (Exception e)
{
throw e;
}
}
}
Found the problem - I have to use BinaryReader and replace the code reading the length of the message such:
while(tcpMessageSizeBytesRead < tcpMessageSizeByteCount)
{
tcpMessageSizeBuffer[tcpMessageSizeBytesRead++] = (byte)binaryReader.ReadByte();
}
For the sake of consistency, also the part of the code actually reading the message can be adapted to use BinaryReader.
I have a piece of code that I want to use with Unity 2018.2.14.f1.
#if UNITY_WSA && !UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
namespace SerialForUWP
{
public class SerialComHelper
{
public async static Task<string[]> GetPorts()
{
var serials = SerialDevice.GetDeviceSelector();
var coms = await DeviceInformation.FindAllAsync(serials);
List<string> results = new List<string>();
foreach (var device in coms)
{
using (var serialDevice = await SerialDevice.FromIdAsync(device.Id))
{
if (serialDevice != null)
{
var port = serialDevice.PortName;
results.Add(port.ToString());
}
}
}
return results.ToArray();
}
}
}
#endif
I compile for UWP using IL2CPP :
I also already updated the manifest of the cpp projet :
<DeviceCapability Name="serialcommunication">
<Device Id="any">
<Function Type="name:serialPort" />
</Device>
</DeviceCapability>
As soon as I try to use the GetPorts() function my app freeze.
void Update()
{
text.text = Time.time.ToString();
if (Input.GetKeyUp(KeyCode.Space))
{
try
{
#if UNITY_WSA && !UNITY_EDITOR
foreach (var com in SerialForUWP.SerialComHelper.GetPorts().Result)
{
text.text = com;
}
#endif
}
catch (Exception ex)
{
text.text = ex.ToString();
}
}
}
I got no error, no exception.
Can anyone help please ?
To get the exceptions use:
Debug.Log(ex.ToString()) instead of Text.text = ex.ToString()
According to this answer I can't use .Result