From 4c899f9aeb693017e40ad1687b3b37860d4a103c Mon Sep 17 00:00:00 2001 From: huyufei Date: Fri, 10 May 2024 21:31:14 +0800 Subject: [PATCH] =?UTF-8?q?[1020027]=20[=E4=B8=AD=E5=8F=B0]=20[=E6=89=93?= =?UTF-8?q?=E7=82=B9]=20=E8=A7=84=E8=8C=83=20iap=5Fret=5Ftrue=20=E6=89=93?= =?UTF-8?q?=E7=82=B9=E5=8F=82=E6=95=B0=20--story=3D1020027=20--user=3Dyufe?= =?UTF-8?q?i.hu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: huyufei --- .../Runtime/Analytics/Analytics.Const.cs | 3 - .../Analytics/Analytics.TemplateDefine.cs | 93 +++++++++++++++---- .../IPM/Scripts/RequestData/AppleOrderData.cs | 4 +- .../IPM/Scripts/RequestData/BaseOrderData.cs | 31 ++++--- .../Scripts/RequestData/GoogleOrderData.cs | 7 +- .../IPM/Scripts/Requests/AppleOrderRequest.cs | 60 ++++++------ .../Scripts/Requests/GoogleOrderRequest.cs | 31 +++---- .../GuruIAP/Runtime/Code/IAPServiceBase.cs | 58 +++++++++--- 8 files changed, 194 insertions(+), 93 deletions(-) diff --git a/Runtime/GuruCore/Runtime/Analytics/Analytics.Const.cs b/Runtime/GuruCore/Runtime/Analytics/Analytics.Const.cs index 9e8600c..a388519 100644 --- a/Runtime/GuruCore/Runtime/Analytics/Analytics.Const.cs +++ b/Runtime/GuruCore/Runtime/Analytics/Analytics.Const.cs @@ -76,9 +76,6 @@ namespace Guru public static readonly string ParameterAdUnitName = "ad_unit_name"; public static readonly string ParameterAdCreativeId = "ad_creative_id"; - - - // 评价参数 public static readonly string EventRateImp = "rate_imp"; // 评价弹窗展示 public static readonly string EventRateNow = "rate_now"; // 点击评分引导弹窗中的评分 diff --git a/Runtime/GuruCore/Runtime/Analytics/Analytics.TemplateDefine.cs b/Runtime/GuruCore/Runtime/Analytics/Analytics.TemplateDefine.cs index 40db504..a179229 100644 --- a/Runtime/GuruCore/Runtime/Analytics/Analytics.TemplateDefine.cs +++ b/Runtime/GuruCore/Runtime/Analytics/Analytics.TemplateDefine.cs @@ -397,15 +397,15 @@ namespace Guru var data = new Dictionary() { { ParameterAdPlatform, platform }, - { ParameterCurrency, USD }, { ParameterValue, value }, + { ParameterCurrency, USD }, }; //--------- Extra data for IAP receipt --------------- - if(!string.IsNullOrEmpty(orderType)) data.Add("order_type", orderType); - if(!string.IsNullOrEmpty(productId)) data.Add("product_id", productId); - if(!string.IsNullOrEmpty(orderId)) data.Add("order_id", orderId); - if(!string.IsNullOrEmpty(timestamp)) data.Add("payed_date", timestamp); + if(!string.IsNullOrEmpty(orderType)) data["order_type"] = orderType; + if(!string.IsNullOrEmpty(productId)) data["product_id"] = productId; + if(!string.IsNullOrEmpty(orderId)) data["order_id"] = orderId; + if(!string.IsNullOrEmpty(timestamp)) data["trans_ts"] = timestamp; //--------- Extra data for IAP receipt --------------- LogEvent(evtName, data); @@ -527,21 +527,23 @@ namespace Guru /// /// "app 内弹出的付费引导IAP付费或试用成功打点" /// - /// 界面跳转的来源 - /// product id,多个产品用逗号分隔,第一个商品id放主推商品id + /// 界面跳转的来源 + /// product id,多个产品用逗号分隔,第一个商品id放主推商品id /// 产品的价格 /// 用户的付费币种 + /// 订单 ID /// 付费类型订阅/产品(subscription/product) /// 是否为试用(1:试用,0:付费) - public static void IAPRetTrue(string itemCategory, string productID, double value, string currency, string type, bool isfree) + public static void IAPRetTrue(string scene, string productId, double value, string currency, string orderId, string type, bool isfree) { LogEvent(EventIAPReturnTrue, new Dictionary() { - { ParameterItemCategory, itemCategory }, - { ParameterItemName, productID }, + { ParameterItemCategory, scene }, + { ParameterItemName, productId }, { ParameterValue, value }, { ParameterCurrency, currency }, - { "type", type}, + { "order_id", orderId }, + { "type", type }, { "isfree", isfree ? 1 : 0 }, }); } @@ -596,7 +598,53 @@ namespace Guru { ParameterCurrency, currency }, }); } + + + /// + /// 支付成功后统一上报所有点位数据 + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void ReportIAPSuccessEvent(double usdPrice, string productId, BaseOrderData orderData) + { + string userCurrency = orderData.userCurrency; + double payPrice = orderData.payPrice; + string orderType = orderData.OrderType(); + string orderType2 = orderData.OrderTypeII(); + string orderId = orderData.orderId; + string orderDate = orderData.payedDate; + string scene = orderData.scene; + bool isFree = orderData.isFree; + // TCH 001 + Tch001IAPRev(usdPrice, productId, orderId, orderType, orderDate); + // TCH 020 + Tch02IAPRev(usdPrice); + // Adjust Track IAP Purchase + AdjustService.TrackIAPPurchase(usdPrice, productId); // 上报 IAP 支付事件 + + if (orderData.orderType == 1) + { + // sub_pruchase + SubPurchase(usdPrice, productId, orderId, orderDate); + } + else + { + // iap_purchase + IAPPurchase(usdPrice, productId, orderId, orderDate); + } + + // IAP Ret true + IAPRetTrue(scene, productId, payPrice, userCurrency, orderType2, orderType, isFree); + } + #endregion #region IAP_PURCHASE @@ -606,18 +654,20 @@ namespace Guru /// /// /// - public static void IAPPurchase(double value, string productId) + /// + /// + public static void IAPPurchase(double value, string productId, string orderId, string orderDate) { - IAPPurchaseReport(EventIAPPurchase, value, productId); + IAPPurchaseReport(EventIAPPurchase, value, productId, orderId, "IAP", orderDate); } - public static void SubPurchase(double value, string productId) + public static void SubPurchase(double value, string productId, string orderId, string orderDate) { - IAPPurchaseReport(EventSubPurchase, value, productId); + IAPPurchaseReport(EventSubPurchase, value, productId, orderId, "SUB", orderDate); } - private static void IAPPurchaseReport(string eventName, double value, string productId) + private static void IAPPurchaseReport(string eventName, double value, string productId, string orderId, string orderType, string orderDate) { LogEvent(eventName, new Dictionary() { @@ -625,8 +675,15 @@ namespace Guru [ParameterPlatform] = IAPPlatform, [ParameterCurrency] = USD, [ParameterValue] = value, - [ParameterProductId] = productId, - }, new EventSetting() { EnableFirebaseAnalytics = true }); + ["product_id"] = productId, + ["order_id"] = orderId, + ["order_type"] = orderType, + ["trans_ts"] = orderDate + }, new EventSetting() + { + EnableFirebaseAnalytics = true, + EnableAdjustAnalytics = true, + }); } #endregion diff --git a/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/AppleOrderData.cs b/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/AppleOrderData.cs index 2a15496..c0f73a4 100644 --- a/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/AppleOrderData.cs +++ b/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/AppleOrderData.cs @@ -21,7 +21,9 @@ namespace Guru public string country; // 用户商店的国家2字大写代码 public AppleOrderData(int orderType, string productId, string receipt, string orderId, - string date, int level, string offerId = "", string basePlanId = "") : base(orderType, productId, orderId, date, level, offerId, basePlanId) + string date, int level, string userCurrency, double payPrice, string scene, bool isFree = false, + string offerId = "", string basePlanId = "") + :base(orderType, productId, orderId, date, level, userCurrency, payPrice, scene, isFree, offerId, basePlanId) { this.receipt = receipt; bundleId = GuruSettings.Instance.GameIdentifier; diff --git a/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/BaseOrderData.cs b/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/BaseOrderData.cs index 8878b5a..6aee59a 100644 --- a/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/BaseOrderData.cs +++ b/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/BaseOrderData.cs @@ -12,29 +12,33 @@ namespace Guru public class BaseOrderData { - [JsonIgnore] - public string guid; // 唯一标识 public string productId; // 商品ID 当orderType=0时,传递该参数 - [JsonIgnore] + + public string guid; // 唯一标识 public int level; // 关卡 ID - - public int orderType; // 订单类型,可选值:0:IAP 订单 1:SUB 订阅订单 - public Dictionary userInfo; // 当前用户信息。目前包含: level: 用户属性中的"b_level"的值 - public EventConfig eventConfig; // 事件打点所需信息 - - //---- Offer Data ------- - [JsonIgnore] + public string userCurrency; // 用户商店货币 + public double payPrice; // 用户支付的费用 + public string scene; // 用户支付的场景 + public bool isFree; // 是否是试用道具 + // ---- Offer Data ------- public string orderId; // 订单的 OrderID - [JsonIgnore] public string payedDate; // 支付时间 (13位时间戳) + public int orderType; // 订单类型,可选值:0:IAP 订单 1:SUB 订阅订单 public string basePlanId; // 订阅商品的planId public string offerId; // 订阅商品的offerId + public Dictionary userInfo; // 当前用户信息。目前包含: level: 用户属性中的"b_level"的值 + public EventConfig eventConfig; // 事件打点所需信息 public BaseOrderData(int orderType, string productId, string orderId, - string payedDate, int level, string offerId = "", string basePlanId = "") + string payedDate, int level, string userCurrency, double payPrice, string scene, bool isFree = false, + string offerId = "", string basePlanId = "") { guid = GetGuid(); + this.userCurrency = userCurrency; + this.payPrice = payPrice; + this.scene = scene; + this.isFree = isFree; this.orderType = orderType; this.productId = productId; this.orderId = orderId; @@ -48,7 +52,8 @@ namespace Guru protected string GetGuid() => Guid.NewGuid().ToString(); - public string OrderType() => orderType == 0 ? "IAP" : "SUB"; + public string OrderType() => orderType == 1 ? "SUB": "IAP"; + public string OrderTypeII() => orderType == 1 ? "subscription" : "product"; public override string ToString() { diff --git a/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/GoogleOrderData.cs b/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/GoogleOrderData.cs index a0d8dfd..cb49c13 100644 --- a/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/GoogleOrderData.cs +++ b/Runtime/GuruCore/Runtime/IPM/Scripts/RequestData/GoogleOrderData.cs @@ -18,8 +18,11 @@ namespace Guru public string packageName; //应用包名 public string token; // 应用商店里面的购买token - public GoogleOrderData(int orderType, string productId, string token, string orderId, - string date, int level, string offerId = "", string basePlanId = "") : base(orderType, productId, orderId, date, level, offerId, basePlanId) + public GoogleOrderData(int orderType, string productId, string token, + string orderId, string date, int level, + string userCurrency, double payPrice, string scene, bool isFree = false, + string offerId = "", string basePlanId = "") + :base(orderType, productId, orderId, date, level, userCurrency, payPrice, scene, isFree, offerId, basePlanId) { _productId = productId; this.packageName = GuruSettings.Instance.GameIdentifier; diff --git a/Runtime/GuruCore/Runtime/IPM/Scripts/Requests/AppleOrderRequest.cs b/Runtime/GuruCore/Runtime/IPM/Scripts/Requests/AppleOrderRequest.cs index e0cb832..58e09df 100644 --- a/Runtime/GuruCore/Runtime/IPM/Scripts/Requests/AppleOrderRequest.cs +++ b/Runtime/GuruCore/Runtime/IPM/Scripts/Requests/AppleOrderRequest.cs @@ -10,33 +10,11 @@ namespace Guru public class AppleOrderRequest : RequestBase { - public int orderType; - public string productId; public string receipt; public AppleOrderData orderData; public AppleOrderRequest(){} - public static AppleOrderRequest Build(int orderType, string productId, string receipt, string orderId, string date, int level) - { - var request = new AppleOrderRequest() - { - orderType = orderType, - productId = productId, - receipt = receipt, - orderData = new AppleOrderData(orderType, productId, receipt, orderId, date, level), - }; - return request; - } - - public static AppleOrderRequest Build(AppleOrderData orderData) - { - return Build(orderData.orderType, - orderData.productId, - orderData.receipt, - orderData.orderId, - orderData.payedDate, - orderData.level); - } + protected override string RequestURL => IPMConfig.IPM_URL + "order/api/v1/orders/ios"; protected override UnityWebRequest CreateRequest() @@ -59,13 +37,16 @@ namespace Guru ResponseData responseData = JsonUtility.FromJson>(response); if (responseData != null && responseData.data != null) { - double usdPrice = responseData.data.usdPrice; + double usdPrice = responseData.data.usdPrice; + string productId = orderData.productId; - Analytics.Tch001IAPRev(usdPrice, productId, orderData.orderId, orderData.OrderType(), orderData.payedDate); - Analytics.Tch02IAPRev(usdPrice); + // Analytics.Tch001IAPRev(usdPrice, productId, orderData.orderId, orderData.OrderType(), orderData.payedDate); + // Analytics.Tch02IAPRev(usdPrice); + // + // AdjustService.TrackSubPurchase(usdPrice, productId); + // Analytics.SubPurchase(usdPrice, productId); - AdjustService.TrackSubPurchase(usdPrice, productId); - Analytics.SubPurchase(usdPrice, productId); + Analytics.ReportIAPSuccessEvent(usdPrice, productId, orderData); } } catch (Exception ex) @@ -74,5 +55,28 @@ namespace Guru } } + + public static AppleOrderRequest Build(int orderType, string productId, + string receipt, string orderId, string date, int level, + string userCurrency, double payPrice, string scene, bool isFree = false) + { + var request = new AppleOrderRequest() + { + receipt = receipt, + orderData = new AppleOrderData(orderType, productId, receipt, orderId, date, level, + userCurrency, payPrice, scene, isFree), + }; + return request; + } + + public static AppleOrderRequest Build(AppleOrderData data) + { + var request = new AppleOrderRequest() + { + orderData = data, + receipt = data.receipt, + }; + return request; + } } } \ No newline at end of file diff --git a/Runtime/GuruCore/Runtime/IPM/Scripts/Requests/GoogleOrderRequest.cs b/Runtime/GuruCore/Runtime/IPM/Scripts/Requests/GoogleOrderRequest.cs index d801c55..54a63f4 100644 --- a/Runtime/GuruCore/Runtime/IPM/Scripts/Requests/GoogleOrderRequest.cs +++ b/Runtime/GuruCore/Runtime/IPM/Scripts/Requests/GoogleOrderRequest.cs @@ -13,13 +13,6 @@ namespace Guru public GoogleOrderRequest(){} - public GoogleOrderRequest(int orderType, string productId, string subscriptionId, string token, string orderId, - string date, int level, string offerId = "", string basePlanId = "") - { - this.token = token; - orderData = new GoogleOrderData(orderType, productId, token, orderId, date, level, offerId, basePlanId); - } - protected override string RequestURL => IPMConfig.IPM_URL + "order/api/v1/orders/android"; protected override UnityWebRequest CreateRequest() { @@ -41,17 +34,18 @@ namespace Guru ResponseData responseData = JsonUtility.FromJson>(response); if (responseData != null && responseData.data != null) { - // Analytics.Tch001IAPRev(responseData.data.usdPrice); double usdPrice = responseData.data.usdPrice; string productId = orderData.RealProductId; - Analytics.Tch001IAPRev(usdPrice, productId, orderData.orderId, orderData.OrderType(), orderData.payedDate); // TCH 001 - // Analytics.Tch02IAPRev(usdPrice, productId, orderId, orderTypeString, timestamp); - Analytics.Tch02IAPRev(usdPrice); // TCH 020 + // Analytics.Tch001IAPRev(usdPrice, productId, orderId, orderType, orderDate); // TCH 001 + // // Analytics.Tch02IAPRev(usdPrice, productId, orderId, orderTypeString, timestamp); + // Analytics.Tch02IAPRev(usdPrice); // TCH 020 + // + // // Adjust Track IAP Purchase + // AdjustService.TrackIAPPurchase(usdPrice, productId); // 上报 IAP 支付事件 + // Analytics.IAPPurchase(usdPrice, productId); - // Adjust Track IAP Purchase - AdjustService.TrackIAPPurchase(usdPrice, productId); // 上报 IAP 支付事件 - Analytics.IAPPurchase(usdPrice, productId); + Analytics.ReportIAPSuccessEvent(usdPrice, productId, orderData); } } catch (Exception ex) @@ -61,12 +55,15 @@ namespace Guru } - public static GoogleOrderRequest Build(int orderType, string productId, - string token, string orderId, string date, int level, string offerId = "", string basePlanId = "") + public static GoogleOrderRequest Build(int orderType, string productId, + string token, string orderId, string date, int level, + string userCurrency, double payPrice, string scene, bool isFree = false, + string offerId = "", string basePlanId = "") { var request = new GoogleOrderRequest() { - orderData = new GoogleOrderData(orderType, productId, token, orderId, date, level, offerId, basePlanId), + orderData = new GoogleOrderData(orderType, productId, token, orderId, date, level, + userCurrency, payPrice, scene, isFree, offerId, basePlanId), token = token, }; return request; diff --git a/Runtime/GuruIAP/Runtime/Code/IAPServiceBase.cs b/Runtime/GuruIAP/Runtime/Code/IAPServiceBase.cs index a30ed63..d64edb9 100644 --- a/Runtime/GuruIAP/Runtime/Code/IAPServiceBase.cs +++ b/Runtime/GuruIAP/Runtime/Code/IAPServiceBase.cs @@ -576,7 +576,6 @@ namespace Guru // 真实购买后上报对应的事件 if (IsFirstIAP) Analytics.FirstIAP(info.Id, info.Price, info.CurrencyCode); // 上报首次支付打点 Analytics.ProductIAP(info.Id,info.Id, info.Price, info.CurrencyCode); - Analytics.IAPRetTrue(_curProductCategory, info.Id, info.Price, info.CurrencyCode, info.Type, info.IsFree); } var pp = purchaseEvent.purchasedProduct; @@ -723,20 +722,26 @@ namespace Guru Analytics.LogCrashlytics(new Exception($"IAPService can not report order because Validator is null!")); return false; } + + //---------------- All Report Information -------------------- int level = GetBLevel(); int orderType = args.purchasedProduct.definition.type == ProductType.Subscription ? 1 : 0; string productId = args.purchasedProduct.definition.id; - string appleReceiptString = ""; - // ----- 支付后的b_level上报逻辑 - LogI($"--- Report b_level:[{level}] with product id:{args.purchasedProduct.definition.id} "); + // string appleReceiptString = ""; + string userCurrency = args.purchasedProduct.metadata.isoCurrencyCode; + double payPrice = decimal.ToDouble(args.purchasedProduct.metadata.localizedPrice); + string scene = _curProductCategory ?? "Store"; + bool isFree = false; + if (orderType == 1) isFree = IsSubscriptionFreeTrailById(productId); + //---------------- All Report Information -------------------- + LogI($"--- Report b_level:[{level}] with product id:{args.purchasedProduct.definition.id} "); #if UNITY_EDITOR // // Editor 不做上报逻辑 LogI($"--- Editor Validate Success. But Editor can't report order."); return true; #endif - IPurchaseReceipt[] allReceipts = null; try @@ -769,7 +774,9 @@ namespace Guru googleReceipt.purchaseToken, googleReceipt.orderID, googleReceipt.purchaseDate, - level, offerId, basePlanId); + level, + userCurrency, payPrice, scene, isFree, + offerId, basePlanId); } else if (receipt is AppleInAppPurchaseReceipt appleReceipt) { @@ -777,7 +784,9 @@ namespace Guru appleReceipt.productID, args.purchasedProduct.receipt, appleReceipt.transactionID, - appleReceipt.purchaseDate, level); + appleReceipt.purchaseDate, + level, + userCurrency, payPrice, scene, isFree); } else { @@ -938,10 +947,13 @@ namespace Guru /// /// private void ReportGoogleOrder(int orderType, string productId, string token, - string orderId, DateTime date, int level, string offerId = "", string basePlanId = "") + string orderId, DateTime date, int level, + string userCurrency, double payPrice, string scene, bool isFree = false, + string offerId = "", string basePlanId = "") { var payedDate = TimeUtil.GetTimeStampString(date); - var request = GoogleOrderRequest.Build(orderType, productId, token, orderId, payedDate, level, offerId, basePlanId); + var request = GoogleOrderRequest.Build(orderType, productId, token, orderId, payedDate, level, + userCurrency, payPrice, scene, isFree, offerId, basePlanId); ReportNextOrder(request); } private void ReportGoogleOrder(GoogleOrderData data) @@ -962,10 +974,12 @@ namespace Guru /// /// private void ReportAppleOrder(int orderType, string productId, string receipt, - string orderId, DateTime date,int level, string offerId = "", string basePlanId = "") + string orderId, DateTime date,int level, string userCurrency, double payPrice, string scene, bool isFree = false, + string offerId = "", string basePlanId = "") { var payedDate = TimeUtil.GetTimeStampString(date); - var request = AppleOrderRequest.Build(orderType, productId, receipt, orderId, payedDate, level); + var request = AppleOrderRequest.Build(orderType, productId, receipt, orderId, payedDate, level, + userCurrency, payPrice, scene, isFree); ReportNextOrder(request); } @@ -1105,6 +1119,16 @@ namespace Guru } return null; } + + private SubscriptionManager GetSubManagerById(string productId) + { + var product = _storeController.products.WithID(productId); + if (product != null && product.definition.type == ProductType.Subscription) + { + return new SubscriptionManager(product, null); + } + return null; + } public bool IsSubscriptionFreeTrail(string productName) @@ -1118,6 +1142,18 @@ namespace Guru } return false; } + + public bool IsSubscriptionFreeTrailById(string productId) + { + if(!IsInitialized) return false; + + var smgr = GetSubManagerById(productId); + if (smgr != null) + { + return smgr.getSubscriptionInfo().isFreeTrial() == Result.True; + } + return false; + } public bool IsSubscriptionCancelled(string productName)