diff --git a/ExtraPluginCfgs/Android/flexion/AndroidManifest.xml b/ExtraPluginCfgs/Android/flexion/AndroidManifest.xml
index 567a8f2..16ca0ce 100644
--- a/ExtraPluginCfgs/Android/flexion/AndroidManifest.xml
+++ b/ExtraPluginCfgs/Android/flexion/AndroidManifest.xml
@@ -54,12 +54,13 @@
追加 ${applicationId}(Flexion 包名)作为后缀后,与 GP 版 authority 不同,
两个渠道包可同时安装在同一设备上,不会触发 INSTALL_FAILED_CONFLICTING_PROVIDER。
参考:Flexion 官方文档《Unique package name - follow-on requirements》
- -->
+
+ -->
diff --git a/ExtraPluginCfgs/Android/flexion/ChannelHelpers.java b/ExtraPluginCfgs/Android/flexion/ChannelHelpers.java
index 000d512..0111209 100644
--- a/ExtraPluginCfgs/Android/flexion/ChannelHelpers.java
+++ b/ExtraPluginCfgs/Android/flexion/ChannelHelpers.java
@@ -5,7 +5,7 @@ public class ChannelHelpers {
public static final String CHANNEL = "Flexion";
static void register() {
- SDKManager.registerHelper(CHANNEL, new FlexionSDKHelper());
+ SDKManager.registerHelper(new FlexionSDKHelper());
}
@@ -14,4 +14,7 @@ public class ChannelHelpers {
public static String normalizeSkuList(String msg) {
return msg;
}
+
+
+ //public SDKExtBuilder;
}
diff --git a/ExtraPluginCfgs/Android/flexion/FlexionSDKHelper.java b/ExtraPluginCfgs/Android/flexion/FlexionSDKHelper.java
index 1da70de..698df06 100644
--- a/ExtraPluginCfgs/Android/flexion/FlexionSDKHelper.java
+++ b/ExtraPluginCfgs/Android/flexion/FlexionSDKHelper.java
@@ -25,6 +25,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Base64;
import java.util.List;
public class FlexionSDKHelper implements SDKManager.ISDKHelper {
@@ -33,12 +34,18 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
private static boolean billingConnected = false;
private static final PurchasesUpdateListener purchasesListener = (billingResult, purchase) -> {
+
+
+ Log.i(TAG, "[PAY-FLOW] PurchasesUpdateListener: code=" + billingResult.getResponseCode()
+ + " hasPurchase=" + (purchase != null));
if (billingResult.getResponseCode() == BillingResults.ResultCode.PURCHASE_SUCCESS_CODE) {
if (purchase != null) handlePurchase(purchase);
} else if (billingResult.getResponseCode() == BillingResults.ResultCode.PURCHASE_USER_CANCELLED_CODE) {
- sendPayCallback(1, "user_cancelled", null, null);
+ Log.i(TAG, "[PAY-FLOW] user cancelled");
+ sendPayCallback(1, "user_cancelled", null, null, null);
} else {
- sendPayCallback(1, "purchase_failed_" + billingResult.getResponseCode(), null, null);
+ Log.e(TAG, "[PAY-FLOW] purchase failed: code=" + billingResult.getResponseCode());
+ sendPayCallback(1, "purchase_failed_" + billingResult.getResponseCode(), null, null, null);
}
};
@@ -83,19 +90,36 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
@Override
public void pay(Activity activity, String productId, String productName,
String productCount, String prodorderId, String appInfo) {
- Log.i(TAG, "pay: " + productId);
+ Log.i(TAG, "[PAY-FLOW] pay called: productId=" + productId + " billingReady=" + billingConnected);
if (billingService == null || !billingConnected) {
- sendPayCallback(1, "billing_not_ready", null, null);
+ Log.e(TAG, "[PAY-FLOW] billing not ready");
+ sendPayCallback(1, "billing_not_ready", null, null, null);
return;
}
- activity.runOnUiThread(() ->
- billingService.launchBillingFlow(activity,
- new BillingFlowParams(productId, "inapp", "")));
+ String developerPayload = "";
+ try {
+ byte[] decoded = Base64.getDecoder().decode(appInfo);
+ JSONObject json = new JSONObject(new String(decoded, "UTF-8"));
+ JSONObject payload = new JSONObject();
+ payload.put("playerId", json.optString("playerId", ""));
+ payload.put("customData", json.optString("customData", ""));
+ developerPayload = payload.toString();
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to extract playerId/customData from appInfo: " + e.getMessage());
+ }
+ String finalPayload = developerPayload;
+ activity.runOnUiThread(() -> {
+ Log.i(TAG, "[PAY-FLOW] launching billing flow for: " + productId + " payload=" + finalPayload);
+ billingService.launchBillingFlow(activity,
+ new BillingFlowParams(productId, "inapp", finalPayload));
+ });
}
@Override
public void queryProducts() {
+ Log.i(TAG, "queryProducts called, billingConnected=" + billingConnected);
if (billingService == null || !billingConnected) {
+ Log.w(TAG, "queryProducts: billing not ready");
sendExtensionError("billing_not_ready");
return;
}
@@ -108,6 +132,7 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
SDKAPI.getIns().thirdExtend(jsonObject.toString(), new SDKCallBack.Extend() {
@Override
public void callback(int code, String msg) {
+ Log.i(TAG, "TuYoo thirdExtend callback: code=" + code + " msg=" + msg);
if (code == SDKCallBack.Extend.EXTEND_CODE_SUCCESS && msg != null) {
try {
JSONArray products = new JSONArray(msg);
@@ -117,6 +142,7 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
String pid = p.optString("productId", "");
if (!pid.isEmpty()) productIds.add(pid);
}
+ Log.i(TAG, "queryProductDetails with " + productIds.size() + " items: " + productIds);
queryProductDetails(productIds);
} catch (JSONException e) {
sendExtensionError("parse_error: " + e.getMessage());
@@ -131,10 +157,12 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
// ---- Billing Infrastructure ----
private static void initBillingService(Activity activity) {
+ Log.i(TAG, "[PAY-FLOW] initBillingService");
billingService = FLX.createBillingService(activity, purchasesListener);
billingService.startConnection(activity, new ConnectionStateListener() {
@Override
public void onBillingSetupFinished(BillingResult result) {
+ Log.i(TAG, "[PAY-FLOW] onBillingSetupFinished: code=" + result.getResponseCode());
if (result.getResponseCode() == BillingResults.ResultCode.CONNECTION_SUCCESS_CODE) {
billingConnected = true;
queryPendingPurchases();
@@ -142,20 +170,22 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
}
@Override
public void onBillingServiceDisconnected() {
+ Log.w(TAG, "[PAY-FLOW] billing service disconnected");
billingConnected = false;
}
});
}
private static void handlePurchase(Purchase purchase) {
+ Log.i(TAG, "[PAY-FLOW] handlePurchase: state=" + purchase.getPurchaseState()
+ + " token=" + purchase.getToken());
if (purchase.getPurchaseState() == 0) {
- sendPayCallback(0, "success", purchase.getPurchaseJson(), purchase.getSignature());
- billingService.consumeAsync(
- new ConsumeParams(purchase.getToken()),
- r -> Log.i(TAG, "Consume " +
- (r.getResponseCode() == BillingResults.ResultCode.CONSUME_SUCCESS_CODE ? "ok" : "fail")));
+ Log.i(TAG, "[PAY-FLOW] purchaseJson=" + purchase.getPurchaseJson());
+ Log.i(TAG, "[PAY-FLOW] signature=" + purchase.getSignature());
+ sendPayCallback(0, "success", purchase.getPurchaseJson(), purchase.getSignature(), purchase.getToken());
} else if (purchase.getPurchaseState() == 2) {
- sendPayCallback(2, "pending", null, null);
+ Log.i(TAG, "[PAY-FLOW] purchase state=2 (pending)");
+ sendPayCallback(2, "pending", null, null, null);
}
}
@@ -207,13 +237,19 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
// ---- Callbacks to Unity ----
- private static void sendPayCallback(int code, String errStr, String purchaseJson, String signature) {
+ private static void sendPayCallback(int code, String errStr,
+ String purchaseJson, String signature, String purchaseToken) {
+ Log.i(TAG, "[PAY-FLOW] sendPayCallback: code=" + code + " errStr=" + errStr
+ + " hasPurchaseJson=" + (purchaseJson != null) + " hasSignature=" + (signature != null)
+ + " hasToken=" + (purchaseToken != null));
try {
JSONObject result = new JSONObject();
result.put("code", code);
result.put("errStr", errStr != null ? errStr : "");
if (purchaseJson != null) result.put("purchaseJson", purchaseJson);
if (signature != null) result.put("signature", signature);
+ if (purchaseToken != null) result.put("purchaseToken", purchaseToken);
+ Log.i(TAG, "[PAY-FLOW] UnitySendMessage callback: " + result.toString());
UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME,
ConfigManager.PAY_CALLBACK_FUNCTION_NAME, result.toString());
} catch (JSONException e) {
@@ -222,6 +258,18 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
}
}
+ public static void consumePurchase(String token) {
+ if (billingService == null || token == null || token.isEmpty()) {
+ Log.w(TAG, "[PAY-FLOW] consumePurchase: billingService or token is null");
+ return;
+ }
+ Log.i(TAG, "[PAY-FLOW] consumePurchase: token=" + token);
+ billingService.consumeAsync(
+ new ConsumeParams(token),
+ r -> Log.i(TAG, "[PAY-FLOW] consume result: " +
+ (r.getResponseCode() == BillingResults.ResultCode.CONSUME_SUCCESS_CODE ? "ok" : "fail")));
+ }
+
private static void sendExtensionError(String errStr) {
try {
JSONObject result = new JSONObject();
diff --git a/ExtraPluginCfgs/Android/flexion/Plugins/Android/tuyoosdk_1.0.0.aar b/ExtraPluginCfgs/Android/flexion/Plugins/Android/tuyoosdk_1.0.0.aar
index b16d93c..2fcfaf0 100644
Binary files a/ExtraPluginCfgs/Android/flexion/Plugins/Android/tuyoosdk_1.0.0.aar and b/ExtraPluginCfgs/Android/flexion/Plugins/Android/tuyoosdk_1.0.0.aar differ
diff --git a/sdk-intergration/Assets/Plugins/Android/AndroidManifest.xml b/sdk-intergration/Assets/Plugins/Android/AndroidManifest.xml
index ebd9b2e..4a20bb8 100644
--- a/sdk-intergration/Assets/Plugins/Android/AndroidManifest.xml
+++ b/sdk-intergration/Assets/Plugins/Android/AndroidManifest.xml
@@ -1,48 +1,52 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sdk-intergration/Assets/Plugins/Android/mainTemplate.gradle b/sdk-intergration/Assets/Plugins/Android/mainTemplate.gradle
index 0505686..54696e0 100644
--- a/sdk-intergration/Assets/Plugins/Android/mainTemplate.gradle
+++ b/sdk-intergration/Assets/Plugins/Android/mainTemplate.gradle
@@ -82,9 +82,7 @@ dependencies {
implementation 'com.applovin.mediation:vungle-adapter:7.4.2.2' // Assets/MaxSdk/Mediation/Vungle/Editor/Dependencies.xml:4
implementation 'com.applovin:applovin-sdk:13.5.1' // Assets/MaxSdk/AppLovin/Editor/Dependencies.xml:4
implementation 'com.appsflyer:af-android-sdk:6.17.3' // Assets/AppsFlyer/Editor/AppsFlyerDependencies.xml:5
- // Flexion: purchase-connector removed — Flexion does not use Google Play Billing.
- // Also covered by top-level `configurations.all { exclude ... }` as a safety net.
- // implementation 'com.appsflyer:purchase-connector:2.2.0' // Assets/AppsFlyer/Editor/AppsFlyerDependencies.xml:8
+ implementation 'com.appsflyer:purchase-connector:2.2.0' // Assets/AppsFlyer/Editor/AppsFlyerDependencies.xml:8
implementation 'com.appsflyer:unity-wrapper:6.17.7' // Assets/AppsFlyer/Editor/AppsFlyerDependencies.xml:6
implementation 'com.google.android.ump:user-messaging-platform:2.1.0' // Assets/MaxSdk/AppLovin/Editor/Dependencies.xml:5
// Android Resolver Dependencies End
diff --git a/sdk-intergration/Assets/Scenes/SampleScene.unity b/sdk-intergration/Assets/Scenes/SampleScene.unity
index 50dc601..b521c8b 100644
--- a/sdk-intergration/Assets/Scenes/SampleScene.unity
+++ b/sdk-intergration/Assets/Scenes/SampleScene.unity
@@ -1964,6 +1964,85 @@ MonoBehaviour:
m_OnClick:
m_PersistentCalls:
m_Calls: []
+--- !u!1 &783615086
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 783615087}
+ - component: {fileID: 783615089}
+ - component: {fileID: 783615088}
+ m_Layer: 5
+ m_Name: Title
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &783615087
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 783615086}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1451597222}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 1}
+ m_AnchorMax: {x: 0.5, y: 1}
+ m_AnchoredPosition: {x: 0, y: -57}
+ m_SizeDelta: {x: 294.3188, y: 100}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &783615088
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 783615086}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.8207547, g: 0.8207547, b: 0.8207547, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 27
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 0
+ m_MaxSize: 61
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: GooglePlay
+--- !u!222 &783615089
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 783615086}
+ m_CullTransparentMesh: 1
--- !u!1 &816060983
GameObject:
m_ObjectHideFlags: 0
@@ -4263,6 +4342,7 @@ RectTransform:
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
+ - {fileID: 783615087}
- {fileID: 2070325009}
- {fileID: 1044920373}
m_Father: {fileID: 0}
@@ -4968,6 +5048,7 @@ MonoBehaviour:
_mfbShareLinkBtn: {fileID: 1240291501}
_reviewBtn: {fileID: 678940591}
_messageTxt: {fileID: 2070325010}
+ _titleText: {fileID: 783615088}
--- !u!4 &1788702880
Transform:
m_ObjectHideFlags: 0
@@ -5417,7 +5498,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 1}
m_AnchorMax: {x: 0.5, y: 1}
- m_AnchoredPosition: {x: 0, y: -120}
+ m_AnchoredPosition: {x: 0, y: -152}
m_SizeDelta: {x: 800, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &2070325010
diff --git a/sdk-intergration/Assets/Scripts/SDKTest.cs b/sdk-intergration/Assets/Scripts/SDKTest.cs
index 2eb32ce..acfbc82 100644
--- a/sdk-intergration/Assets/Scripts/SDKTest.cs
+++ b/sdk-intergration/Assets/Scripts/SDKTest.cs
@@ -62,6 +62,9 @@ public class SDKTest : MonoBehaviour
[SerializeField]
private Text _messageTxt;
+
+ [SerializeField]
+ private Text _titleText;
void Start()
{
@@ -71,6 +74,7 @@ public class SDKTest : MonoBehaviour
GContext.container.RegisterInstance(config);
Debug.Log("SDKTest Start");
+ UpdateChannelTitle();
//===============================================================================
//====================== Test Server ===========================
// UnityBridgeFunc.UnityResetServerUrl("https://128-hwsfsdk-sdk-test01.qijihdhk.com");
@@ -130,6 +134,18 @@ public class SDKTest : MonoBehaviour
UnityBridgeFunc.UnityResetServerUrl("https://128-hwsfsdk-sdk-test01.qijihdhk.com");
}
+ private void UpdateChannelTitle()
+ {
+#if UNITY_ANDROID
+ using (var cls = new AndroidJavaClass("com.unity3d.player.ChannelHelpers"))
+ {
+ string channel = cls.GetStatic("CHANNEL");
+ Debug.Log($"[SDKTest] Channel from Java: {channel}");
+ _titleText.text = $" {channel}";
+ }
+#endif
+ }
+
int retryAttempt;
public void InitializeRewardedAds()
@@ -161,6 +177,7 @@ public class SDKTest : MonoBehaviour
_messageTxt.text = $"Login: {info.isSuccess}";
if (info.isSuccess)
{
+ _messageTxt.text += $" UserId:{info.userId}";
_messageTxt.text += $"\n{info.msg}";
_messageTxt.text += $"\n{TYSdkFacade.TYAccountInfo.token}";
}
@@ -187,10 +204,23 @@ public class SDKTest : MonoBehaviour
public async void OnPayTestBtn()
{
_messageTxt.text = "";
+
+ if (ChannelConfig.Channel.Equals("Flexion"))
+ {
+ sku = new SKUDetail
+ {
+ productId = "com.arkgame.ft.pack0199",
+ ourProductId = "com.arkgame.ft.pack0199",
+ price = "1.99",
+ price_amount_micros = "1990000",
+ title = "Flexion Test Pack",
+ type = "inapp"
+ };
+ }
if (sku == null){
_messageTxt.text = "no product";
return;
- }
+ }
#if !UNITY_EDITOR && UNITY_IOS
sku.productId = "comarkgameftpack0199";
@@ -201,7 +231,7 @@ public class SDKTest : MonoBehaviour
var purchaseInfo = new JObject();
purchaseInfo["pfid"] = "TestPlayer";
purchaseInfo["customData"] = "{\"test\":\"test\"}";
-
+ purchaseInfo["playerId"] = TYSdkFacade.TYAccountInfo.strUserId;
PaymentInfo payResult = await TYSdkFacade.Instance.Pay(sku, 1, sku.ProdPrice, purchaseInfo);
_messageTxt.text = "\n" + $"Success : {payResult.isSuccess}";
@@ -220,6 +250,7 @@ public class SDKTest : MonoBehaviour
_messageTxt.text = "products count:::" + result.products.Count;
_messageTxt.text += "\n" + result.products[0].ToString();
sku = result.products[0];
+ Debug.Log($"Sku -> {sku}");
}
else
{
diff --git a/sdk-intergration/Packages/tysdk/Plugins/Android/ChannelHelpers.java b/sdk-intergration/Packages/tysdk/Plugins/Android/ChannelHelpers.java
index 000d512..0111209 100644
--- a/sdk-intergration/Packages/tysdk/Plugins/Android/ChannelHelpers.java
+++ b/sdk-intergration/Packages/tysdk/Plugins/Android/ChannelHelpers.java
@@ -5,7 +5,7 @@ public class ChannelHelpers {
public static final String CHANNEL = "Flexion";
static void register() {
- SDKManager.registerHelper(CHANNEL, new FlexionSDKHelper());
+ SDKManager.registerHelper(new FlexionSDKHelper());
}
@@ -14,4 +14,7 @@ public class ChannelHelpers {
public static String normalizeSkuList(String msg) {
return msg;
}
+
+
+ //public SDKExtBuilder;
}
diff --git a/sdk-intergration/Packages/tysdk/Plugins/Android/FlexionSDKHelper.java b/sdk-intergration/Packages/tysdk/Plugins/Android/FlexionSDKHelper.java
index 1da70de..698df06 100644
--- a/sdk-intergration/Packages/tysdk/Plugins/Android/FlexionSDKHelper.java
+++ b/sdk-intergration/Packages/tysdk/Plugins/Android/FlexionSDKHelper.java
@@ -25,6 +25,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Base64;
import java.util.List;
public class FlexionSDKHelper implements SDKManager.ISDKHelper {
@@ -33,12 +34,18 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
private static boolean billingConnected = false;
private static final PurchasesUpdateListener purchasesListener = (billingResult, purchase) -> {
+
+
+ Log.i(TAG, "[PAY-FLOW] PurchasesUpdateListener: code=" + billingResult.getResponseCode()
+ + " hasPurchase=" + (purchase != null));
if (billingResult.getResponseCode() == BillingResults.ResultCode.PURCHASE_SUCCESS_CODE) {
if (purchase != null) handlePurchase(purchase);
} else if (billingResult.getResponseCode() == BillingResults.ResultCode.PURCHASE_USER_CANCELLED_CODE) {
- sendPayCallback(1, "user_cancelled", null, null);
+ Log.i(TAG, "[PAY-FLOW] user cancelled");
+ sendPayCallback(1, "user_cancelled", null, null, null);
} else {
- sendPayCallback(1, "purchase_failed_" + billingResult.getResponseCode(), null, null);
+ Log.e(TAG, "[PAY-FLOW] purchase failed: code=" + billingResult.getResponseCode());
+ sendPayCallback(1, "purchase_failed_" + billingResult.getResponseCode(), null, null, null);
}
};
@@ -83,19 +90,36 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
@Override
public void pay(Activity activity, String productId, String productName,
String productCount, String prodorderId, String appInfo) {
- Log.i(TAG, "pay: " + productId);
+ Log.i(TAG, "[PAY-FLOW] pay called: productId=" + productId + " billingReady=" + billingConnected);
if (billingService == null || !billingConnected) {
- sendPayCallback(1, "billing_not_ready", null, null);
+ Log.e(TAG, "[PAY-FLOW] billing not ready");
+ sendPayCallback(1, "billing_not_ready", null, null, null);
return;
}
- activity.runOnUiThread(() ->
- billingService.launchBillingFlow(activity,
- new BillingFlowParams(productId, "inapp", "")));
+ String developerPayload = "";
+ try {
+ byte[] decoded = Base64.getDecoder().decode(appInfo);
+ JSONObject json = new JSONObject(new String(decoded, "UTF-8"));
+ JSONObject payload = new JSONObject();
+ payload.put("playerId", json.optString("playerId", ""));
+ payload.put("customData", json.optString("customData", ""));
+ developerPayload = payload.toString();
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to extract playerId/customData from appInfo: " + e.getMessage());
+ }
+ String finalPayload = developerPayload;
+ activity.runOnUiThread(() -> {
+ Log.i(TAG, "[PAY-FLOW] launching billing flow for: " + productId + " payload=" + finalPayload);
+ billingService.launchBillingFlow(activity,
+ new BillingFlowParams(productId, "inapp", finalPayload));
+ });
}
@Override
public void queryProducts() {
+ Log.i(TAG, "queryProducts called, billingConnected=" + billingConnected);
if (billingService == null || !billingConnected) {
+ Log.w(TAG, "queryProducts: billing not ready");
sendExtensionError("billing_not_ready");
return;
}
@@ -108,6 +132,7 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
SDKAPI.getIns().thirdExtend(jsonObject.toString(), new SDKCallBack.Extend() {
@Override
public void callback(int code, String msg) {
+ Log.i(TAG, "TuYoo thirdExtend callback: code=" + code + " msg=" + msg);
if (code == SDKCallBack.Extend.EXTEND_CODE_SUCCESS && msg != null) {
try {
JSONArray products = new JSONArray(msg);
@@ -117,6 +142,7 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
String pid = p.optString("productId", "");
if (!pid.isEmpty()) productIds.add(pid);
}
+ Log.i(TAG, "queryProductDetails with " + productIds.size() + " items: " + productIds);
queryProductDetails(productIds);
} catch (JSONException e) {
sendExtensionError("parse_error: " + e.getMessage());
@@ -131,10 +157,12 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
// ---- Billing Infrastructure ----
private static void initBillingService(Activity activity) {
+ Log.i(TAG, "[PAY-FLOW] initBillingService");
billingService = FLX.createBillingService(activity, purchasesListener);
billingService.startConnection(activity, new ConnectionStateListener() {
@Override
public void onBillingSetupFinished(BillingResult result) {
+ Log.i(TAG, "[PAY-FLOW] onBillingSetupFinished: code=" + result.getResponseCode());
if (result.getResponseCode() == BillingResults.ResultCode.CONNECTION_SUCCESS_CODE) {
billingConnected = true;
queryPendingPurchases();
@@ -142,20 +170,22 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
}
@Override
public void onBillingServiceDisconnected() {
+ Log.w(TAG, "[PAY-FLOW] billing service disconnected");
billingConnected = false;
}
});
}
private static void handlePurchase(Purchase purchase) {
+ Log.i(TAG, "[PAY-FLOW] handlePurchase: state=" + purchase.getPurchaseState()
+ + " token=" + purchase.getToken());
if (purchase.getPurchaseState() == 0) {
- sendPayCallback(0, "success", purchase.getPurchaseJson(), purchase.getSignature());
- billingService.consumeAsync(
- new ConsumeParams(purchase.getToken()),
- r -> Log.i(TAG, "Consume " +
- (r.getResponseCode() == BillingResults.ResultCode.CONSUME_SUCCESS_CODE ? "ok" : "fail")));
+ Log.i(TAG, "[PAY-FLOW] purchaseJson=" + purchase.getPurchaseJson());
+ Log.i(TAG, "[PAY-FLOW] signature=" + purchase.getSignature());
+ sendPayCallback(0, "success", purchase.getPurchaseJson(), purchase.getSignature(), purchase.getToken());
} else if (purchase.getPurchaseState() == 2) {
- sendPayCallback(2, "pending", null, null);
+ Log.i(TAG, "[PAY-FLOW] purchase state=2 (pending)");
+ sendPayCallback(2, "pending", null, null, null);
}
}
@@ -207,13 +237,19 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
// ---- Callbacks to Unity ----
- private static void sendPayCallback(int code, String errStr, String purchaseJson, String signature) {
+ private static void sendPayCallback(int code, String errStr,
+ String purchaseJson, String signature, String purchaseToken) {
+ Log.i(TAG, "[PAY-FLOW] sendPayCallback: code=" + code + " errStr=" + errStr
+ + " hasPurchaseJson=" + (purchaseJson != null) + " hasSignature=" + (signature != null)
+ + " hasToken=" + (purchaseToken != null));
try {
JSONObject result = new JSONObject();
result.put("code", code);
result.put("errStr", errStr != null ? errStr : "");
if (purchaseJson != null) result.put("purchaseJson", purchaseJson);
if (signature != null) result.put("signature", signature);
+ if (purchaseToken != null) result.put("purchaseToken", purchaseToken);
+ Log.i(TAG, "[PAY-FLOW] UnitySendMessage callback: " + result.toString());
UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME,
ConfigManager.PAY_CALLBACK_FUNCTION_NAME, result.toString());
} catch (JSONException e) {
@@ -222,6 +258,18 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
}
}
+ public static void consumePurchase(String token) {
+ if (billingService == null || token == null || token.isEmpty()) {
+ Log.w(TAG, "[PAY-FLOW] consumePurchase: billingService or token is null");
+ return;
+ }
+ Log.i(TAG, "[PAY-FLOW] consumePurchase: token=" + token);
+ billingService.consumeAsync(
+ new ConsumeParams(token),
+ r -> Log.i(TAG, "[PAY-FLOW] consume result: " +
+ (r.getResponseCode() == BillingResults.ResultCode.CONSUME_SUCCESS_CODE ? "ok" : "fail")));
+ }
+
private static void sendExtensionError(String errStr) {
try {
JSONObject result = new JSONObject();
diff --git a/sdk-intergration/Packages/tysdk/Plugins/Android/SDKManager.java b/sdk-intergration/Packages/tysdk/Plugins/Android/SDKManager.java
index c6065f6..2cc9cba 100644
--- a/sdk-intergration/Packages/tysdk/Plugins/Android/SDKManager.java
+++ b/sdk-intergration/Packages/tysdk/Plugins/Android/SDKManager.java
@@ -57,19 +57,26 @@ public class SDKManager {
private static SnsInfo tmpSnsInfo;
private static String channel = "GooglePlay";
- // Channel helper registry
+ // Channel helper
public interface ISDKHelper {
void init(Activity activity);
void pay(Activity activity, String productId, String productName,
String productCount, String prodorderId, String appInfo);
void queryProducts();
+ void consume(String token);
}
- private static final java.util.Map helperMap = new java.util.HashMap<>();
private static ISDKHelper sdkHelper;
- public static void registerHelper(String ch, ISDKHelper helper) {
- helperMap.put(ch, helper);
+ public static void registerHelper(ISDKHelper helper) {
+ sdkHelper = helper;
+ }
+
+ public static void ConsumeFlexionPurchase(String token) {
+ Log.i(TAG, "ConsumeFlexionPurchase: token=" + token);
+ if (sdkHelper != null) {
+ sdkHelper.consume(token);
+ }
}
// -------------------------------------------------------------------------
@@ -79,7 +86,16 @@ public class SDKManager {
public static void InitSDK(Activity activity, String ch) {
channel = ChannelHelpers.CHANNEL;
ChannelHelpers.register();
- sdkHelper = helperMap.get(channel);
+
+// var builder = SDKManager.ExtendBuilder()
+// .WithChannel(SDKManagerExt.CHANNEL)
+// .WithInit(SDKManagerExt.GetInit())
+// .WithPay(SDKManagerExt.GetPay())
+// .WithQuery(SDKManagerExt.GetQuery())
+// .Builder()
+
+
+
Log.i(TAG, "[CHANNEL-VERIFY] Java InitSDK channel=" + channel
+ " fromCSharp=" + ch
+ " helper=" + (sdkHelper != null ? sdkHelper.getClass().getSimpleName() : "default"));
@@ -87,7 +103,8 @@ public class SDKManager {
// Sync channel to C# ChannelConfig
UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME,
"SetChannelFromNative", channel);
-
+
+// build.init(activity)
if (sdkHelper != null) {
sdkHelper.init(activity);
} else {
@@ -402,6 +419,7 @@ public class SDKManager {
// -------------------------------------------------------------------------
public static void thirdExtend() {
+ Log.e(TAG, "thirdExtend called, sdkHelper=" + (sdkHelper != null ? sdkHelper.getClass().getSimpleName() : "null"));
if (sdkHelper != null) {
sdkHelper.queryProducts();
return;
diff --git a/sdk-intergration/Packages/tysdk/Plugins/Android/tuyoosdk_1.0.0.aar b/sdk-intergration/Packages/tysdk/Plugins/Android/tuyoosdk_1.0.0.aar
index b16d93c..2fcfaf0 100644
Binary files a/sdk-intergration/Packages/tysdk/Plugins/Android/tuyoosdk_1.0.0.aar and b/sdk-intergration/Packages/tysdk/Plugins/Android/tuyoosdk_1.0.0.aar differ
diff --git a/sdk-intergration/Packages/tysdk/Runtime/TYSdkFacade_Pay.cs b/sdk-intergration/Packages/tysdk/Runtime/TYSdkFacade_Pay.cs
index a877cbe..7d4b2b1 100644
--- a/sdk-intergration/Packages/tysdk/Runtime/TYSdkFacade_Pay.cs
+++ b/sdk-intergration/Packages/tysdk/Runtime/TYSdkFacade_Pay.cs
@@ -30,6 +30,7 @@ namespace tysdk
if (purchaseInfo == null)
purchaseInfo = new JObject();
+ // purchaseInfo["playerId"] = _accountInfo.strUserId;
string extraInfo = purchaseInfo.ToString(Newtonsoft.Json.Formatting.None);
extraInfo = Convert.ToBase64String(Encoding.UTF8.GetBytes(extraInfo));
@@ -56,18 +57,16 @@ namespace tysdk
#elif UNITY_ANDROID
var pType = ChannelConfig.PayType;
-
- var task = TYSDKCallbackManager.Instance.RegisterCallback(TimeSpan.FromSeconds(30));
-
+ var task = TYSDKCallbackManager.Instance.RegisterCallback(TimeSpan.FromSeconds(90));
try
{
UnityBridgeFunc.UnityKnowNew(prodId, prodPrice, prodName, count.ToString(), orderId, extraInfo, pType);
-
var result = await task;
result.count = count;
result.orderId = orderId;
result.productId = prodId;
result.price = prodPrice;
+ result.Check(orderId, prodId);
return result;
}
catch (Exception e)
@@ -112,6 +111,9 @@ namespace tysdk
var result = new PaymentInfo();
result.code = jresult["code"].ToString();
result.msg = jresult["errStr"].ToString();
+ result.purchaseJson = jresult["purchaseJson"]?.ToString();
+ result.signature = jresult["signature"]?.ToString();
+ result.purchaseToken = jresult["purchaseToken"]?.ToString();
if (result.code == "-1")
{
if (!_payFirstNegativeHandled)
diff --git a/sdk-intergration/Packages/tysdk/Runtime/TYSdkModel.cs b/sdk-intergration/Packages/tysdk/Runtime/TYSdkModel.cs
index 1954082..375df67 100644
--- a/sdk-intergration/Packages/tysdk/Runtime/TYSdkModel.cs
+++ b/sdk-intergration/Packages/tysdk/Runtime/TYSdkModel.cs
@@ -21,6 +21,8 @@ namespace tysdk
public string purchaseJson;
// Flexion: purchase.getSignature(), used by server for RSA signature verification
public string signature;
+ // Flexion: purchase token, used to consume after server verification
+ public string purchaseToken;
public bool Check(string orderId, string productId)
{
diff --git a/sdk-intergration/Packages/tysdk/Runtime/UnityBridgeFunc.cs b/sdk-intergration/Packages/tysdk/Runtime/UnityBridgeFunc.cs
index e665a43..681b7ea 100644
--- a/sdk-intergration/Packages/tysdk/Runtime/UnityBridgeFunc.cs
+++ b/sdk-intergration/Packages/tysdk/Runtime/UnityBridgeFunc.cs
@@ -168,6 +168,14 @@ namespace tysdk
}
}
+ public static void ConsumeFlexionPurchase(string token)
+ {
+ using (var sdkManager = new AndroidJavaClass(SDK_CLASS))
+ {
+ sdkManager.CallStatic("ConsumeFlexionPurchase", token);
+ }
+ }
+
public static void UnityKnow(String productId, String productName, String productCount, String prodorderId, String appInfo)
{
using (var sdkManager = new AndroidJavaClass(SDK_CLASS))
diff --git a/sdk-intergration/ProjectSettings/ProjectSettings.asset b/sdk-intergration/ProjectSettings/ProjectSettings.asset
index 6bde347..b4f01c9 100644
--- a/sdk-intergration/ProjectSettings/ProjectSettings.asset
+++ b/sdk-intergration/ProjectSettings/ProjectSettings.asset
@@ -163,7 +163,7 @@ PlayerSettings:
androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.1
applicationIdentifier:
- Android: com.arkgame.ft
+ Android: com.arkgame.ft.flexion
Standalone: com.Unity-Technologies.com.unity.template.urp-blank
iPhone: com.arkgame.ft
buildNumber: