/// <summary> /// Advances to a particular state in your application. The string can be /// any value of your choosing, and will show up in the dashboard. /// A state is a section of your app that the user is currently in. /// </summary> public override void AdvanceTo(string state, string info, IDictionary <string, object> parameters) { if (Constants.isNoop) { return; } if (!calledStart) { CompatibilityLayer.LogError("You cannot call AdvanceTo before calling Start."); return; } IDictionary <string, string> requestParams = new Dictionary <string, string>(); requestParams[Constants.Params.INFO] = info; if (state != null) { requestParams[Constants.Params.STATE] = state; } if (parameters != null) { requestParams[Constants.Params.PARAMS] = Json.Serialize(parameters); } LeanplumRequest.Post(Constants.Methods.ADVANCE, requestParams).Send(); }
/// <summary> /// Logs a particular event in your application. The string can be /// any value of your choosing, and will show up in the dashboard. /// To track purchases, use Leanplum.PURCHASE_EVENT_NAME as the event name. /// </summary> public void Track(string eventName, double value, string info, IDictionary <string, object> parameters, IDictionary <string, string> arguments) { if (Constants.isNoop) { return; } if (!calledStart) { CompatibilityLayer.LogError("You cannot call Track before calling Start."); return; } IDictionary <string, string> requestParams = new Dictionary <string, string>(); requestParams[Constants.Params.EVENT] = eventName; requestParams[Constants.Params.VALUE] = value.ToString(); if (info != null) { requestParams [Constants.Params.INFO] = info; } if (parameters != null) { requestParams[Constants.Params.PARAMS] = Json.Serialize(parameters); } if (arguments != null) { foreach (string argName in arguments.Keys) { requestParams[argName] = arguments[argName]; } } LeanplumRequest.Post(Constants.Methods.TRACK, requestParams).Send(); }
/// <summary> /// Set location manually. Calls SetDeviceLocationWithLatitude with cell type. Best if /// used in after calling DisableLocationCollection. /// </summary> /// <param name="latitude"> Device location latitude. </param> /// <param name="longitude"> Device location longitude. </param> public override void SetDeviceLocation(double latitude, double longitude) { var parameters = new Dictionary <string, string>(); parameters[Constants.Keys.LOCATION] = string.Format("{0},{1}", latitude, longitude); LeanplumRequest.Post(Constants.Methods.SET_USER_ATTRIBUTES, parameters); }
/// <summary> /// Call this when your application pauses. /// </summary> internal static void Pause() { if (Constants.isNoop) { return; } if (!calledStart) { CompatibilityLayer.LogError("You cannot call Pause before calling start."); return; } if (!isPaused) { isPaused = true; LeanplumRequest request = LeanplumRequest.Post(Constants.Methods.PAUSE_SESSION, null); request.Response += (object obj) => { CompatibilityLayer.FlushSavedSettings(); }; request.Error += (Exception obj) => { CompatibilityLayer.FlushSavedSettings(); }; request.SendIfConnected(); } }
internal static void CheckVarsUpdate(Action callback) { IDictionary <string, string> updateVarsParams = new Dictionary <string, string>(); updateVarsParams[Constants.Params.INCLUDE_DEFAULTS] = false.ToString(); LeanplumRequest updateVarsReq = LeanplumRequest.Post(Constants.Methods.GET_VARS, updateVarsParams); updateVarsReq.Response += delegate(object varsUpdate) { var getVariablesResponse = Util.GetLastResponse(varsUpdate) as IDictionary <string, object>; var newVarValues = Util.GetValueOrDefault(getVariablesResponse, Constants.Keys.VARS) as IDictionary <string, object>; var newVarFileAttributes = Util.GetValueOrDefault(getVariablesResponse, Constants.Keys.FILE_ATTRIBUTES) as IDictionary <string, object>; var newVariants = Util.GetValueOrDefault(getVariablesResponse, Constants.Keys.VARIANTS) as List <object> ?? new List <object>(); ApplyVariableDiffs(newVarValues, newVarFileAttributes, newVariants); if (callback != null) { callback(); } }; updateVarsReq.Error += delegate { if (callback != null) { callback(); } }; updateVarsReq.SendNow(); VarsNeedUpdate = false; }
/// <summary> /// Set location manually. Calls SetDeviceLocationWithLatitude with cell type. Best if /// used in after calling DisableLocationCollection. /// </summary> /// <param name="latitude"> Device location latitude. </param> /// <param name="longitude"> Device location longitude. </param> /// <param name="city"> Location city. </param> /// <param name="region"> Location region. </param> /// <param name="country"> Country ISO code. </param> /// <param name="type"> Location accuracy type. </param> public override void SetDeviceLocation(double latitude, double longitude, string city, string region, string country, LPLocationAccuracyType type) { var parameters = new Dictionary <string, string>(); parameters[Constants.Keys.LOCATION] = string.Format("{0},{1}", latitude, longitude); parameters[Constants.Keys.LOCATION_ACCURACY_TYPE] = LocationAccuracyTypeToString(type); parameters[Constants.Keys.COUNTRY] = city; parameters[Constants.Keys.REGION] = region; parameters[Constants.Keys.CITY] = country; LeanplumRequest.Post(Constants.Methods.SET_USER_ATTRIBUTES, parameters); }
internal static bool SendVariablesIfChanged() { if (devModeValuesFromServer != null && valuesFromClient != devModeValuesFromServer) { var parameters = new Dictionary <string, string>(); parameters[Constants.Params.VARIABLES] = Json.Serialize(valuesFromClient); parameters[Constants.Params.KINDS] = Json.Serialize(defaultKinds); LeanplumUnityHelper.QueueOnMainThread(() => LeanplumRequest.Post(Constants.Methods.SET_VARS, parameters).SendNow()); return(true); } return(false); }
/// <summary> /// Resumes the current state. /// </summary> public override void ResumeState() { if (Constants.isNoop) { return; } if (!calledStart) { CompatibilityLayer.LogError("You cannot call ResumeState before calling start."); return; } LeanplumRequest.Post(Constants.Methods.RESUME_STATE, new Dictionary <string, string>()).Send(); }
public override void Remove(string messageId) { if (messageId != null) { var msgs = _messages.FindAll(msg => msg.Id != messageId).ToList(); UpdateMessages(msgs); var param = new Dictionary <string, string> { [Constants.Params.INBOX_MESSAGE_ID] = messageId }; LeanplumRequest request = LeanplumRequest.Post(Constants.Methods.DELETE_INBOX_MESSAGE, param); request.SendIfConnected(); } }
/// <summary> /// Allows start to be called again. /// </summary> internal static void Reset() { if (calledStart) { Stop(); } calledStart = false; _hasStarted = false; _HasStartedAndRegisteredAsDeveloper = false; startSuccessful = false; variablesChanged = null; variablesChangedAndNoDownloadsPending = null; started = null; LeanplumRequest.ClearNoPendingDownloads(); }
/// <summary> /// Call this when your application resumes. /// </summary> internal static void Resume() { if (Constants.isNoop) { return; } if (!calledStart) { CompatibilityLayer.LogError("You cannot call Resume before calling start."); return; } if (isPaused) { isPaused = false; LeanplumRequest.Post(Constants.Methods.RESUME_SESSION, null).SendIfConnected(); } }
/// <summary> /// Call this when your application stops. /// </summary> internal static void Stop() { if (Constants.isNoop) { return; } if (!calledStart) { CompatibilityLayer.LogError("You cannot call Stop before calling start."); return; } if (leanplumSocket != null) { leanplumSocket.Close(); } LeanplumRequest.Post(Constants.Methods.STOP, null).SendIfConnected(); }
/// <summary> /// Sets the traffic source info for the current user. /// Keys in info must be one of: publisherId, publisherName, publisherSubPublisher, /// publisherSubSite, publisherSubCampaign, publisherSubAdGroup, publisherSubAd. /// </summary> public override void SetTrafficSourceInfo(IDictionary <string, string> info) { if (Constants.isNoop) { return; } if (!calledStart) { CompatibilityLayer.LogError("You cannot call SetTrafficSourceInfo before calling " + "Start."); return; } IDictionary <string, string> requestParams = new Dictionary <string, string>(); requestParams[Constants.Params.TRAFFIC_SOURCE] = Json.Serialize(info); LeanplumRequest.Post(Constants.Methods.SET_TRAFFIC_SOURCE_INFO, requestParams).Send(); }
public override void Read(string messageId) { if (messageId != null) { var msg = _messages.Find(message => message.Id == messageId); if (msg != null) { msg.IsRead = true; var param = new Dictionary <string, string> { [Constants.Params.INBOX_MESSAGE_ID] = messageId }; LeanplumRequest request = LeanplumRequest.Post(Constants.Methods.MARK_INBOX_MESSAGE_AS_READ, param); request.SendIfConnected(); } } }
internal static void ForceSendVariables(Leanplum.SyncVariablesCompleted completedHandler) { var parameters = new Dictionary <string, string>(); parameters[Constants.Params.VARIABLES] = Json.Serialize(valuesFromClient); parameters[Constants.Params.KINDS] = Json.Serialize(defaultKinds); LeanplumUnityHelper.QueueOnMainThread(() => { LeanplumRequest setVarsReq = LeanplumRequest.Post(Constants.Methods.SET_VARS, parameters); setVarsReq.Response += delegate(object response) { completedHandler?.Invoke(true); }; setVarsReq.Error += delegate(Exception ex) { LeanplumNative.CompatibilityLayer.LogError("Leanplum Error: ForceSyncVariables", ex); completedHandler?.Invoke(false); }; setVarsReq.SendNow(); }); }
/// <summary> /// Updates the user ID and adds or modifies user attributes. /// </summary> /// <param name="newUserId">New user identifier.</param> /// <param name="value">User attributes.</param> public override void SetUserAttributes(string newUserId, IDictionary <string, object> value) { if (!calledStart) { CompatibilityLayer.LogWarning("Start was not called. Set user ID and attributes " + "as the arguments when calling Start."); return; } if (Constants.isNoop) { return; } var parameters = new Dictionary <string, string>(); if (value != null) { ValidateAttributes(value); parameters[Constants.Params.USER_ATTRIBUTES] = Json.Serialize(value); } if (!String.IsNullOrEmpty(newUserId)) { parameters[Constants.Params.NEW_USER_ID] = newUserId; VarCache.SaveDiffs(); } LeanplumRequest.Post(Constants.Methods.SET_USER_ATTRIBUTES, parameters).Send(); if (!String.IsNullOrEmpty(newUserId)) { LeanplumRequest.UserId = newUserId; if (_hasStarted) { VarCache.SaveDiffs(); } } }
/// <summary> /// Call this when your application starts. /// This will initiate a call to Leanplum's servers to get the values /// of the variables used in your app. /// </summary> public override void Start(string userId, IDictionary <string, object> attributes, Leanplum.StartHandler startResponseAction) { if (calledStart) { CompatibilityLayer.Log("Already called start"); return; } if (String.IsNullOrEmpty(LeanplumRequest.AppId)) { CompatibilityLayer.LogError("You cannot call Start without setting your app's " + "API keys."); return; } if (CompatibilityLayer.GetPlatformName() == "Standalone") { // TODO: Fix this. // This is a workaround for SSL issues when running on // standalone when connecting with the production server. // No issue on staging. Constants.API_SSL = false; } if (startResponseAction != null) { Started += startResponseAction; } if (Constants.isNoop) { _hasStarted = true; startSuccessful = true; OnVariablesChanged(); OnVariablesChangedAndNoDownloadsPending(); OnStarted(true); VarCache.ApplyVariableDiffs(null, null); return; } ValidateAttributes(attributes); calledStart = true; // Load the variables that were stored on the device from the last session. VarCache.IsSilent = true; VarCache.LoadDiffs(); VarCache.IsSilent = false; // Setup class members. VarCache.Update += delegate { OnVariablesChanged(); if (LeanplumRequest.PendingDownloads == 0) { OnVariablesChangedAndNoDownloadsPending(); } }; LeanplumRequest.NoPendingDownloads += delegate { OnVariablesChangedAndNoDownloadsPending(); }; string deviceId; if (customDeviceId != null) { deviceId = customDeviceId; } else { deviceId = CompatibilityLayer.GetDeviceId(); } LeanplumRequest.DeviceId = deviceId; // Don't overwrite UserID if it was set previously if Start() // was called without a new UserID. if (!String.IsNullOrEmpty(userId)) { LeanplumRequest.UserId = userId; } if (String.IsNullOrEmpty(LeanplumRequest.UserId)) { LeanplumRequest.UserId = deviceId; } // Setup parameters. var parameters = new Dictionary <string, string>(); parameters[Constants.Params.INCLUDE_DEFAULTS] = false.ToString(); parameters[Constants.Params.VERSION_NAME] = CompatibilityLayer.VersionName ?? ""; parameters[Constants.Params.DEVICE_NAME] = CompatibilityLayer.GetDeviceName(); parameters[Constants.Params.DEVICE_MODEL] = CompatibilityLayer.GetDeviceModel(); parameters[Constants.Params.DEVICE_SYSTEM_NAME] = CompatibilityLayer.GetSystemName(); parameters[Constants.Params.DEVICE_SYSTEM_VERSION] = CompatibilityLayer.GetSystemVersion(); TimeZone timezone = System.TimeZone.CurrentTimeZone; if (timezone.IsDaylightSavingTime(DateTime.UtcNow)) { parameters[Constants.Keys.TIMEZONE] = timezone.DaylightName; } else { parameters[Constants.Keys.TIMEZONE] = timezone.StandardName; } parameters[Constants.Keys.TIMEZONE_OFFSET_SECONDS] = timezone.GetUtcOffset(DateTime.UtcNow).TotalSeconds.ToString(); parameters[Constants.Keys.COUNTRY] = Constants.Values.DETECT; parameters[Constants.Keys.REGION] = Constants.Values.DETECT; parameters[Constants.Keys.CITY] = Constants.Values.DETECT; parameters[Constants.Keys.LOCATION] = Constants.Values.DETECT; if (attributes != null) { parameters[Constants.Params.USER_ATTRIBUTES] = Json.Serialize(attributes); } // Issue start API call. LeanplumRequest req = LeanplumRequest.Post(Constants.Methods.START, parameters); req.Response += delegate(object responsesObject) { IDictionary <string, object> response = Util.GetLastResponse(responsesObject) as IDictionary <string, object>; IDictionary <string, object> values = Util.GetValueOrDefault(response, Constants.Keys.VARS) as IDictionary <string, object> ?? new Dictionary <string, object>(); IDictionary <string, object> fileAttributes = Util.GetValueOrDefault(response, Constants.Keys.FILE_ATTRIBUTES) as IDictionary <string, object> ?? new Dictionary <string, object>(); List <object> variants = Util.GetValueOrDefault(response, Constants.Keys.VARIANTS) as List <object> ?? new List <object>(); bool isRegistered = (bool)Util.GetValueOrDefault(response, Constants.Keys.IS_REGISTERED, false); LeanplumRequest.Token = Util.GetValueOrDefault(response, Constants.Keys.TOKEN) as string ?? ""; // Allow bidirectional realtime variable updates. if (Constants.isDevelopmentModeEnabled) { VarCache.SetDevModeValuesFromServer( Util.GetValueOrDefault(response, Constants.Keys.VARS_FROM_CODE) as Dictionary <string, object>); if (Constants.EnableRealtimeUpdatesInDevelopmentMode && SocketUtilsFactory.Utils.AreSocketsAvailable) { leanplumSocket = new LeanplumSocket(delegate() { // Callback when we receive an updateVars command through the // development socket. // Set a flag so that the next time VarCache.CheckVarsUpdate() is // called the variables are updated. VarCache.VarsNeedUpdate = true; }); } // Register device. if (isRegistered) { // Check for updates. string latestVersion = Util.GetValueOrDefault(response, Constants.Keys.LATEST_VERSION) as string; if (latestVersion != null) { CompatibilityLayer.Log("Leanplum Unity SDK " + latestVersion + " available. Go to https://www.leanplum.com/dashboard to " + "download it."); } OnHasStartedAndRegisteredAsDeveloper(); } } VarCache.ApplyVariableDiffs(values, fileAttributes, variants); _hasStarted = true; startSuccessful = true; OnStarted(true); CompatibilityLayer.Init(); }; req.Error += delegate { VarCache.ApplyVariableDiffs(null, null); _hasStarted = true; startSuccessful = false; OnStarted(false); CompatibilityLayer.Init(); }; req.SendIfConnected(); }
public override void DownloadMessages(OnForceContentUpdate completedHandler) { LeanplumRequest request = LeanplumRequest.Post(Constants.Methods.GET_INBOX_MESSAGES, null); request.Response += delegate(object data) { try { var response = Util.GetLastResponse(data) as IDictionary <string, object>; var messages = Util.GetValueOrDefault(response, Constants.Keys.INBOX_MESSAGES) as IDictionary <string, object>; var inboxMessages = new List <Message>(); if (messages != null) { foreach (var pair in messages) { var id = pair.Key; if (pair.Value is IDictionary <string, object> value) { var message = new Message { Id = id }; if (value.TryGetValue(Constants.Keys.MESSAGE_IS_READ, out var isRead)) { if (isRead is bool b) { message.IsRead = b; } } if (value.TryGetValue(Constants.Keys.DELIVERY_TIMESTAMP, out var deliveryTimestamp)) { if (deliveryTimestamp is long l) { TimeSpan ts = TimeSpan.FromMilliseconds(l); DateTime date = new DateTime(1970, 1, 1).AddTicks(ts.Ticks); message.DeliveryTimestamp = date; } } if (value.TryGetValue(Constants.Keys.EXPIRATION_TIMESTAMP, out var expirationTimestamp)) { if (expirationTimestamp is long l) { TimeSpan ts = TimeSpan.FromMilliseconds(l); DateTime date = new DateTime(1970, 1, 1).AddTicks(ts.Ticks); message.ExpirationTimestamp = date; } } if (value.TryGetValue(Constants.Keys.MESSAGE_DATA, out var messageData)) { if (messageData is IDictionary <string, object> dict) { if (dict.TryGetValue(Constants.Keys.VARS, out var vars)) { if (vars is Dictionary <string, object> varsDict) { message.ActionContext = varsDict; if (varsDict.TryGetValue(Constants.Keys.TITLE, out var title)) { message.Title = title as string; } if (varsDict.TryGetValue(Constants.Keys.SUBTITLE, out var subtitle)) { message.Subtitle = subtitle as string; } if (varsDict.TryGetValue(Constants.Keys.IMAGE, out var image)) { message.ImageURL = image as string; } } } } } inboxMessages.Add(message); } } } UpdateMessages(inboxMessages); TriggerInboxSyncedWithStatus(true, completedHandler); } catch (Exception exception) { Debug.Log("exception getting messages: " + exception.Message); TriggerInboxSyncedWithStatus(false, completedHandler); } }; request.Error += delegate { TriggerInboxSyncedWithStatus(false, completedHandler); }; request.SendIfConnected(); }
public override void Update() { object newValue = VarCache.GetMergedValueFromComponentArray(NameComponents); if (newValue == null) { newValue = GetDefaultValue(); } if (Kind == Constants.Kinds.FILE) { if (VarCache.IsSilent) { return; } string newFile = newValue.ToString(); string url = null; if (String.IsNullOrEmpty(newFile)) { return; } if (VarCache.FileAttributes != null && VarCache.FileAttributes.ContainsKey(newFile)) { IDictionary <string, object> currentFile = (VarCache.FileAttributes[newFile] as IDictionary <string, object>) [String.Empty] as IDictionary <string, object>; if (currentFile.ContainsKey(Constants.Keys.URL)) { url = ((VarCache.FileAttributes[newFile] as IDictionary <string, object>) [String.Empty] as IDictionary <string, object>)[Constants.Keys.URL] as string; } } // Update if the file is different from what we currently have and if we have started downloading it // already. Also update if we don't have the file but don't update if realtime updating is disabled - // wait 'til we get the value from the serve so that the correct file is displayed. if (currentlyDownloadingFile != newFile && !String.IsNullOrEmpty(url) && ((newFile != FileName && realtimeAssetUpdating && fileReady) || (Value == null && realtimeAssetUpdating))) { VarCache.downloadsPending++; currentlyDownloadingFile = newFile; FileName = newFile; fileReady = false; LeanplumRequest downloadRequest = LeanplumRequest.Get(url.Substring(1)); downloadRequest.Response += delegate(object obj) { _value = (T)obj; if (newFile == FileName && !fileReady) { fileReady = true; OnValueChanged(); currentlyDownloadingFile = null; } VarCache.downloadsPending--; }; downloadRequest.Error += delegate(Exception obj) { if (newFile == FileName && !fileReady) { LeanplumNative.CompatibilityLayer.LogError("Error downloading assetbundle \"" + FileName + "\". " + obj.ToString()); currentlyDownloadingFile = null; } VarCache.downloadsPending--; }; downloadRequest.DownloadAssetNow(); } } else { if (Json.Serialize(newValue) != Json.Serialize(Value)) { try { if (newValue is IDictionary || newValue is IList) { // If the value is a container, copy all the values from the newValue container to Value. SharedUtil.FillInValues(newValue, Value); } else { _value = (T)Convert.ChangeType(newValue, typeof(T)); } if (VarCache.IsSilent) { return; } OnValueChanged(); } catch (Exception ex) { Util.MaybeThrow(new LeanplumException("Error parsing values from server. " + ex.ToString())); return; } } } }
/// <summary> /// Must call either this or SetAppIdForDevelopmentMode /// before issuing any calls to the API, including start. /// </summary> /// <param name="appId"> Your app ID. </param> /// <param name="accessKey"> Your production key. </param> public override void SetAppIdForProductionMode(string appId, string accessKey) { Constants.isDevelopmentModeEnabled = false; LeanplumRequest.SetAppId(appId, accessKey); }