feat: Flexion 先验签后消费支付流程 + playerId 绑定
实现 Flexion 渠道支付验签重构:支付成功后不立即消费,将 purchaseJson/signature/purchaseToken 回调至 Unity,由服务端 SHA1withRSA 验签并校验 developerPayload.playerId 后再调用 consume。 同步更新 SDKManager 接口、UnityBridgeFunc 桥接、TYSdkModel 字段及 ExtraPluginCfgs。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -54,12 +54,13 @@
|
|||||||
追加 ${applicationId}(Flexion 包名)作为后缀后,与 GP 版 authority 不同,
|
追加 ${applicationId}(Flexion 包名)作为后缀后,与 GP 版 authority 不同,
|
||||||
两个渠道包可同时安装在同一设备上,不会触发 INSTALL_FAILED_CONFLICTING_PROVIDER。
|
两个渠道包可同时安装在同一设备上,不会触发 INSTALL_FAILED_CONFLICTING_PROVIDER。
|
||||||
参考:Flexion 官方文档《Unique package name - follow-on requirements》
|
参考:Flexion 官方文档《Unique package name - follow-on requirements》
|
||||||
-->
|
|
||||||
<provider
|
<provider
|
||||||
android:name="com.facebook.FacebookContentProvider"
|
android:name="com.facebook.FacebookContentProvider"
|
||||||
android:authorities="com.facebook.app.FacebookContentProvider162066986963808.${applicationId}"
|
android:authorities="com.facebook.app.FacebookContentProvider162066986963808.${applicationId}"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
tools:replace="android:authorities" />
|
tools:replace="android:authorities" />
|
||||||
|
-->
|
||||||
</application>
|
</application>
|
||||||
<queries>
|
<queries>
|
||||||
<provider android:authorities="com.facebook.katana.provider.PlatformProvider" />
|
<provider android:authorities="com.facebook.katana.provider.PlatformProvider" />
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ public class ChannelHelpers {
|
|||||||
public static final String CHANNEL = "Flexion";
|
public static final String CHANNEL = "Flexion";
|
||||||
|
|
||||||
static void register() {
|
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) {
|
public static String normalizeSkuList(String msg) {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//public SDKExtBuilder;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
||||||
@@ -33,12 +34,18 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
private static boolean billingConnected = false;
|
private static boolean billingConnected = false;
|
||||||
|
|
||||||
private static final PurchasesUpdateListener purchasesListener = (billingResult, purchase) -> {
|
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 (billingResult.getResponseCode() == BillingResults.ResultCode.PURCHASE_SUCCESS_CODE) {
|
||||||
if (purchase != null) handlePurchase(purchase);
|
if (purchase != null) handlePurchase(purchase);
|
||||||
} else if (billingResult.getResponseCode() == BillingResults.ResultCode.PURCHASE_USER_CANCELLED_CODE) {
|
} 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 {
|
} 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
|
@Override
|
||||||
public void pay(Activity activity, String productId, String productName,
|
public void pay(Activity activity, String productId, String productName,
|
||||||
String productCount, String prodorderId, String appInfo) {
|
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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
activity.runOnUiThread(() ->
|
String developerPayload = "";
|
||||||
billingService.launchBillingFlow(activity,
|
try {
|
||||||
new BillingFlowParams(productId, "inapp", "")));
|
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
|
@Override
|
||||||
public void queryProducts() {
|
public void queryProducts() {
|
||||||
|
Log.i(TAG, "queryProducts called, billingConnected=" + billingConnected);
|
||||||
if (billingService == null || !billingConnected) {
|
if (billingService == null || !billingConnected) {
|
||||||
|
Log.w(TAG, "queryProducts: billing not ready");
|
||||||
sendExtensionError("billing_not_ready");
|
sendExtensionError("billing_not_ready");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -108,6 +132,7 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
SDKAPI.getIns().thirdExtend(jsonObject.toString(), new SDKCallBack.Extend() {
|
SDKAPI.getIns().thirdExtend(jsonObject.toString(), new SDKCallBack.Extend() {
|
||||||
@Override
|
@Override
|
||||||
public void callback(int code, String msg) {
|
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) {
|
if (code == SDKCallBack.Extend.EXTEND_CODE_SUCCESS && msg != null) {
|
||||||
try {
|
try {
|
||||||
JSONArray products = new JSONArray(msg);
|
JSONArray products = new JSONArray(msg);
|
||||||
@@ -117,6 +142,7 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
String pid = p.optString("productId", "");
|
String pid = p.optString("productId", "");
|
||||||
if (!pid.isEmpty()) productIds.add(pid);
|
if (!pid.isEmpty()) productIds.add(pid);
|
||||||
}
|
}
|
||||||
|
Log.i(TAG, "queryProductDetails with " + productIds.size() + " items: " + productIds);
|
||||||
queryProductDetails(productIds);
|
queryProductDetails(productIds);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
sendExtensionError("parse_error: " + e.getMessage());
|
sendExtensionError("parse_error: " + e.getMessage());
|
||||||
@@ -131,10 +157,12 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
// ---- Billing Infrastructure ----
|
// ---- Billing Infrastructure ----
|
||||||
|
|
||||||
private static void initBillingService(Activity activity) {
|
private static void initBillingService(Activity activity) {
|
||||||
|
Log.i(TAG, "[PAY-FLOW] initBillingService");
|
||||||
billingService = FLX.createBillingService(activity, purchasesListener);
|
billingService = FLX.createBillingService(activity, purchasesListener);
|
||||||
billingService.startConnection(activity, new ConnectionStateListener() {
|
billingService.startConnection(activity, new ConnectionStateListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onBillingSetupFinished(BillingResult result) {
|
public void onBillingSetupFinished(BillingResult result) {
|
||||||
|
Log.i(TAG, "[PAY-FLOW] onBillingSetupFinished: code=" + result.getResponseCode());
|
||||||
if (result.getResponseCode() == BillingResults.ResultCode.CONNECTION_SUCCESS_CODE) {
|
if (result.getResponseCode() == BillingResults.ResultCode.CONNECTION_SUCCESS_CODE) {
|
||||||
billingConnected = true;
|
billingConnected = true;
|
||||||
queryPendingPurchases();
|
queryPendingPurchases();
|
||||||
@@ -142,20 +170,22 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onBillingServiceDisconnected() {
|
public void onBillingServiceDisconnected() {
|
||||||
|
Log.w(TAG, "[PAY-FLOW] billing service disconnected");
|
||||||
billingConnected = false;
|
billingConnected = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handlePurchase(Purchase purchase) {
|
private static void handlePurchase(Purchase purchase) {
|
||||||
|
Log.i(TAG, "[PAY-FLOW] handlePurchase: state=" + purchase.getPurchaseState()
|
||||||
|
+ " token=" + purchase.getToken());
|
||||||
if (purchase.getPurchaseState() == 0) {
|
if (purchase.getPurchaseState() == 0) {
|
||||||
sendPayCallback(0, "success", purchase.getPurchaseJson(), purchase.getSignature());
|
Log.i(TAG, "[PAY-FLOW] purchaseJson=" + purchase.getPurchaseJson());
|
||||||
billingService.consumeAsync(
|
Log.i(TAG, "[PAY-FLOW] signature=" + purchase.getSignature());
|
||||||
new ConsumeParams(purchase.getToken()),
|
sendPayCallback(0, "success", purchase.getPurchaseJson(), purchase.getSignature(), purchase.getToken());
|
||||||
r -> Log.i(TAG, "Consume " +
|
|
||||||
(r.getResponseCode() == BillingResults.ResultCode.CONSUME_SUCCESS_CODE ? "ok" : "fail")));
|
|
||||||
} else if (purchase.getPurchaseState() == 2) {
|
} 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 ----
|
// ---- 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 {
|
try {
|
||||||
JSONObject result = new JSONObject();
|
JSONObject result = new JSONObject();
|
||||||
result.put("code", code);
|
result.put("code", code);
|
||||||
result.put("errStr", errStr != null ? errStr : "");
|
result.put("errStr", errStr != null ? errStr : "");
|
||||||
if (purchaseJson != null) result.put("purchaseJson", purchaseJson);
|
if (purchaseJson != null) result.put("purchaseJson", purchaseJson);
|
||||||
if (signature != null) result.put("signature", signature);
|
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,
|
UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME,
|
||||||
ConfigManager.PAY_CALLBACK_FUNCTION_NAME, result.toString());
|
ConfigManager.PAY_CALLBACK_FUNCTION_NAME, result.toString());
|
||||||
} catch (JSONException e) {
|
} 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) {
|
private static void sendExtensionError(String errStr) {
|
||||||
try {
|
try {
|
||||||
JSONObject result = new JSONObject();
|
JSONObject result = new JSONObject();
|
||||||
|
|||||||
Binary file not shown.
@@ -1,48 +1,52 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.arkgame.ft.flexion" xmlns:tools="http://schemas.android.com/tools">
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
package="com.arkgame.ft"
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<application android:extractNativeLibs="true" android:name="com.unity3d.player.TYApp" tools:replace="android:usesCleartextTraffic,android:fullBackupContent" android:fullBackupContent="@xml/flexion_backup_rules" android:usesCleartextTraffic="true">
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<activity android:name="com.unity3d.player.TYUnityActivity" android:theme="@style/UnityThemeSelector">
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
<intent-filter>
|
||||||
<application android:extractNativeLibs="true" android:name="com.unity3d.player.TYApp" android:usesCleartextTraffic="true">
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<activity android:name="com.unity3d.player.TYUnityActivity"
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
android:theme="@style/UnityThemeSelector">
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter android:autoVerify="true">
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" android:host="fishingtraveliae.onelink.me" android:pathPrefix="/jT1Q" />
|
||||||
<intent-filter android:autoVerify="true">
|
</intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<intent-filter>
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:scheme="https" android:host="fishingtraveliae.onelink.me" android:pathPrefix="/jT1Q"/>
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
</intent-filter>
|
<data android:host="mainactivity" android:scheme="zzft" />
|
||||||
|
</intent-filter>
|
||||||
<intent-filter>
|
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
|
||||||
<action android:name="android.intent.action.VIEW" />
|
</activity>
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<!-- 渠道标识,ChannelManager 读取此值以识别 Flexion 渠道 -->
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<meta-data android:name="CHANNEL" android:value="Flexion" />
|
||||||
<data android:host="mainactivity" android:scheme="zzft" />
|
<!-- 覆盖 gasdk 与 tuyoosdk 的 MainProcessName 冲突 -->
|
||||||
</intent-filter>
|
<meta-data android:name="com.sensorsdata.analytics.android.MainProcessName" android:value="com.arkgame.ft.flexion" tools:replace="android:value" />
|
||||||
|
<!-- Flexion SDK 应用标识,从 DropPoint 获取 -->
|
||||||
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
|
<meta-data android:name="com.flexionmobile.fdk.apptoken" android:value="fishingtravel" />
|
||||||
|
<!-- 告知 Flexion SDK 当前为 Unity 项目,必须声明 -->
|
||||||
<meta-data android:name="google_analytics_default_allow_analytics_storage" android:value="true" />
|
<meta-data android:name="com.flexionmobile.fdk.sdk-type" android:value="unity" />
|
||||||
<meta-data android:name="google_analytics_default_allow_ad_storage" android:value="true" />
|
<!--
|
||||||
<meta-data android:name="google_analytics_default_allow_ad_user_data" android:value="true" />
|
覆盖 tuyoosdk AAR 中硬编码的 Facebook ContentProvider authority。
|
||||||
<meta-data android:name="google_analytics_default_allow_ad_personalization_signals" android:value="true" />
|
AAR 原值:com.facebook.app.FacebookContentProvider162066986963808
|
||||||
|
追加 ${applicationId}(Flexion 包名)作为后缀后,与 GP 版 authority 不同,
|
||||||
</activity>
|
两个渠道包可同时安装在同一设备上,不会触发 INSTALL_FAILED_CONFLICTING_PROVIDER。
|
||||||
<meta-data android:name="CHANNEL" android:value="GooglePlay" />
|
参考:Flexion 官方文档《Unique package name - follow-on requirements》
|
||||||
</application>
|
|
||||||
<queries>
|
<provider
|
||||||
<provider android:authorities="com.facebook.katana.provider.PlatformProvider" /> <!-- allows app to access Facebook app features -->
|
android:name="com.facebook.FacebookContentProvider"
|
||||||
<provider android:authorities="com.facebook.orca.provider.PlatformProvider" /> <!-- allows sharing to Messenger app -->
|
android:authorities="com.facebook.app.FacebookContentProvider162066986963808.${applicationId}"
|
||||||
<intent>
|
android:exported="true"
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
tools:replace="android:authorities" />
|
||||||
</intent>
|
-->
|
||||||
</queries>
|
</application>
|
||||||
</manifest>
|
<queries>
|
||||||
|
<provider android:authorities="com.facebook.katana.provider.PlatformProvider" />
|
||||||
|
<provider android:authorities="com.facebook.orca.provider.PlatformProvider" />
|
||||||
|
</queries>
|
||||||
|
</manifest>
|
||||||
@@ -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.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.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
|
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.
|
implementation 'com.appsflyer:purchase-connector:2.2.0' // Assets/AppsFlyer/Editor/AppsFlyerDependencies.xml:8
|
||||||
// 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:unity-wrapper:6.17.7' // Assets/AppsFlyer/Editor/AppsFlyerDependencies.xml:6
|
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
|
implementation 'com.google.android.ump:user-messaging-platform:2.1.0' // Assets/MaxSdk/AppLovin/Editor/Dependencies.xml:5
|
||||||
// Android Resolver Dependencies End
|
// Android Resolver Dependencies End
|
||||||
|
|||||||
@@ -1964,6 +1964,85 @@ MonoBehaviour:
|
|||||||
m_OnClick:
|
m_OnClick:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
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
|
--- !u!1 &816060983
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -4263,6 +4342,7 @@ RectTransform:
|
|||||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
|
- {fileID: 783615087}
|
||||||
- {fileID: 2070325009}
|
- {fileID: 2070325009}
|
||||||
- {fileID: 1044920373}
|
- {fileID: 1044920373}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
@@ -4968,6 +5048,7 @@ MonoBehaviour:
|
|||||||
_mfbShareLinkBtn: {fileID: 1240291501}
|
_mfbShareLinkBtn: {fileID: 1240291501}
|
||||||
_reviewBtn: {fileID: 678940591}
|
_reviewBtn: {fileID: 678940591}
|
||||||
_messageTxt: {fileID: 2070325010}
|
_messageTxt: {fileID: 2070325010}
|
||||||
|
_titleText: {fileID: 783615088}
|
||||||
--- !u!4 &1788702880
|
--- !u!4 &1788702880
|
||||||
Transform:
|
Transform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -5417,7 +5498,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 1}
|
m_AnchorMin: {x: 0.5, y: 1}
|
||||||
m_AnchorMax: {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_SizeDelta: {x: 800, y: 100}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!114 &2070325010
|
--- !u!114 &2070325010
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ public class SDKTest : MonoBehaviour
|
|||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private Text _messageTxt;
|
private Text _messageTxt;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private Text _titleText;
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
@@ -71,6 +74,7 @@ public class SDKTest : MonoBehaviour
|
|||||||
GContext.container.RegisterInstance<IConfig>(config);
|
GContext.container.RegisterInstance<IConfig>(config);
|
||||||
|
|
||||||
Debug.Log("SDKTest Start");
|
Debug.Log("SDKTest Start");
|
||||||
|
UpdateChannelTitle();
|
||||||
//===============================================================================
|
//===============================================================================
|
||||||
//====================== Test Server ===========================
|
//====================== Test Server ===========================
|
||||||
// UnityBridgeFunc.UnityResetServerUrl("https://128-hwsfsdk-sdk-test01.qijihdhk.com");
|
// 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");
|
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<string>("CHANNEL");
|
||||||
|
Debug.Log($"[SDKTest] Channel from Java: {channel}");
|
||||||
|
_titleText.text = $" {channel}";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int retryAttempt;
|
int retryAttempt;
|
||||||
|
|
||||||
public void InitializeRewardedAds()
|
public void InitializeRewardedAds()
|
||||||
@@ -161,6 +177,7 @@ public class SDKTest : MonoBehaviour
|
|||||||
_messageTxt.text = $"Login: {info.isSuccess}";
|
_messageTxt.text = $"Login: {info.isSuccess}";
|
||||||
if (info.isSuccess)
|
if (info.isSuccess)
|
||||||
{
|
{
|
||||||
|
_messageTxt.text += $" UserId:{info.userId}";
|
||||||
_messageTxt.text += $"\n{info.msg}";
|
_messageTxt.text += $"\n{info.msg}";
|
||||||
_messageTxt.text += $"\n{TYSdkFacade.TYAccountInfo.token}";
|
_messageTxt.text += $"\n{TYSdkFacade.TYAccountInfo.token}";
|
||||||
}
|
}
|
||||||
@@ -187,10 +204,23 @@ public class SDKTest : MonoBehaviour
|
|||||||
public async void OnPayTestBtn()
|
public async void OnPayTestBtn()
|
||||||
{
|
{
|
||||||
_messageTxt.text = "";
|
_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){
|
if (sku == null){
|
||||||
_messageTxt.text = "no product";
|
_messageTxt.text = "no product";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !UNITY_EDITOR && UNITY_IOS
|
#if !UNITY_EDITOR && UNITY_IOS
|
||||||
sku.productId = "comarkgameftpack0199";
|
sku.productId = "comarkgameftpack0199";
|
||||||
@@ -201,7 +231,7 @@ public class SDKTest : MonoBehaviour
|
|||||||
var purchaseInfo = new JObject();
|
var purchaseInfo = new JObject();
|
||||||
purchaseInfo["pfid"] = "TestPlayer";
|
purchaseInfo["pfid"] = "TestPlayer";
|
||||||
purchaseInfo["customData"] = "{\"test\":\"test\"}";
|
purchaseInfo["customData"] = "{\"test\":\"test\"}";
|
||||||
|
purchaseInfo["playerId"] = TYSdkFacade.TYAccountInfo.strUserId;
|
||||||
|
|
||||||
PaymentInfo payResult = await TYSdkFacade.Instance.Pay(sku, 1, sku.ProdPrice, purchaseInfo);
|
PaymentInfo payResult = await TYSdkFacade.Instance.Pay(sku, 1, sku.ProdPrice, purchaseInfo);
|
||||||
_messageTxt.text = "\n" + $"Success : {payResult.isSuccess}";
|
_messageTxt.text = "\n" + $"Success : {payResult.isSuccess}";
|
||||||
@@ -220,6 +250,7 @@ public class SDKTest : MonoBehaviour
|
|||||||
_messageTxt.text = "products count:::" + result.products.Count;
|
_messageTxt.text = "products count:::" + result.products.Count;
|
||||||
_messageTxt.text += "\n" + result.products[0].ToString();
|
_messageTxt.text += "\n" + result.products[0].ToString();
|
||||||
sku = result.products[0];
|
sku = result.products[0];
|
||||||
|
Debug.Log($"Sku -> {sku}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ public class ChannelHelpers {
|
|||||||
public static final String CHANNEL = "Flexion";
|
public static final String CHANNEL = "Flexion";
|
||||||
|
|
||||||
static void register() {
|
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) {
|
public static String normalizeSkuList(String msg) {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//public SDKExtBuilder;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
||||||
@@ -33,12 +34,18 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
private static boolean billingConnected = false;
|
private static boolean billingConnected = false;
|
||||||
|
|
||||||
private static final PurchasesUpdateListener purchasesListener = (billingResult, purchase) -> {
|
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 (billingResult.getResponseCode() == BillingResults.ResultCode.PURCHASE_SUCCESS_CODE) {
|
||||||
if (purchase != null) handlePurchase(purchase);
|
if (purchase != null) handlePurchase(purchase);
|
||||||
} else if (billingResult.getResponseCode() == BillingResults.ResultCode.PURCHASE_USER_CANCELLED_CODE) {
|
} 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 {
|
} 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
|
@Override
|
||||||
public void pay(Activity activity, String productId, String productName,
|
public void pay(Activity activity, String productId, String productName,
|
||||||
String productCount, String prodorderId, String appInfo) {
|
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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
activity.runOnUiThread(() ->
|
String developerPayload = "";
|
||||||
billingService.launchBillingFlow(activity,
|
try {
|
||||||
new BillingFlowParams(productId, "inapp", "")));
|
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
|
@Override
|
||||||
public void queryProducts() {
|
public void queryProducts() {
|
||||||
|
Log.i(TAG, "queryProducts called, billingConnected=" + billingConnected);
|
||||||
if (billingService == null || !billingConnected) {
|
if (billingService == null || !billingConnected) {
|
||||||
|
Log.w(TAG, "queryProducts: billing not ready");
|
||||||
sendExtensionError("billing_not_ready");
|
sendExtensionError("billing_not_ready");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -108,6 +132,7 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
SDKAPI.getIns().thirdExtend(jsonObject.toString(), new SDKCallBack.Extend() {
|
SDKAPI.getIns().thirdExtend(jsonObject.toString(), new SDKCallBack.Extend() {
|
||||||
@Override
|
@Override
|
||||||
public void callback(int code, String msg) {
|
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) {
|
if (code == SDKCallBack.Extend.EXTEND_CODE_SUCCESS && msg != null) {
|
||||||
try {
|
try {
|
||||||
JSONArray products = new JSONArray(msg);
|
JSONArray products = new JSONArray(msg);
|
||||||
@@ -117,6 +142,7 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
String pid = p.optString("productId", "");
|
String pid = p.optString("productId", "");
|
||||||
if (!pid.isEmpty()) productIds.add(pid);
|
if (!pid.isEmpty()) productIds.add(pid);
|
||||||
}
|
}
|
||||||
|
Log.i(TAG, "queryProductDetails with " + productIds.size() + " items: " + productIds);
|
||||||
queryProductDetails(productIds);
|
queryProductDetails(productIds);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
sendExtensionError("parse_error: " + e.getMessage());
|
sendExtensionError("parse_error: " + e.getMessage());
|
||||||
@@ -131,10 +157,12 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
// ---- Billing Infrastructure ----
|
// ---- Billing Infrastructure ----
|
||||||
|
|
||||||
private static void initBillingService(Activity activity) {
|
private static void initBillingService(Activity activity) {
|
||||||
|
Log.i(TAG, "[PAY-FLOW] initBillingService");
|
||||||
billingService = FLX.createBillingService(activity, purchasesListener);
|
billingService = FLX.createBillingService(activity, purchasesListener);
|
||||||
billingService.startConnection(activity, new ConnectionStateListener() {
|
billingService.startConnection(activity, new ConnectionStateListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onBillingSetupFinished(BillingResult result) {
|
public void onBillingSetupFinished(BillingResult result) {
|
||||||
|
Log.i(TAG, "[PAY-FLOW] onBillingSetupFinished: code=" + result.getResponseCode());
|
||||||
if (result.getResponseCode() == BillingResults.ResultCode.CONNECTION_SUCCESS_CODE) {
|
if (result.getResponseCode() == BillingResults.ResultCode.CONNECTION_SUCCESS_CODE) {
|
||||||
billingConnected = true;
|
billingConnected = true;
|
||||||
queryPendingPurchases();
|
queryPendingPurchases();
|
||||||
@@ -142,20 +170,22 @@ public class FlexionSDKHelper implements SDKManager.ISDKHelper {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onBillingServiceDisconnected() {
|
public void onBillingServiceDisconnected() {
|
||||||
|
Log.w(TAG, "[PAY-FLOW] billing service disconnected");
|
||||||
billingConnected = false;
|
billingConnected = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handlePurchase(Purchase purchase) {
|
private static void handlePurchase(Purchase purchase) {
|
||||||
|
Log.i(TAG, "[PAY-FLOW] handlePurchase: state=" + purchase.getPurchaseState()
|
||||||
|
+ " token=" + purchase.getToken());
|
||||||
if (purchase.getPurchaseState() == 0) {
|
if (purchase.getPurchaseState() == 0) {
|
||||||
sendPayCallback(0, "success", purchase.getPurchaseJson(), purchase.getSignature());
|
Log.i(TAG, "[PAY-FLOW] purchaseJson=" + purchase.getPurchaseJson());
|
||||||
billingService.consumeAsync(
|
Log.i(TAG, "[PAY-FLOW] signature=" + purchase.getSignature());
|
||||||
new ConsumeParams(purchase.getToken()),
|
sendPayCallback(0, "success", purchase.getPurchaseJson(), purchase.getSignature(), purchase.getToken());
|
||||||
r -> Log.i(TAG, "Consume " +
|
|
||||||
(r.getResponseCode() == BillingResults.ResultCode.CONSUME_SUCCESS_CODE ? "ok" : "fail")));
|
|
||||||
} else if (purchase.getPurchaseState() == 2) {
|
} 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 ----
|
// ---- 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 {
|
try {
|
||||||
JSONObject result = new JSONObject();
|
JSONObject result = new JSONObject();
|
||||||
result.put("code", code);
|
result.put("code", code);
|
||||||
result.put("errStr", errStr != null ? errStr : "");
|
result.put("errStr", errStr != null ? errStr : "");
|
||||||
if (purchaseJson != null) result.put("purchaseJson", purchaseJson);
|
if (purchaseJson != null) result.put("purchaseJson", purchaseJson);
|
||||||
if (signature != null) result.put("signature", signature);
|
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,
|
UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME,
|
||||||
ConfigManager.PAY_CALLBACK_FUNCTION_NAME, result.toString());
|
ConfigManager.PAY_CALLBACK_FUNCTION_NAME, result.toString());
|
||||||
} catch (JSONException e) {
|
} 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) {
|
private static void sendExtensionError(String errStr) {
|
||||||
try {
|
try {
|
||||||
JSONObject result = new JSONObject();
|
JSONObject result = new JSONObject();
|
||||||
|
|||||||
@@ -57,19 +57,26 @@ public class SDKManager {
|
|||||||
private static SnsInfo tmpSnsInfo;
|
private static SnsInfo tmpSnsInfo;
|
||||||
private static String channel = "GooglePlay";
|
private static String channel = "GooglePlay";
|
||||||
|
|
||||||
// Channel helper registry
|
// Channel helper
|
||||||
public interface ISDKHelper {
|
public interface ISDKHelper {
|
||||||
void init(Activity activity);
|
void init(Activity activity);
|
||||||
void pay(Activity activity, String productId, String productName,
|
void pay(Activity activity, String productId, String productName,
|
||||||
String productCount, String prodorderId, String appInfo);
|
String productCount, String prodorderId, String appInfo);
|
||||||
void queryProducts();
|
void queryProducts();
|
||||||
|
void consume(String token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final java.util.Map<String, ISDKHelper> helperMap = new java.util.HashMap<>();
|
|
||||||
private static ISDKHelper sdkHelper;
|
private static ISDKHelper sdkHelper;
|
||||||
|
|
||||||
public static void registerHelper(String ch, ISDKHelper helper) {
|
public static void registerHelper(ISDKHelper helper) {
|
||||||
helperMap.put(ch, 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) {
|
public static void InitSDK(Activity activity, String ch) {
|
||||||
channel = ChannelHelpers.CHANNEL;
|
channel = ChannelHelpers.CHANNEL;
|
||||||
ChannelHelpers.register();
|
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
|
Log.i(TAG, "[CHANNEL-VERIFY] Java InitSDK channel=" + channel
|
||||||
+ " fromCSharp=" + ch
|
+ " fromCSharp=" + ch
|
||||||
+ " helper=" + (sdkHelper != null ? sdkHelper.getClass().getSimpleName() : "default"));
|
+ " helper=" + (sdkHelper != null ? sdkHelper.getClass().getSimpleName() : "default"));
|
||||||
@@ -87,7 +103,8 @@ public class SDKManager {
|
|||||||
// Sync channel to C# ChannelConfig
|
// Sync channel to C# ChannelConfig
|
||||||
UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME,
|
UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME,
|
||||||
"SetChannelFromNative", channel);
|
"SetChannelFromNative", channel);
|
||||||
|
|
||||||
|
// build.init(activity)
|
||||||
if (sdkHelper != null) {
|
if (sdkHelper != null) {
|
||||||
sdkHelper.init(activity);
|
sdkHelper.init(activity);
|
||||||
} else {
|
} else {
|
||||||
@@ -402,6 +419,7 @@ public class SDKManager {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
public static void thirdExtend() {
|
public static void thirdExtend() {
|
||||||
|
Log.e(TAG, "thirdExtend called, sdkHelper=" + (sdkHelper != null ? sdkHelper.getClass().getSimpleName() : "null"));
|
||||||
if (sdkHelper != null) {
|
if (sdkHelper != null) {
|
||||||
sdkHelper.queryProducts();
|
sdkHelper.queryProducts();
|
||||||
return;
|
return;
|
||||||
|
|||||||
Binary file not shown.
@@ -30,6 +30,7 @@ namespace tysdk
|
|||||||
|
|
||||||
if (purchaseInfo == null)
|
if (purchaseInfo == null)
|
||||||
purchaseInfo = new JObject();
|
purchaseInfo = new JObject();
|
||||||
|
// purchaseInfo["playerId"] = _accountInfo.strUserId;
|
||||||
|
|
||||||
string extraInfo = purchaseInfo.ToString(Newtonsoft.Json.Formatting.None);
|
string extraInfo = purchaseInfo.ToString(Newtonsoft.Json.Formatting.None);
|
||||||
extraInfo = Convert.ToBase64String(Encoding.UTF8.GetBytes(extraInfo));
|
extraInfo = Convert.ToBase64String(Encoding.UTF8.GetBytes(extraInfo));
|
||||||
@@ -56,18 +57,16 @@ namespace tysdk
|
|||||||
#elif UNITY_ANDROID
|
#elif UNITY_ANDROID
|
||||||
|
|
||||||
var pType = ChannelConfig.PayType;
|
var pType = ChannelConfig.PayType;
|
||||||
|
var task = TYSDKCallbackManager.Instance.RegisterCallback<PaymentInfo>(TimeSpan.FromSeconds(90));
|
||||||
var task = TYSDKCallbackManager.Instance.RegisterCallback<PaymentInfo>(TimeSpan.FromSeconds(30));
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UnityBridgeFunc.UnityKnowNew(prodId, prodPrice, prodName, count.ToString(), orderId, extraInfo, pType);
|
UnityBridgeFunc.UnityKnowNew(prodId, prodPrice, prodName, count.ToString(), orderId, extraInfo, pType);
|
||||||
|
|
||||||
var result = await task;
|
var result = await task;
|
||||||
result.count = count;
|
result.count = count;
|
||||||
result.orderId = orderId;
|
result.orderId = orderId;
|
||||||
result.productId = prodId;
|
result.productId = prodId;
|
||||||
result.price = prodPrice;
|
result.price = prodPrice;
|
||||||
|
result.Check(orderId, prodId);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -112,6 +111,9 @@ namespace tysdk
|
|||||||
var result = new PaymentInfo();
|
var result = new PaymentInfo();
|
||||||
result.code = jresult["code"].ToString();
|
result.code = jresult["code"].ToString();
|
||||||
result.msg = jresult["errStr"].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 (result.code == "-1")
|
||||||
{
|
{
|
||||||
if (!_payFirstNegativeHandled)
|
if (!_payFirstNegativeHandled)
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ namespace tysdk
|
|||||||
public string purchaseJson;
|
public string purchaseJson;
|
||||||
// Flexion: purchase.getSignature(), used by server for RSA signature verification
|
// Flexion: purchase.getSignature(), used by server for RSA signature verification
|
||||||
public string signature;
|
public string signature;
|
||||||
|
// Flexion: purchase token, used to consume after server verification
|
||||||
|
public string purchaseToken;
|
||||||
|
|
||||||
public bool Check(string orderId, string productId)
|
public bool Check(string orderId, string productId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
public static void UnityKnow(String productId, String productName, String productCount, String prodorderId, String appInfo)
|
||||||
{
|
{
|
||||||
using (var sdkManager = new AndroidJavaClass(SDK_CLASS))
|
using (var sdkManager = new AndroidJavaClass(SDK_CLASS))
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ PlayerSettings:
|
|||||||
androidSupportedAspectRatio: 1
|
androidSupportedAspectRatio: 1
|
||||||
androidMaxAspectRatio: 2.1
|
androidMaxAspectRatio: 2.1
|
||||||
applicationIdentifier:
|
applicationIdentifier:
|
||||||
Android: com.arkgame.ft
|
Android: com.arkgame.ft.flexion
|
||||||
Standalone: com.Unity-Technologies.com.unity.template.urp-blank
|
Standalone: com.Unity-Technologies.com.unity.template.urp-blank
|
||||||
iPhone: com.arkgame.ft
|
iPhone: com.arkgame.ft
|
||||||
buildNumber:
|
buildNumber:
|
||||||
|
|||||||
Reference in New Issue
Block a user