Compare commits
2 Commits
dc622282f2
...
dev_flexio
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d3eae1c88 | |||
| f06074d9cc |
@@ -54,13 +54,13 @@
|
||||
追加 ${applicationId}(Flexion 包名)作为后缀后,与 GP 版 authority 不同,
|
||||
两个渠道包可同时安装在同一设备上,不会触发 INSTALL_FAILED_CONFLICTING_PROVIDER。
|
||||
参考:Flexion 官方文档《Unique package name - follow-on requirements》
|
||||
|
||||
-->
|
||||
<provider
|
||||
android:name="com.facebook.FacebookContentProvider"
|
||||
android:authorities="com.facebook.app.FacebookContentProvider162066986963808.${applicationId}"
|
||||
android:exported="true"
|
||||
tools:replace="android:authorities" />
|
||||
-->
|
||||
|
||||
</application>
|
||||
<queries>
|
||||
<provider android:authorities="com.facebook.katana.provider.PlatformProvider" />
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.unity3d.player;
|
||||
|
||||
public class ChannelEntry {
|
||||
|
||||
|
||||
public static final String CHANNEL = "Flexion";
|
||||
|
||||
public static SDKManager.IChannelSDKAdapter createSDKAdapter() {
|
||||
return new FlexionSDKService();
|
||||
return new FlexionSDKAdapter();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ public class ChannelEntry {
|
||||
public static String normalizeSkuList(String msg) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//public SDKExtBuilder;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.unity3d.player;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.flexionmobile.ddpx.listener.ConnectionStateListener;
|
||||
@@ -30,17 +32,38 @@ import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class FlexionSDKService implements
|
||||
public class FlexionSDKAdapter implements
|
||||
SDKManager.IChannelSDKAdapter,
|
||||
SDKManager.IPaymentAdapter,
|
||||
SDKManager.IProductQueryAdapter,
|
||||
SDKManager.IPendingPurchaseAdapter {
|
||||
private static final String TAG = "FlexionSDKService";
|
||||
SDKManager.IPendingPurchaseAdapter,
|
||||
SDKManager.IBillingLifecycleAdapter {
|
||||
private static final String TAG = "FlexionSDKAdapter";
|
||||
private static BillingService billingService;
|
||||
private static boolean billingConnected = false;
|
||||
private static boolean billingConnecting = false;
|
||||
private static Activity billingActivity;
|
||||
private static final Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
private static final List<String> pendingPurchases = new ArrayList<>();
|
||||
private static final List<PendingBillingOperation> pendingBillingOperations = new ArrayList<>();
|
||||
private static final ExecutorService billingExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, "FlexionBillingThread"));
|
||||
|
||||
private interface BillingReadyOperation {
|
||||
void run(BillingService service);
|
||||
}
|
||||
|
||||
private static class PendingBillingOperation {
|
||||
final String operation;
|
||||
final BillingReadyOperation onReady;
|
||||
final Runnable onFail;
|
||||
|
||||
PendingBillingOperation(String operation, BillingReadyOperation onReady, Runnable onFail) {
|
||||
this.operation = operation;
|
||||
this.onReady = onReady;
|
||||
this.onFail = onFail;
|
||||
}
|
||||
}
|
||||
|
||||
private static final PurchasesUpdateListener purchasesListener = (billingResult, purchase) -> {
|
||||
Log.w(TAG, "[PAY-FLOW] PurchasesUpdateListener: code=" + billingResult.getResponseCode()
|
||||
+ " hasPurchase=" + (purchase != null));
|
||||
@@ -100,12 +123,7 @@ public class FlexionSDKService implements
|
||||
public void pay(Activity activity, String productId, String productPrice,
|
||||
String productName, String productCount, String prodorderId,
|
||||
String appInfo) {
|
||||
Log.i(TAG, "[PAY-FLOW] pay called: productId=" + productId + " billingReady=" + billingConnected);
|
||||
if (billingService == null || !billingConnected || !billingService.isReady()) {
|
||||
Log.e(TAG, "[PAY-FLOW] billing not ready");
|
||||
sendPayCallback(1, "billing_not_ready", null, null, null, null);
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "[PAY-FLOW] pay called: productId=" + productId + " billingConnected=" + billingConnected);
|
||||
String developerPayload = "";
|
||||
try {
|
||||
byte[] decoded = Base64.getDecoder().decode(appInfo);
|
||||
@@ -127,31 +145,32 @@ public class FlexionSDKService implements
|
||||
Log.w(TAG, "Failed to extract payload fields from appInfo: " + e.getMessage());
|
||||
}
|
||||
String finalPayload = developerPayload;
|
||||
billingExecutor.execute(() -> {
|
||||
try {
|
||||
BillingService bs = billingService;
|
||||
if (bs == null || !bs.isReady()) {
|
||||
Log.e(TAG, "[PAY-FLOW] billingService became null or not ready");
|
||||
sendPayCallback(1, "billing_not_ready", null, null, null, null);
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "[PAY-FLOW] launching billing flow for: " + productId + " payload=" + finalPayload);
|
||||
BillingResult result = bs.launchBillingFlow(activity,
|
||||
new BillingFlowParams(productId, "inapp", finalPayload));
|
||||
Log.i(TAG, "[PAY-FLOW] launchBillingFlow result: code=" + result.getResponseCode()
|
||||
+ " debugMsg=" + result.getDebugMessage());
|
||||
if (result.getResponseCode() != 2000) {
|
||||
Log.e(TAG, "[PAY-FLOW] launchBillingFlow error: code=" + result.getResponseCode()
|
||||
+ " debugMsg=" + result.getDebugMessage());
|
||||
sendPayCallback(1, "billing_flow_error_" + result.getResponseCode()
|
||||
+ "_" + result.getDebugMessage(), null, null, null, null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "[PAY-FLOW] launchBillingFlow exception: " + e.getClass().getName()
|
||||
+ " msg=" + e.getMessage());
|
||||
sendPayCallback(1, "launch_billing_failed: " + e.getMessage(), null, null, null, null);
|
||||
}
|
||||
});
|
||||
ensureBillingReady(activity, "pay", bs ->
|
||||
billingExecutor.execute(() -> {
|
||||
try {
|
||||
if (bs == null || !bs.isReady()) {
|
||||
Log.e(TAG, "[PAY-FLOW] billingService became null or not ready");
|
||||
sendPayCallback(1, "billing_not_ready", null, null, null, null);
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "[PAY-FLOW] launching billing flow for: " + productId + " payload=" + finalPayload);
|
||||
BillingResult result = bs.launchBillingFlow(activity,
|
||||
new BillingFlowParams(productId, "inapp", finalPayload));
|
||||
Log.i(TAG, "[PAY-FLOW] launchBillingFlow result: code=" + result.getResponseCode()
|
||||
+ " debugMsg=" + result.getDebugMessage());
|
||||
if (result.getResponseCode() != 2000) {
|
||||
Log.e(TAG, "[PAY-FLOW] launchBillingFlow error: code=" + result.getResponseCode()
|
||||
+ " debugMsg=" + result.getDebugMessage());
|
||||
sendPayCallback(1, "billing_flow_error_" + result.getResponseCode()
|
||||
+ "_" + result.getDebugMessage(), null, null, null, null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "[PAY-FLOW] launchBillingFlow exception: " + e.getClass().getName()
|
||||
+ " msg=" + e.getMessage());
|
||||
sendPayCallback(1, "launch_billing_failed: " + e.getMessage(), null, null, null, null);
|
||||
}
|
||||
}),
|
||||
() -> sendPayCallback(1, "billing_not_ready", null, null, null, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,36 +181,119 @@ public class FlexionSDKService implements
|
||||
@Override
|
||||
public void queryProducts(String productIds) {
|
||||
Log.i(TAG, "queryProducts(productIds) called, billingConnected=" + billingConnected);
|
||||
if (billingService == null || !billingConnected) {
|
||||
sendExtensionError("billing_not_ready");
|
||||
return;
|
||||
}
|
||||
List<String> ids = Arrays.asList(productIds.split(","));
|
||||
Log.i(TAG, "queryProductDetails with " + ids.size() + " items from config");
|
||||
queryProductDetails(ids);
|
||||
ensureBillingReady(null, "queryProducts",
|
||||
bs -> queryProductDetails(bs, ids),
|
||||
() -> sendExtensionError("billing_not_ready"));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
ensureBillingReady(activity, "initBillingService",
|
||||
bs -> queryPendingPurchases(),
|
||||
() -> Log.w(TAG, "[PAY-FLOW] initBillingService failed: billing not ready"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingServiceDisconnected() {
|
||||
Log.w(TAG, "[PAY-FLOW] billing service disconnected");
|
||||
private static void ensureBillingReady(Activity activity, String operation,
|
||||
BillingReadyOperation onReady, Runnable onFail) {
|
||||
ensureBillingReady(activity, operation, onReady, onFail, false);
|
||||
}
|
||||
|
||||
private static void ensureBillingReady(Activity activity, String operation,
|
||||
BillingReadyOperation onReady, Runnable onFail,
|
||||
boolean forceReconnect) {
|
||||
if (activity != null) {
|
||||
billingActivity = activity;
|
||||
}
|
||||
Activity targetActivity = activity != null ? activity : billingActivity;
|
||||
if (targetActivity == null) {
|
||||
Log.e(TAG, "[PAY-FLOW] ensureBillingReady failed: activity is null operation=" + operation);
|
||||
if (onFail != null) onFail.run();
|
||||
return;
|
||||
}
|
||||
|
||||
targetActivity.runOnUiThread(() -> {
|
||||
try {
|
||||
if (billingService == null) {
|
||||
Log.i(TAG, "[PAY-FLOW] create BillingService operation=" + operation);
|
||||
billingService = FLX.createBillingService(targetActivity, purchasesListener);
|
||||
}
|
||||
|
||||
boolean ready = billingService != null && billingService.isReady();
|
||||
Log.i(TAG, "[PAY-FLOW] ensureBillingReady operation=" + operation
|
||||
+ " connected=" + billingConnected
|
||||
+ " ready=" + ready
|
||||
+ " connecting=" + billingConnecting
|
||||
+ " forceReconnect=" + forceReconnect);
|
||||
|
||||
if (ready && !forceReconnect) {
|
||||
billingConnected = true;
|
||||
if (onReady != null) onReady.run(billingService);
|
||||
return;
|
||||
}
|
||||
|
||||
pendingBillingOperations.add(new PendingBillingOperation(operation, onReady, onFail));
|
||||
if (billingConnecting) {
|
||||
Log.i(TAG, "[PAY-FLOW] billing connection already in progress, queued operation=" + operation);
|
||||
return;
|
||||
}
|
||||
|
||||
billingConnecting = true;
|
||||
Log.i(TAG, "[PAY-FLOW] billing reconnect start operation=" + operation);
|
||||
billingService.startConnection(targetActivity, new ConnectionStateListener() {
|
||||
@Override
|
||||
public void onBillingSetupFinished(BillingResult result) {
|
||||
int code = result.getResponseCode();
|
||||
Log.i(TAG, "[PAY-FLOW] onBillingSetupFinished: code=" + code);
|
||||
billingConnecting = false;
|
||||
billingConnected = code == BillingResults.ResultCode.CONNECTION_SUCCESS_CODE;
|
||||
drainBillingOperations(billingConnected);
|
||||
if (billingConnected) {
|
||||
queryPendingPurchases();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingServiceDisconnected() {
|
||||
Log.w(TAG, "[PAY-FLOW] billing service disconnected");
|
||||
billingConnected = false;
|
||||
}
|
||||
});
|
||||
mainHandler.postDelayed(() -> {
|
||||
if (!billingConnecting) return;
|
||||
boolean timeoutReady = billingService != null && billingService.isReady();
|
||||
Log.w(TAG, "[PAY-FLOW] billing reconnect timeout operation=" + operation
|
||||
+ " ready=" + timeoutReady);
|
||||
billingConnecting = false;
|
||||
billingConnected = timeoutReady;
|
||||
drainBillingOperations(timeoutReady);
|
||||
}, 10000);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "[PAY-FLOW] ensureBillingReady exception operation=" + operation
|
||||
+ " msg=" + e.getMessage());
|
||||
billingConnecting = false;
|
||||
billingConnected = false;
|
||||
drainBillingOperations(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void drainBillingOperations(boolean success) {
|
||||
List<PendingBillingOperation> operations = new ArrayList<>(pendingBillingOperations);
|
||||
pendingBillingOperations.clear();
|
||||
Log.i(TAG, "[PAY-FLOW] drainBillingOperations success=" + success
|
||||
+ " count=" + operations.size());
|
||||
for (PendingBillingOperation operation : operations) {
|
||||
if (success) {
|
||||
if (operation.onReady != null) operation.onReady.run(billingService);
|
||||
} else {
|
||||
Log.w(TAG, "[PAY-FLOW] billing operation failed operation=" + operation.operation);
|
||||
if (operation.onFail != null) operation.onFail.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void handlePurchase(Purchase purchase) {
|
||||
Log.i(TAG, "[PAY-FLOW] handlePurchase: state=" + purchase.getPurchaseState()
|
||||
+ " orderId=" + purchase.getOrderId()
|
||||
@@ -208,17 +310,15 @@ public class FlexionSDKService implements
|
||||
private static void queryPendingPurchases() {
|
||||
Log.i(TAG, "[PAY-FLOW] queryPendingPurchases start: billingService=" + billingService
|
||||
+ " billingConnected=" + billingConnected);
|
||||
if (billingService == null || !billingConnected) {
|
||||
Log.w(TAG, "[PAY-FLOW] queryPendingPurchases skipped: billing not connected");
|
||||
return;
|
||||
}
|
||||
billingService.queryPurchasesAsync(
|
||||
new QueryPurchasesParams("inapp"),
|
||||
(result, purchases) -> {
|
||||
Log.i(TAG, "[PAY-FLOW] queryPendingPurchases result: code=" + result.getResponseCode()
|
||||
+ " count=" + (purchases == null ? 0 : purchases.size()));
|
||||
if (purchases != null) for (Purchase p : purchases) cachePendingPurchase(p);
|
||||
});
|
||||
ensureBillingReady(null, "queryPendingPurchases",
|
||||
bs -> bs.queryPurchasesAsync(
|
||||
new QueryPurchasesParams("inapp"),
|
||||
(result, purchases) -> {
|
||||
Log.i(TAG, "[PAY-FLOW] queryPendingPurchases result: code=" + result.getResponseCode()
|
||||
+ " count=" + (purchases == null ? 0 : purchases.size()));
|
||||
if (purchases != null) for (Purchase p : purchases) cachePendingPurchase(p);
|
||||
}),
|
||||
() -> Log.w(TAG, "[PAY-FLOW] queryPendingPurchases skipped: billing not connected"));
|
||||
}
|
||||
|
||||
private static void cachePendingPurchase(Purchase purchase) {
|
||||
@@ -272,10 +372,33 @@ public class FlexionSDKService implements
|
||||
}
|
||||
}
|
||||
|
||||
private static void queryProductDetails(List<String> productIds) {
|
||||
billingService.queryProductDetailsAsync(
|
||||
@Override
|
||||
public void refreshBilling() {
|
||||
Log.i(TAG, "[PAY-FLOW] refreshBilling requested");
|
||||
billingConnected = false;
|
||||
ensureBillingReady(null, "refreshBilling",
|
||||
bs -> Log.i(TAG, "[PAY-FLOW] refreshBilling ready"),
|
||||
() -> Log.w(TAG, "[PAY-FLOW] refreshBilling failed"),
|
||||
true);
|
||||
}
|
||||
|
||||
private static void queryProductDetails(BillingService service, List<String> productIds) {
|
||||
final boolean[] completed = {false};
|
||||
mainHandler.postDelayed(() -> {
|
||||
if (completed[0]) return;
|
||||
completed[0] = true;
|
||||
Log.w(TAG, "[PAY-FLOW] queryProductDetails timeout count=" + productIds.size());
|
||||
sendExtensionError("flexion_query_timeout");
|
||||
}, 30000);
|
||||
|
||||
service.queryProductDetailsAsync(
|
||||
new ProductDetailsParams("inapp", productIds),
|
||||
(billingResult, productDetails) -> {
|
||||
if (completed[0]) {
|
||||
Log.w(TAG, "[PAY-FLOW] queryProductDetails callback ignored after timeout");
|
||||
return;
|
||||
}
|
||||
completed[0] = true;
|
||||
try {
|
||||
JSONObject result = new JSONObject();
|
||||
if (billingResult.getResponseCode() == BillingResults.ResultCode.QUERY_PRODUCT_DETAILS_SUCCESS_CODE
|
||||
@@ -338,15 +461,17 @@ public class FlexionSDKService implements
|
||||
}
|
||||
|
||||
public static void consumePurchase(String token) {
|
||||
if (billingService == null || token == null || token.isEmpty()) {
|
||||
Log.w(TAG, "[PAY-FLOW] consumePurchase: billingService or token is null");
|
||||
if (token == null || token.isEmpty()) {
|
||||
Log.w(TAG, "[PAY-FLOW] consumePurchase: 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")));
|
||||
ensureBillingReady(null, "consumePurchase",
|
||||
bs -> bs.consumeAsync(
|
||||
new ConsumeParams(token),
|
||||
r -> Log.i(TAG, "[PAY-FLOW] consume result: " +
|
||||
(r.getResponseCode() == BillingResults.ResultCode.CONSUME_SUCCESS_CODE ? "ok" : "fail"))),
|
||||
() -> Log.w(TAG, "[PAY-FLOW] consumePurchase skipped: billing not connected"));
|
||||
}
|
||||
|
||||
public static void cancelPurchase() {
|
||||
Binary file not shown.
@@ -34,7 +34,7 @@ dependencies {
|
||||
// Google Play In-App Review
|
||||
implementation 'com.google.android.play:review:2.0.1'
|
||||
// Google Play Billing — tuyoosdk AAR references BillingManager during init
|
||||
implementation 'com.android.billingclient:billing:6.0.1'
|
||||
implementation 'com.android.billingclient:billing:7.0.0'
|
||||
implementation 'net.aihelp:android-aihelp-aar:5.3.+'
|
||||
|
||||
implementation 'com.google.android.gms:play-services-auth:20.2.0'
|
||||
@@ -52,7 +52,7 @@ dependencies {
|
||||
|
||||
implementation 'com.miui.referrer:homereferrer:1.0.0.6'
|
||||
|
||||
implementation platform('com.google.firebase:firebase-bom:32.7.4')
|
||||
implementation platform('com.google.firebase:firebase-bom:34.6.0')
|
||||
implementation 'com.google.firebase:firebase-analytics'
|
||||
|
||||
implementation('com.facebook.android:facebook-android-sdk:16.2.0')
|
||||
@@ -78,6 +78,7 @@ dependencies {
|
||||
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
|
||||
implementation 'com.tapjoy:tapjoy-android-unitybridge:14.5.0' // Packages/com.unity.package-offerwall/Editor/TJPluginDependencies.xml:10
|
||||
// Android Resolver Dependencies End
|
||||
**DEPS**}
|
||||
|
||||
|
||||
@@ -28,7 +28,10 @@ dependencyResolutionManagement {
|
||||
}
|
||||
|
||||
// Android Resolver Repos Start
|
||||
def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/")
|
||||
def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/")
|
||||
maven {
|
||||
url "https://sdk.tapjoy.com/" // Packages/com.unity.package-offerwall/Editor/TJPluginDependencies.xml:9
|
||||
}
|
||||
maven {
|
||||
url "https://android-sdk.is.com/" // Assets/MaxSdk/Mediation/IronSource/Editor/Dependencies.xml:8
|
||||
}
|
||||
|
||||
@@ -55,31 +55,17 @@ public class BuildTool
|
||||
BuildiOS(bparams);
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Build Android")]
|
||||
public static void BuildAndroid()
|
||||
{
|
||||
|
||||
BuildParams bparams = new BuildParams()
|
||||
{
|
||||
outPath = "../Bin/tysdkTest.apk"
|
||||
};
|
||||
|
||||
BuildAndroid(bparams);
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Build Android With Debug")]
|
||||
public static void BuildAndroidWithDebug()
|
||||
{
|
||||
|
||||
BuildParams bparams = new BuildParams()
|
||||
{
|
||||
outPath = "../Bin/tysdkTest_debug.apk",
|
||||
};
|
||||
|
||||
var buildOptions = BuildOptions.Development | BuildOptions.AllowDebugging | BuildOptions.WaitForPlayerConnection;
|
||||
|
||||
BuildAndroid(bparams, buildOptions);
|
||||
}
|
||||
[MenuItem("Tools/Build Android")]
|
||||
public static void BuildAndroid()
|
||||
{
|
||||
ChannelBuildTool.Build_GooglePlay();
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Build Android With Debug")]
|
||||
public static void BuildAndroidWithDebug()
|
||||
{
|
||||
ChannelBuildTool.Build_GooglePlay_Debug();
|
||||
}
|
||||
|
||||
public static void CIBuildAndroid()
|
||||
{
|
||||
|
||||
@@ -7,6 +7,8 @@ public class ChannelBuildTool
|
||||
{
|
||||
public static readonly string[] SupportedChannels = { "GooglePlay", "Rustore", "Flexion" };
|
||||
|
||||
private const string DefaultChannel = "GooglePlay";
|
||||
private const string DefaultAndroidBundleIdentifier = "com.arkgame.ft";
|
||||
private const string ExtraCfgRoot = "../ExtraPluginCfgs/Android";
|
||||
private const string TysdkPlugins = "Packages/tysdk/Plugins/Android";
|
||||
private const string TysdkFiles = "Packages/tysdk/Files";
|
||||
@@ -61,6 +63,8 @@ public class ChannelBuildTool
|
||||
File.Delete(oldJava);
|
||||
foreach (var oldJava in Directory.GetFiles(TysdkPlugins, "*SDKService.java"))
|
||||
File.Delete(oldJava);
|
||||
foreach (var oldJava in Directory.GetFiles(TysdkPlugins, "*SDKAdapter.java"))
|
||||
File.Delete(oldJava);
|
||||
var oldConfig = Path.Combine(TysdkPlugins, "ConfigManager.java");
|
||||
if (File.Exists(oldConfig)) File.Delete(oldConfig);
|
||||
|
||||
@@ -111,35 +115,51 @@ public class ChannelBuildTool
|
||||
|
||||
// ==================== Build ====================
|
||||
|
||||
private static void RestoreDefaultChannel()
|
||||
{
|
||||
Debug.Log($"[ChannelBuild] Restore default channel -> {DefaultChannel}");
|
||||
SwitchChannel(DefaultChannel);
|
||||
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, DefaultAndroidBundleIdentifier);
|
||||
Debug.Log($"[ChannelBuild] Restore bundle identifier -> {DefaultAndroidBundleIdentifier}");
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
private static void BuildAndroidForChannel(string channel, bool debug)
|
||||
{
|
||||
SwitchChannel(channel);
|
||||
|
||||
string fileName = debug ? $"tysdkTest_{channel}_debug.apk" : $"tysdkTest_{channel}.apk";
|
||||
string outPath = $"../Bin/{fileName}";
|
||||
var buildOptions = debug
|
||||
? BuildOptions.Development | BuildOptions.AllowDebugging | BuildOptions.WaitForPlayerConnection
|
||||
: BuildOptions.None;
|
||||
|
||||
var buildPlayerOptions = new BuildPlayerOptions
|
||||
try
|
||||
{
|
||||
scenes = EditorBuildSettings.scenes.Select(x => x.path).ToArray(),
|
||||
locationPathName = outPath,
|
||||
target = BuildTarget.Android,
|
||||
options = buildOptions,
|
||||
};
|
||||
SwitchChannel(channel);
|
||||
|
||||
Debug.Log($"[ChannelBuild] Building {channel} → {outPath}");
|
||||
var buildReport = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
||||
string fileName = debug ? $"tysdkTest_{channel}_debug.apk" : $"tysdkTest_{channel}.apk";
|
||||
string outPath = $"../Bin/{fileName}";
|
||||
var buildOptions = debug
|
||||
? BuildOptions.Development | BuildOptions.AllowDebugging | BuildOptions.WaitForPlayerConnection
|
||||
: BuildOptions.None;
|
||||
|
||||
if (buildReport?.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded)
|
||||
{
|
||||
Debug.Log($"[ChannelBuild] Success: {Path.GetFullPath(outPath)}");
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
var buildPlayerOptions = new BuildPlayerOptions
|
||||
{
|
||||
scenes = EditorBuildSettings.scenes.Select(x => x.path).ToArray(),
|
||||
locationPathName = outPath,
|
||||
target = BuildTarget.Android,
|
||||
options = buildOptions,
|
||||
};
|
||||
|
||||
Debug.Log($"[ChannelBuild] Building {channel} → {outPath}");
|
||||
var buildReport = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
||||
|
||||
if (buildReport?.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded)
|
||||
{
|
||||
Debug.Log($"[ChannelBuild] Success: {Path.GetFullPath(outPath)}");
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[ChannelBuild] Failed: {buildReport?.summary}");
|
||||
}
|
||||
}
|
||||
else
|
||||
finally
|
||||
{
|
||||
Debug.LogError($"[ChannelBuild] Failed: {buildReport?.summary}");
|
||||
RestoreDefaultChannel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,29 +177,7 @@ public class ChannelBuildTool
|
||||
public static void Switch_Flexion() => SwitchChannel("Flexion");
|
||||
|
||||
// ==================== Menu: Build ====================
|
||||
|
||||
[MenuItem("Tools/Build Android (Current Channel)")]
|
||||
public static void Build_CurrentChannel()
|
||||
{
|
||||
if (string.IsNullOrEmpty(currentChannel))
|
||||
{
|
||||
Debug.LogError("[ChannelBuild] No channel selected. Use Tools/Switch Channel first.");
|
||||
return;
|
||||
}
|
||||
BuildAndroidForChannel(currentChannel, false);
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Build Android (Current Channel) Debug")]
|
||||
public static void Build_CurrentChannel_Debug()
|
||||
{
|
||||
if (string.IsNullOrEmpty(currentChannel))
|
||||
{
|
||||
Debug.LogError("[ChannelBuild] No channel selected. Use Tools/Switch Channel first.");
|
||||
return;
|
||||
}
|
||||
BuildAndroidForChannel(currentChannel, true);
|
||||
}
|
||||
|
||||
|
||||
[MenuItem("Tools/Build Android (Channel)/GooglePlay")]
|
||||
public static void Build_GooglePlay() => BuildAndroidForChannel("GooglePlay", false);
|
||||
|
||||
|
||||
@@ -76,6 +76,10 @@ public class SDKManager {
|
||||
String getPendingPurchases();
|
||||
}
|
||||
|
||||
public interface IBillingLifecycleAdapter {
|
||||
void refreshBilling();
|
||||
}
|
||||
|
||||
private static IChannelSDKAdapter sdkAdapter;
|
||||
|
||||
public static void queryProductsByIDs(String productIds) {
|
||||
@@ -100,9 +104,16 @@ public class SDKManager {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
public static void RefreshBillingService() {
|
||||
Log.i(TAG, "RefreshBillingService");
|
||||
if (sdkAdapter instanceof IBillingLifecycleAdapter) {
|
||||
((IBillingLifecycleAdapter) sdkAdapter).refreshBilling();
|
||||
}
|
||||
}
|
||||
|
||||
public static void CancelBillingFlow() {
|
||||
Log.w(TAG, "CancelBillingFlow");
|
||||
// FlexionSDKService.cancelPurchase();
|
||||
// FlexionSDKAdapter.cancelPurchase();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -322,6 +322,9 @@ namespace tysdk
|
||||
result.isSuccess = true;
|
||||
result.userId = _accountInfo.userId;
|
||||
SetUserInfo();
|
||||
#if UNITY_ANDROID
|
||||
UnityBridgeFunc.RefreshBillingService();
|
||||
#endif
|
||||
}
|
||||
|
||||
TYSDKCallbackManager.Instance.TryTriggerCallback(result);
|
||||
@@ -414,6 +417,9 @@ namespace tysdk
|
||||
{
|
||||
_accountInfo.AddLinkedAccount(accoutType);
|
||||
_accountInfo.Save();
|
||||
#if UNITY_ANDROID
|
||||
UnityBridgeFunc.RefreshBillingService();
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -160,10 +160,18 @@ namespace tysdk
|
||||
var result = new ProductListInfo();
|
||||
return result;
|
||||
#elif UNITY_ANDROID || UNITY_IOS
|
||||
var task = TYSDKCallbackManager.Instance.RegisterCallback<ProductListInfo>();
|
||||
var task = TYSDKCallbackManager.Instance.RegisterCallback<ProductListInfo>(TimeSpan.FromSeconds(45));
|
||||
UnityBridgeFunc.GetSKUList();
|
||||
var result = await task;
|
||||
return result;
|
||||
try
|
||||
{
|
||||
var result = await task;
|
||||
return result;
|
||||
}
|
||||
catch (TaskCanceledException e)
|
||||
{
|
||||
Debug.LogWarning($"[TYSdkFacade] GetSKUList timeout: {e.Message}");
|
||||
return new ProductListInfo() { code = 1, msg = "sku_callback_timeout" };
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -176,10 +184,18 @@ namespace tysdk
|
||||
await Task.Yield();
|
||||
return new ProductListInfo();
|
||||
#elif UNITY_ANDROID
|
||||
var task = TYSDKCallbackManager.Instance.RegisterCallback<ProductListInfo>();
|
||||
var task = TYSDKCallbackManager.Instance.RegisterCallback<ProductListInfo>(TimeSpan.FromSeconds(45));
|
||||
UnityBridgeFunc.GetSKUListByIapIds(productIds);
|
||||
var result = await task;
|
||||
return result;
|
||||
try
|
||||
{
|
||||
var result = await task;
|
||||
return result;
|
||||
}
|
||||
catch (TaskCanceledException e)
|
||||
{
|
||||
Debug.LogWarning($"[TYSdkFacade] GetSKUListByIapIds timeout: {e.Message}");
|
||||
return new ProductListInfo() { code = 1, msg = "sku_callback_timeout" };
|
||||
}
|
||||
#else
|
||||
return new ProductListInfo() { code = -1, msg = "unsupported platform" };
|
||||
#endif
|
||||
|
||||
@@ -48,6 +48,8 @@ namespace tysdk
|
||||
|
||||
public static string GetPendingPurchases() => "[]";
|
||||
|
||||
public static void RefreshBillingService() { }
|
||||
|
||||
//打点
|
||||
public static void SetGaUserInfo(string userId){}
|
||||
public static void SetGaCommonInfo(string SetGaCommonInfo){}
|
||||
@@ -224,6 +226,15 @@ namespace tysdk
|
||||
}
|
||||
}
|
||||
|
||||
public static void RefreshBillingService()
|
||||
{
|
||||
UnityEngine.Debug.Log("UnityBridgeFunc.RefreshBillingService");
|
||||
using(var sdkManager = new AndroidJavaClass(SDK_CLASS))
|
||||
{
|
||||
sdkManager.CallStatic("RefreshBillingService");
|
||||
}
|
||||
}
|
||||
|
||||
public static void CancelBillingFlow()
|
||||
{
|
||||
UnityEngine.Debug.Log("UnityBridgeFunc.CancelBillingFlow");
|
||||
@@ -470,6 +481,8 @@ namespace tysdk
|
||||
|
||||
public static string GetPendingPurchases() => "[]";
|
||||
|
||||
public static void RefreshBillingService() { }
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user