/// <summary> /// Initializes the SOOMLA SDK. /// </summary> /// <param name="storeAssets">Your game's economy.</param> /// <exception cref="ExitGUIException">Thrown if soomlaSecret is missing or has not been changed.</exception> public static bool Initialize(IStoreAssets storeAssets) { if (string.IsNullOrEmpty(CoreSettings.SoomlaSecret)) { SoomlaUtils.LogError(TAG, "MISSING SoomlaSecret !!! Stopping here !!"); throw new ExitGUIException(); } if (CoreSettings.SoomlaSecret == CoreSettings.ONLY_ONCE_DEFAULT) { SoomlaUtils.LogError(TAG, "You have to change SoomlaSecret !!! Stopping here !!"); throw new ExitGUIException(); } var storeEvents = GameObject.FindObjectOfType <StoreEvents> (); if (storeEvents == null) { SoomlaUtils.LogDebug(TAG, "StoreEvents Component not found in scene. We're continuing from here but you won't get many events."); } if (Initialized) { StoreEvents.Instance.onUnexpectedStoreError("{\"errorCode\": 0}", true); SoomlaUtils.LogError(TAG, "SoomlaStore is already initialized. You can't initialize it twice!"); return(false); } SoomlaUtils.LogDebug(TAG, "SoomlaStore Initializing ..."); StoreInfo.SetStoreAssets(storeAssets); instance._loadBillingService(); #if UNITY_IOS // On iOS we only refresh market items instance._refreshMarketItemsDetails(); #elif UNITY_ANDROID // On Android we refresh market items and restore transactions instance._refreshInventory(); #elif UNITY_WP8 instance._refreshInventory(); #endif Initialized = true; StoreEvents.Instance.onSoomlaStoreInitialized("", true); return(true); }
public override void GetFeed(bool fromStart, FeedSuccess success, FeedFailed fail) { checkPermission("read_stream", () => { int pageNumber; if (fromStart || this.lastPageNumber == 0) { pageNumber = 1; } else { pageNumber = this.lastPageNumber + 1; } this.lastPageNumber = 0; FB.API("/me/feed?limit=" + DEFAULT_FEED_PAGE_SIZE + "&offset=" + DEFAULT_FEED_PAGE_SIZE * (pageNumber - 1), Facebook.HttpMethod.GET, (FBResult result) => { if (result.Error != null) { SoomlaUtils.LogDebug(TAG, "GetFeedCallback[result.Error]: " + result.Error); fail(result.Error); } else { SoomlaUtils.LogDebug(TAG, "GetFeedCallback[result.Text]: " + result.Text); SoomlaUtils.LogDebug(TAG, "GetFeedCallback[result.Texture]: " + result.Texture); JSONObject jsonFeed = new JSONObject(result.Text); SocialPageData <String> resultData = new SocialPageData <String>(); resultData.PageData = StoriesFromFBJsonObjs(jsonFeed["data"].list); resultData.PageNumber = pageNumber; this.lastPageNumber = pageNumber; JSONObject paging = jsonFeed["paging"]; if (paging != null) { resultData.HasMore = (paging["next"] != null); } success(resultData); } }); }, (string errorMessage) => { fail(errorMessage); }); }
/// <summary> /// Takes upgrade from the user, or in other words DOWNGRADES the associated /// <code>VirtualGood</code> (mGood). /// Checks if the current Upgrade is really associated with the <code>VirtualGood</code> and: /// </summary> /// <param name="amount">NOT USED HERE!.</param> /// <param name="notify">see parent.</param> public override int Take(int amount, bool notify) { VirtualGood good = null; try { good = (VirtualGood)StoreInfo.GetItemByItemId(GoodItemId); } catch (VirtualItemNotFoundException) { SoomlaUtils.LogError(TAG, "VirtualGood with itemId: " + GoodItemId + " doesn't exist! Can't downgrade."); return(0); } UpgradeVG upgradeVG = VirtualGoodsStorage.GetCurrentUpgrade(good); // Case: Upgrade is not assigned to this Virtual Good if (upgradeVG != this) { SoomlaUtils.LogError(TAG, "You can't take an upgrade that's not currently assigned." + "The UpgradeVG " + Name + " is not assigned to " + "the VirtualGood: " + good.Name); return(0); } if (!string.IsNullOrEmpty(PrevItemId)) { UpgradeVG prevUpgradeVG = null; // Case: downgrade is not possible because previous upgrade does not exist try { prevUpgradeVG = (UpgradeVG)StoreInfo.GetItemByItemId(PrevItemId); } catch (VirtualItemNotFoundException) { SoomlaUtils.LogError(TAG, "Previous UpgradeVG with itemId: " + PrevItemId + " doesn't exist! Can't downgrade."); return(0); } // Case: downgrade is successful! SoomlaUtils.LogDebug(TAG, "Downgrading " + good.Name + " to: " + prevUpgradeVG.Name); VirtualGoodsStorage.AssignCurrentUpgrade(good, prevUpgradeVG, notify); } // Case: first Upgrade in the series - so we downgrade to NO upgrade. else { SoomlaUtils.LogDebug(TAG, "Downgrading " + good.Name + " to NO-UPGRADE"); VirtualGoodsStorage.RemoveUpgrades(good, notify); } return(base.Take(amount, notify)); }
private void checkPermissions(string[] requestedPermissions, Action success, Action <string> fail) { Action checking = () => { List <string> missedPermissions = new List <string>(); foreach (string requestedPermission in requestedPermissions) { if (!this.permissions.Contains(requestedPermission)) { missedPermissions.Add(requestedPermission); } } if (missedPermissions.Count == 0) { success(); return; } string permissionsStr = String.Join(",", missedPermissions.ToArray()); FB.Login(permissionsStr, (FBResult result) => { if (result.Error != null) { SoomlaUtils.LogDebug(TAG, "LoginCallback[result.Error]: " + result.Error); fail(result.Error); return; } if (!FB.IsLoggedIn) { SoomlaUtils.LogDebug(TAG, "LoginCallback[cancelled]"); fail("User has not granter the permissions"); return; } this.permissions.AddRange(missedPermissions); success(); }); }; if (this.permissions == null) { fetchPermissions(checking, fail); } else { checking(); } }
/// <summary> /// See docs in <see cref="SoomlaProfile.GetContacts"/> /// </summary> /// <param name="fromStart">Should we reset pagination or request the next page</param> /// <param name="success">Callback function that is called if the contacts were fetched successfully.</param> /// <param name="fail">Callback function that is called if fetching contacts failed.</param> public override void GetContacts(bool fromStart, ContactsSuccess success, ContactsFailed fail) { checkPermission("user_friends", () => { int pageNumber; if (fromStart || this.lastPageNumber == 0) { pageNumber = 1; } else { pageNumber = this.lastPageNumber + 1; } this.lastPageNumber = 0; FB.API("/me/friends?fields=id,name,picture,email,first_name,last_name&limit=" + DEFAULT_CONTACTS_PAGE_SIZE + "&offset=" + DEFAULT_CONTACTS_PAGE_SIZE * (pageNumber - 1), Facebook.HttpMethod.GET, (FBResult result) => { if (result.Error != null) { SoomlaUtils.LogDebug(TAG, "GetContactsCallback[result.Error]: " + result.Error); fail(result.Error); } else { SoomlaUtils.LogDebug(TAG, "GetContactsCallback[result.Text]: " + result.Text); SoomlaUtils.LogDebug(TAG, "GetContactsCallback[result.Texture]: " + result.Texture); JSONObject jsonContacts = new JSONObject(result.Text); SocialPageData <UserProfile> resultData = new SocialPageData <UserProfile>(); resultData.PageData = UserProfilesFromFBJsonObjs(jsonContacts["data"].list); resultData.PageNumber = pageNumber; this.lastPageNumber = pageNumber; JSONObject paging = jsonContacts["paging"]; if (paging != null) { resultData.HasMore = (paging["next"] != null); } success(resultData); } }); }, (string errorMessage) => { fail(errorMessage); }); }
/// <summary> /// Handles an <c>onSocialActionFailed</c> event /// </summary> /// <param name="message"> /// Will contain a numeric representation of <c>Provider</c> /// numeric representation of <c>SocialActionType</c>, /// error message and payload</param> public void onSocialActionFailed(String message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onSocialActionFailed"); JSONObject eventJson = new JSONObject(message); Provider provider = Provider.fromInt((int)eventJson["provider"].n); SocialActionType socialAction = SocialActionType.fromInt((int)eventJson["socialActionType"].n); String errorMessage = eventJson["message"].str; JSONObject payloadJSON = new JSONObject(eventJson ["payload"].str); ProfileEvents.OnSocialActionFailed(provider, socialAction, errorMessage, ProfilePayload.GetUserPayload(payloadJSON)); //ProfileEvents.OnSocialActionFailed (new SocialActionFailedEvent(provider, socialAction, errorMessage, ProfilePayload.GetUserPayload(payloadJSON))); }
/// <summary> /// Refreshing GrowInsights with SOOMLA GROW /// </summary> public static void RefreshInsights() { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY Refreshing Insights"); #if UNITY_ANDROID && !UNITY_EDITOR AndroidJNI.PushLocalFrame(100); using (AndroidJavaClass jniGrowInsightsClass = new AndroidJavaClass("com.soomla.insights.GrowInsights")) { AndroidJavaObject jniGrowInsightsInstance = jniGrowInsightsClass.CallStatic <AndroidJavaObject>("getInstance"); jniGrowInsightsInstance.Call("refreshInsights"); } AndroidJNI.PopLocalFrame(IntPtr.Zero); #elif UNITY_IOS && !UNITY_EDITOR growInsights_refreshInsights(); #endif }
/** * Removes any upgrade associated with the given VirtualGood. * * @param good the virtual good to remove the upgrade from * @param notify if true post event to bus */ public void removeUpgrades(VirtualGood good, bool notify) { SoomlaUtils.LogDebug(mTag, "Removing upgrade information from virtual good: " + good.getName()); String itemId = good.getItemId(); String key = keyGoodUpgrade(itemId); KeyValueStorage.DeleteKeyValue(key); if (notify) { BusProvider.Instance.Post(new GoodUpgradeEvent(good, null)); } }
public static void onGoodUnequipped(GoodUnEquippedEvent _Event, bool alsoPush) { SoomlaWpStore.domain.virtualGoods.EquippableVG good = _Event.GetEquippableVG(); SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onVirtualGoodUnEquipped:" + good.getItemId()); EquippableVG vg = (EquippableVG)StoreInfo.GetItemByItemId(good.getItemId()); StoreInventory.RefreshOnGoodUnEquipped(vg); StoreEvents.OnGoodUnEquipped(vg); if (alsoPush) { sep.PushEventOnGoodUnequipped(_Event); } }
/// <summary> /// Handles an <c>onGetContactsFailed</c> event /// </summary> /// <param name="message"> /// Will contain a numeric representation of <c>Provider</c>, /// error message payload</param> public void onGetContactsFailed(String message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onGetContactsFailed"); JSONObject eventJson = new JSONObject(message); Provider provider = Provider.fromInt((int)eventJson["provider"].n); String errorMessage = eventJson["message"].str; JSONObject payloadJSON = new JSONObject(eventJson ["payload"].str); bool fromStart = eventJson["fromStart"].b; ProfileEvents.OnGetContactsFailed(provider, errorMessage, fromStart, ProfilePayload.GetUserPayload(payloadJSON)); }
/* Internal SOOMLA events ... Not meant for public use */ public void onConflict(string message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onConflict:" + message); JSONObject eventJSON = new JSONObject(message); string remoteStateStr = eventJSON["remoteState"].str; string currentStateStr = eventJSON["currentState"].str; string stateDiffStr = eventJSON["stateDiff"].str; JSONObject remoteState = new JSONObject(remoteStateStr); JSONObject currentState = new JSONObject(currentStateStr); JSONObject stateDiff = new JSONObject(stateDiffStr); GrowSync.HandleStateSyncConflict(remoteState, currentState, stateDiff); }
/// <summary> /// Handles an <c>onGoodUpgrade</c> event, which is fired when a specific <c>UpgradeVG</c> has /// been upgraded/downgraded. /// </summary> /// <param name="message">Message that contains information about the good that has been /// upgraded/downgraded.</param> public void onGoodUpgrade(string message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onGoodUpgrade:" + message); string[] vars = Regex.Split(message, "#SOOM#"); VirtualGood vg = (VirtualGood)StoreInfo.GetItemByItemId(vars[0]); UpgradeVG vgu = null; if (vars.Length > 1) { vgu = (UpgradeVG)StoreInfo.GetItemByItemId(vars[1]); } StoreEvents.OnGoodUpgrade(vg, vgu); }
/// <summary> /// Handles the <c>onMarketPurchaseDeferred</c> event, which is fired when a Market purchase was deferred /// until it can be finished by the family delegate. /// Note that this is an iOS only event for when users have set up "Ask to Buy" and the purchaser is /// selected as a family member that needs "family organizer" permission to buy. /// <see href="https://support.apple.com/en-us/HT201089">Apple's explanation of "Ask to Buy"</see> /// </summary> /// <param name="message">Message that contains information about the market purchase that is being /// deferred.</param> public void onMarketPurchaseDeferred(string message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onMarketPurchaseDeferred: " + message); var eventJSON = new JSONObject(message); PurchasableVirtualItem pvi = (PurchasableVirtualItem)StoreInfo.GetItemByItemId(eventJSON["itemId"].str); string payload = ""; if (eventJSON.HasField("payload")) { payload = eventJSON["payload"].str; } StoreEvents.OnMarketPurchaseDeferred(pvi, payload); }
/// <summary> /// Pauses this <c>Level</c>. /// </summary> public void Pause() { if (State != LevelState.Running) { SoomlaUtils.LogError(TAG, "Can't pause a level that is not running. state=" + State); return; } long now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; Elapsed += now - StartTime; StartTime = 0; State = LevelState.Paused; }
/// <summary> /// Pauses this <c>Level</c>. /// </summary> public void Pause() { if (State != LevelState.Running) { SoomlaUtils.LogError(TAG, "Can't pause a level that is not running. state=" + State); return; } long now = this.UseTimeScaling ? Mathf.RoundToInt(Time.time * 1000) : DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; Elapsed += now - StartTime; StartTime = 0; State = LevelState.Paused; }
public void onSoomlaStoreInitialized(string message, bool alsoPush) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onSoomlaStoreInitialized"); StoreInventory.RefreshLocalInventory(); StoreEvents.OnSoomlaStoreInitialized(); if (alsoPush) { #if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR sep.PushEventSoomlaStoreInitialized(); #endif } }
public void onUnexpectedStoreError(string message, bool alsoPush) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY OnUnexpectedStoreError"); JSONObject eventJSON = new JSONObject(message); StoreEvents.OnUnexpectedStoreError((int)eventJSON ["errorCode"].n); if (alsoPush) { #if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR sep.PushEventSoomlaStoreInitialized(); #endif } }
public static void onItemPurchased(ItemPurchasedEvent _Event, bool alsoPush) { SoomlaWpStore.domain.PurchasableVirtualItem purchasableVirtualItem = _Event.GetPurchasableVirtualItem(); String payload = _Event.GetPayload(); SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onItemPurchased:" + purchasableVirtualItem.getItemId() + " " + payload); PurchasableVirtualItem pvi = (PurchasableVirtualItem)StoreInfo.GetItemByItemId(purchasableVirtualItem.getItemId()); StoreEvents.OnItemPurchased(pvi, payload); if (alsoPush) { sep.PushEventOnItemPurchased(_Event); } }
/// <summary> /// Handles an <c>onLoginFailed</c> event /// </summary> /// <param name="message"> /// Will contain a numeric representation of <c>Provider</c> /// ,error message and payload </param> public void onLoginFailed(String message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onLoginFailed"); JSONObject eventJson = new JSONObject(message); Provider provider = Provider.fromInt((int)(eventJson["provider"].n)); String errorMessage = eventJson["message"].str; bool autoLogin = eventJson["autoLogin"].b; JSONObject payloadJSON = new JSONObject(eventJson ["payload"].str); ProfileEvents.OnLoginFailed(provider, errorMessage, autoLogin, ProfilePayload.GetUserPayload(payloadJSON)); }
/// <summary> /// See docs in <see cref="SoomlaProfile.SubmitScore"/> /// </summary> public void SubmitScore(Leaderboard targetLeaderboard, int value, SingleObjectSuccess <Score> success, FailureHandler fail) { checkPublishPermission(() => { var formData = new Dictionary <string, string> { { "score", value.ToString() } }; FB.API("/me/scores", HttpMethod.POST, (IGraphResult result) => { if (result.Error != null) { SoomlaUtils.LogDebug(TAG, "SubmitScoreCallback[result.Error]: " + result.Error); fail(result.Error); } else { SoomlaUtils.LogDebug(TAG, "SubmitScoreCallback[result.Text]: " + result.RawResult); JSONObject jsonFeed = new JSONObject(result.RawResult); if (jsonFeed["success"].b) { var userJson = new JSONObject(); userJson.AddField(PJSONConsts.UP_USERNAME, "me"); userJson.AddField(PJSONConsts.UP_PROVIDER, Provider.FACEBOOK.ToString()); userJson.AddField(PJSONConsts.UP_PROFILEID, "0"); var scoreJsonObj = new JSONObject(); scoreJsonObj.AddField(PJSONConsts.UP_LEADERBOARD, targetLeaderboard.toJSONObject()); scoreJsonObj.AddField(PJSONConsts.UP_USER_PROFILE, userJson); scoreJsonObj.AddField(PJSONConsts.UP_SCORE_RANK, 0); scoreJsonObj.AddField(PJSONConsts.UP_SCORE_VALUE, value); var score = new Score(scoreJsonObj); success(score); } else { fail("Unable to submit score"); } } }, formData); }, (string errorMessage) => { fail(errorMessage); }); }
protected override UserProfile _getStoredUserProfile(Provider provider) { IntPtr p = IntPtr.Zero; int err = soomlaProfile_GetStoredUserProfile(provider.ToString(), out p); IOS_ProfileErrorCodes.CheckAndThrowException(err); string json = Marshal.PtrToStringAnsi(p); Marshal.FreeHGlobal(p); SoomlaUtils.LogDebug(TAG, "Got json: " + json); JSONObject obj = new JSONObject(json); return(new UserProfile(obj)); }
/// <summary> /// Initializes the different native event handlers in Android / iOS /// </summary> public static void Initialize() { SoomlaUtils.LogDebug(TAG, "Initializing StoreEvents ..."); #if UNITY_ANDROID && !UNITY_EDITOR AndroidJNI.PushLocalFrame(100); using (AndroidJavaClass jniEventHandler = new AndroidJavaClass("com.soomla.unity.StoreEventHandler")) { jniEventHandler.CallStatic("initialize"); } AndroidJNI.PopLocalFrame(IntPtr.Zero); sep = new StoreEventPusherAndroid(); #elif UNITY_IOS && !UNITY_EDITOR eventDispatcher_Init(); sep = new StoreEventPusherIOS(); #endif }
/// <summary> /// Converts the current <c>MarketItem</c> to a <c>JSONObject</c>. /// </summary> /// <returns>A <c>JSONObject</c> representation of the current /// <c>MarketItem</c>.</returns> public JSONObject toJSONObject() { JSONObject obj = new JSONObject(JSONObject.Type.OBJECT); obj.AddField(Soomla.JSONConsts.SOOM_CLASSNAME, SoomlaUtils.GetClassName(this)); obj.AddField(StoreJSONConsts.MARKETITEM_PRODUCT_ID, this.ProductId); obj.AddField(StoreJSONConsts.MARKETITEM_PRICE, (float)this.Price); obj.AddField(StoreJSONConsts.MARKETITEM_MARKETPRICE, this.MarketPriceAndCurrency); obj.AddField(StoreJSONConsts.MARKETITEM_MARKETTITLE, this.MarketTitle); obj.AddField(StoreJSONConsts.MARKETITEM_MARKETDESC, this.MarketDescription); obj.AddField(StoreJSONConsts.MARKETITEM_MARKETCURRENCYCODE, this.MarketCurrencyCode); obj.AddField(StoreJSONConsts.MARKETITEM_MARKETPRICEMICROS, (float)this.MarketPriceMicros); return(obj); }
public void onGiftsRetrieveFinished(string message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onGiftsRetrieveFinished: " + message); JSONObject eventJSON = new JSONObject(message); List <JSONObject> givenGiftsJSON = eventJSON["givenGifts"].list; List <Gift> givenGifts = new List <Gift>(); foreach (var givenGiftJSON in givenGiftsJSON) { givenGifts.Add(new Gift(givenGiftJSON)); } HighwayEvents.OnGiftsRetrieveFinished(givenGifts); }
/// <summary> /// Initializes the SOOMLA SDK. /// </summary> /// <param name="storeAssets">Your game's economy.</param> /// <exception cref="ExitGUIException">Thrown if soomlaSecret is missing or has not been changed. /// </exception> public static void Initialize(IStoreAssets storeAssets) { if (string.IsNullOrEmpty(CoreSettings.SoomlaSecret)) { SoomlaUtils.LogError(TAG, "SOOMLA/UNITY MISSING SoomlaSecret !!! Stopping here !!"); throw new ExitGUIException(); } if (CoreSettings.SoomlaSecret == CoreSettings.ONLY_ONCE_DEFAULT) { SoomlaUtils.LogError(TAG, "SOOMLA/UNITY You have to change SoomlaSecret !!! Stopping here !!"); throw new ExitGUIException(); } instance._initialize(storeAssets); }
/// <summary> /// Handles a store controller initialized event. /// </summary> public void onSoomlaStoreInitialized() { // some usage examples for add/remove currency // some examples if (StoreInfo.Currencies.Count > 0) { try { StoreInventory.GiveItem(StoreInfo.Currencies[0].ItemId, 4000); SoomlaUtils.LogDebug("SOOMLA ExampleEventHandler", "Currency balance:" + StoreInventory.GetItemBalance(StoreInfo.Currencies[0].ItemId)); } catch (VirtualItemNotFoundException ex) { SoomlaUtils.LogError("SOOMLA ExampleEventHandler", ex.Message); } } ExampleWindow.GetInstance().setupItemsTextures(); }
public bool Give() { if (!CanGive()) { SoomlaUtils.LogDebug(TAG, "(Give) Reward is not approved by Schedule. id: " + mID); return(false); } if (giveInner()) { RewardStorage.SetRewardStatus(mID, true); return(true); } return(false); }
/// <summary> /// Handles an <c>onItemPurchased</c> event, which is fired when a specific /// <c>PurchasableVirtualItem</c> has been purchased. /// </summary> /// <param name="message">Message that contains information about the good that has been purchased.</param> public void onItemPurchased(string message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onItemPurchased:" + message); string[] vars = Regex.Split(message, "#SOOM#"); PurchasableVirtualItem pvi = (PurchasableVirtualItem)StoreInfo.GetItemByItemId(vars[0]); string payload = ""; if (vars.Length > 1) { payload = vars[1]; } StoreEvents.OnItemPurchased(pvi, payload); }
public void onVungleAdViewed(string message) { SoomlaUtils.LogDebug(TAG, "SOOMLA/UNITY onVungleAdViewed:" + message); JSONObject eventJSON = new JSONObject(message); bool completed = eventJSON["completed"].b; double timeWatched = eventJSON["timeWatched"].n; if (completed && savedReward != null) { savedReward.Give(); savedReward = null; } SoomlaVungle.OnVungleAdViewed(completed, timeWatched); }
/// <summary> /// Gets the item with the given <c>itemId</c>. /// </summary> /// <param name="itemId">Item id.</param> /// <returns>Item with the given id.</returns> /// <exception cref="VirtualItemNotFoundException">Exception is thrown if item is not found.</exception> override protected VirtualItem _getItemByItemId(string itemId) { IntPtr p = IntPtr.Zero; int err = storeInfo_GetItemByItemId(itemId, out p); IOS_ErrorCodes.CheckAndThrowException(err); string json = Marshal.PtrToStringAnsi(p); Marshal.FreeHGlobal(p); SoomlaUtils.LogDebug(TAG, "Got json: " + json); JSONObject obj = new JSONObject(json); return(VirtualItem.factoryItemFromJSONObject(obj)); }