package com.unity3d.player; import android.app.Activity; import android.util.Log; import com.flexionmobile.ddpx.listener.ConnectionStateListener; import com.flexionmobile.ddpx.listener.PurchasesUpdateListener; import com.flexionmobile.ddpx.model.BillingResult; import com.flexionmobile.ddpx.model.BillingResults; import com.flexionmobile.ddpx.model.Purchase; import com.flexionmobile.ddpx.model.ProductDetails; import com.flexionmobile.ddpx.model.params.BillingFlowParams; import com.flexionmobile.ddpx.model.params.ConsumeParams; import com.flexionmobile.ddpx.model.params.QueryPurchasesParams; import com.flexionmobile.ddpx.model.params.ProductDetailsParams; import com.flexionmobile.fdk.FLX; import com.tuyoo.gamesdk.api.SDKAPI; import com.tuyoo.gamesdk.api.SDKCallBack; import com.tuyoo.gamesdk.model.InitParam; import com.tuyoo.gamesdk.util.SDKLog; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.List; public class FlexionSDKHelper implements SDKManager.ISDKHelper { private static final String TAG = "FlexionSDKHelper"; private static BillingService billingService; private static boolean billingConnected = false; private static final PurchasesUpdateListener purchasesListener = (billingResult, purchase) -> { 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); } else { sendPayCallback(1, "purchase_failed_" + billingResult.getResponseCode(), null, null); } }; @Override public void init(Activity activity) { activity.runOnUiThread(() -> { SDKAPI.getIns().lightModeEnable(); try { SDKAPI.getIns().init(new InitParam.Builder() .withActivity(activity) .withAppId(ConfigManager.SDK_APPID) .withClientId(ConfigManager.SDK_CLIENTID) .withServerUrl(ConfigManager.SDK_LOGIN_SERVER_URL) .build()); SDKAPI.getIns().onActivityStart(activity); SDKAPI.getIns().onActivityResume(activity); } catch (Exception e) { Log.e(TAG, "TuYoo SDK init Exception: " + e); } FLX.init(activity, (initCode, initMsg) -> { Log.i(TAG, "FLX.init result=" + initCode); if (initCode == 0) { FLX.showFlexionScreens(activity, (screenCode, screenMsg) -> { Log.i(TAG, "FLX.showFlexionScreens result=" + screenCode); initBillingService(activity); TYUnityActivity.setSdkInited(); }); } else { Log.e(TAG, "FLX.init failed: " + initCode); TYUnityActivity.setSdkInited(); } }); }); } @Override public void pay(Activity activity, String productId, String productName, String productCount, String prodorderId, String appInfo) { Log.i(TAG, "pay: " + productId); if (billingService == null || !billingConnected) { sendPayCallback(1, "billing_not_ready", null, null); return; } activity.runOnUiThread(() -> billingService.launchBillingFlow(activity, new BillingFlowParams(productId, "inapp", ""))); } @Override public void queryProducts() { if (billingService == null || !billingConnected) { sendExtensionError("billing_not_ready"); return; } JSONObject jsonObject = new JSONObject(); try { jsonObject.put("action", "ACTION_GET_SKU_DETAILS_LIST"); } catch (JSONException e) { throw new RuntimeException(e); } SDKAPI.getIns().thirdExtend(jsonObject.toString(), new SDKCallBack.Extend() { @Override public void callback(int code, String msg) { if (code == SDKCallBack.Extend.EXTEND_CODE_SUCCESS && msg != null) { try { JSONArray products = new JSONArray(msg); List productIds = new java.util.ArrayList<>(); for (int i = 0; i < products.length(); i++) { JSONObject p = products.getJSONObject(i); String pid = p.optString("productId", ""); if (!pid.isEmpty()) productIds.add(pid); } queryProductDetails(productIds); } catch (JSONException e) { sendExtensionError("parse_error: " + e.getMessage()); } } else { sendExtensionError("tuyoo_query_failed: " + msg); } } }); } // ---- Billing Infrastructure ---- private static void initBillingService(Activity activity) { billingService = FLX.createBillingService(activity, purchasesListener); billingService.startConnection(activity, new ConnectionStateListener() { @Override public void onBillingSetupFinished(BillingResult result) { if (result.getResponseCode() == BillingResults.ResultCode.CONNECTION_SUCCESS_CODE) { billingConnected = true; queryPendingPurchases(); } } @Override public void onBillingServiceDisconnected() { billingConnected = false; } }); } private static void handlePurchase(Purchase purchase) { 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"))); } else if (purchase.getPurchaseState() == 2) { sendPayCallback(2, "pending", null, null); } } private static void queryPendingPurchases() { if (billingService == null || !billingConnected) return; billingService.queryPurchasesAsync( new QueryPurchasesParams("inapp"), (result, purchases) -> { if (purchases != null) for (Purchase p : purchases) handlePurchase(p); }); } private static void queryProductDetails(List productIds) { billingService.queryProductDetailsAsync( new ProductDetailsParams("inapp", productIds), (billingResult, productDetails) -> { try { JSONObject result = new JSONObject(); if (billingResult.getResponseCode() == BillingResults.ResultCode.QUERY_PRODUCT_DETAILS_SUCCESS_CODE && productDetails != null) { JSONArray arr = new JSONArray(); for (ProductDetails detail : productDetails) { JSONObject item = new JSONObject(); item.put("productId", detail.getId()); item.put("ourProductId", detail.getId()); item.put("title", detail.getTitle()); item.put("description", detail.getDescription()); item.put("price", detail.getPrice()); item.put("price_amount_micros", detail.getPriceAmountMicros()); item.put("price_currency_code", detail.getPriceCurrencyCode()); item.put("type", detail.getType()); arr.put(item); } result.put("code", 0); result.put("respObj", arr.toString()); } else { result.put("code", 1); result.put("thirdExtend_errStr", "flexion_query_failed: " + billingResult.getDebugMessage()); } UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME, ConfigManager.PAY_TYPE_CALLBACK_FUNCTION_NAME, result.toString()); } catch (JSONException e) { UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME, ConfigManager.PAY_TYPE_CALLBACK_FUNCTION_NAME, "{\"code\":1}"); } }); } // ---- Callbacks to Unity ---- private static void sendPayCallback(int code, String errStr, String purchaseJson, String signature) { 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); UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME, ConfigManager.PAY_CALLBACK_FUNCTION_NAME, result.toString()); } catch (JSONException e) { UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME, ConfigManager.PAY_CALLBACK_FUNCTION_NAME, "{\"code\":1,\"errStr\":\"json_error\"}"); } } private static void sendExtensionError(String errStr) { try { JSONObject result = new JSONObject(); result.put("code", 1); result.put("thirdExtend_errStr", errStr); UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME, ConfigManager.PAY_TYPE_CALLBACK_FUNCTION_NAME, result.toString()); } catch (JSONException e) { UnityPlayer.UnitySendMessage(ConfigManager.UNITY_FACADE_NAME, ConfigManager.PAY_TYPE_CALLBACK_FUNCTION_NAME, "{\"code\":1}"); } } }