private IEnumerator ProcessOptOut(CompletionHandler completionHandler = null)
        {
            Dictionary <string, string> requestHeaders = new Dictionary <string, string>();

            yield return(InsertDeviceIdInfo(requestHeaders));

            string url = BaseUrl;

            url += "/v1/optout";
            requestHeaders.Add("App-Bundle", Application.identifier);
            UnityWebResponseHandler onResponse = (request) => {
                if (request.error != null)
                {
                    Debug.LogError("[Apptilaus]: optOut was not registered, due to error:\n" + request.error);
                    if (completionHandler != null)
                    {
                        completionHandler(false, request.error);
                    }
                    return;
                }
                if (completionHandler != null)
                {
                    completionHandler(true, "");
                }
                Debug.Log("[Apptilaus]: optOut processed");
            };

            yield return(GetRequest(url, onResponse, requestHeaders));
        }
        private IEnumerator GetRequest(string url, UnityWebResponseHandler onResponse, Dictionary <string, string> headers = null)
        {
            UnityWebRequest request = UnityWebRequest.Get(url);

            if (headers != null)
            {
                foreach (KeyValuePair <string, string> header in headers)
                {
                    request.SetRequestHeader(header.Key, header.Value);
                }
            }
            yield return(request.SendWebRequest());

            if (onResponse != null)
            {
                onResponse(request);
            }
        }
        private IEnumerator PostRequest(string url, UnityWebResponseHandler onResponse, string body, Dictionary <string, string> headers = null)
        {
            byte[] data = Encoding.UTF8.GetBytes(body);
            Debug.Log("[Apptilaus]: sending POST request. Body :\n" + body);
            UnityWebRequest request = new UnityWebRequest(url, "POST");

            request.uploadHandler   = (UploadHandler) new UploadHandlerRaw(data);
            request.downloadHandler = new DownloadHandlerBuffer();

            if (headers != null)
            {
                foreach (KeyValuePair <string, string> header in headers)
                {
                    request.SetRequestHeader(header.Key, header.Value);
                }
            }
            request.downloadHandler = new DownloadHandlerScript();
            yield return(request.SendWebRequest());

            if (onResponse != null)
            {
                onResponse(request);
            }
        }
        private IEnumerator RegisterSessionIfNeeded()
        {
            if (!CheckSetup())
            {
                yield break;
            }
            Dictionary <string, string> parameters = new Dictionary <string, string>();

            DateTime now             = DateTime.Now;
            TimeSpan nowTimeSpan     = (now - new DateTime(1970, 1, 1, 0, 0, 0));
            double   nowMilliseconds = (Int64)Math.Floor(nowTimeSpan.TotalMilliseconds);
            string   timeParameterName;
            string   lastRegisteredSessionValue = PlayerPrefs.GetString(_lastRegisteredSessionKey, "");
            double   lastCallMilliseconds;

            if (!string.IsNullOrEmpty(lastRegisteredSessionValue) && double.TryParse(lastRegisteredSessionValue, out lastCallMilliseconds))
            {
                //Session had already been registered, check the day of the last session
                TimeSpan lastCall = TimeSpan.FromMilliseconds(lastCallMilliseconds);
                if (Math.Floor(nowTimeSpan.TotalDays) == Math.Floor(lastCall.TotalDays))
                {
                    Debug.Log("[Apptilaus]: already registered session today");
                    yield break;
                }
                timeParameterName = "dp_session";
                parameters.Add("dp_activity", "session");
            }
            else
            {
                //This is the first time this app registers session
                timeParameterName = "dp_install";
                parameters.Add("dp_activity", "install");
            }
            parameters.Add(timeParameterName, String.Format("{0:0}", nowMilliseconds));
            yield return(InsertDeviceIdInfo(parameters));

            //Encode parameters to URL
            string url     = _sessionURL + _appId + "/?";
            int    counter = 0;

            foreach (KeyValuePair <string, string> param in parameters)
            {
                url += param.Key + "=" + param.Value;
                counter++;
                if (counter < parameters.Count)
                {
                    url += "&";
                }
            }
            Debug.Log("[Apptilaus]: sending session request to " + url);
            UnityWebResponseHandler onResponse = (request) => {
                if (request.error != null)
                {
                    Debug.LogError("[Apptilaus]: session was not registered, due to error:\n" + request.error);
                    return;
                }
                PlayerPrefs.SetString(_lastRegisteredSessionKey, nowMilliseconds.ToString());
                PlayerPrefs.Save();
                Debug.Log("[Apptilaus]: session registered");
            };

            yield return(GetRequest(url, onResponse, null));
        }
        private IEnumerator ProcessPurchase(Product product, Dictionary <string, string> customParams, int tryCount)
        {
            Dictionary <string, string> parameters = new Dictionary <string, string>();

#if UNITY_ANDROID
            parameters.Add("platform", "GooglePlay");
#elif UNITY_IOS
            parameters.Add("platform", "AppleAppStore");
#endif
            yield return(InsertDeviceIdInfo(parameters));

            parameters.Add("price", String.Format("{0:f2}", product.metadata.localizedPrice));
            parameters.Add("currency", product.metadata.isoCurrencyCode);
            parameters.Add("sdk_version", _sdkVersion);
            if (!string.IsNullOrEmpty(UserId))
            {
                parameters.Add("user_id", UserId);
            }
            if (customParams != null)
            {
                foreach (KeyValuePair <string, string> param in customParams)
                {
                    parameters.Add("dp_" + param.Key, param.Value);
                }
            }
            parameters.Add("item", product.definition.storeSpecificId);
            parameters.Add("transaction_id", product.transactionID);
            try {
#if UNITY_IOS
                string payload = JSON.Parse(product.receipt)["Payload"];
                parameters.Add("receipt", payload);
#elif UNITY_ANDROID
                string   payload     = JSON.Parse(product.receipt)["Payload"];
                JSONNode payloadNode = JSON.Parse(payload);
                parameters.Add("receipt", payloadNode["signature"]);
                JSONNode json = JSON.Parse(payloadNode["json"]);
                parameters.Add("purchase_token", json["purchaseToken"]);
#endif
            }
            catch {
                Debug.LogError("[Apptilaus] Couldn't parse receipt json : " + product.receipt);
            }

            Dictionary <string, string> headers = new Dictionary <string, string>();
            headers.Add("App-Token", _appToken);
            headers.Add("Content-Type", "application/json");
            string url = BaseUrl;
            url += "/v1/unity/" + _appId + "/";

            UnityWebResponseHandler onResponse = (request) => {
                if (request.error != null)
                {
                    if (request.isNetworkError)
                    {
                        if (tryCount < MaxRequestRetryCount)
                        {
                            StartCoroutine(ProcessPurchase(product, customParams, tryCount + 1));
                        }
                        else
                        {
                            Debug.LogError("[Apptilaus] Could not send purchase request: retry limit is exceeded");
                        }
                    }
                    else
                    {
                        Debug.LogError("[Apptilaus] Could not send purchase request due to error: " + request.error);
                    }
                    return;
                }
                Debug.Log("[Apptilaus]:server response: " + request.downloadHandler.text);
                Debug.Log("[Apptilaus]: Purchase Processed");
            };
            Debug.Log("[Apptilaus]: sending purchase to " + url);
            yield return(PostRequest(url, onResponse, JsonDictionaryWriter.Serialize(parameters), headers));
        }