Kaynağa Gözat

v1.0.0开发:
1)谷歌支付库降级为3.0.3
2)媒体SDK打点接入

#Suyghur 3 yıl önce
ebeveyn
işleme
ce7d7aa79d
31 değiştirilmiş dosya ile 1802 ekleme ve 114 silme
  1. 4 0
      demo/src/main/assets/yyxx_game/ext_log.json
  2. 13 0
      demo/src/main/assets/yyxx_game/sdk_log.json
  3. 1 3
      demo/src/main/assets/yyxx_game/yyxx_cfg.properties
  4. 19 1
      demo/src/main/java/com/eyuangame/demo/DemoActivity.kt
  5. 344 0
      iabv3_backup/ChargeImpl.kt
  6. 145 0
      iabv3_backup/InAppBilling.kt
  7. 313 0
      iabv4_backup/ChargeImpl.kt
  8. 145 0
      iabv4_backup/InAppBilling.kt
  9. 6 6
      library_base/src/main/java/cn/yyxx/eyuangame/base/EYuanGame.kt
  10. 1 0
      library_base/src/main/java/cn/yyxx/eyuangame/base/entity/Function.kt
  11. 18 0
      library_base/src/main/java/cn/yyxx/eyuangame/base/entity/SdkEvent.kt
  12. 13 0
      library_base/src/main/java/cn/yyxx/eyuangame/base/utils/ParamsUtils.kt
  13. 8 3
      library_core/build.gradle
  14. 5 0
      library_core/src/main/java/cn/yyxx/eyuangame/core/SdkBridge.kt
  15. 0 10
      library_core/src/main/java/cn/yyxx/eyuangame/core/entity/SubmitTiming.kt
  16. 27 6
      library_core/src/main/java/cn/yyxx/eyuangame/core/impl/SdkBridgeImpl.kt
  17. 64 33
      library_core/src/main/java/cn/yyxx/eyuangame/core/impl/iab/ChargeImpl.kt
  18. 13 13
      library_core/src/main/java/cn/yyxx/eyuangame/core/impl/iab/InAppBilling.kt
  19. 5 1
      library_core/src/main/java/cn/yyxx/eyuangame/core/impl/login/LoginActivity.kt
  20. 18 3
      library_core/src/main/java/cn/yyxx/eyuangame/core/internal/IEventObserver.kt
  21. 39 8
      library_core/src/main/java/cn/yyxx/eyuangame/core/linking/Linking.kt
  22. 261 3
      library_core/src/main/java/cn/yyxx/eyuangame/core/linking/channel/LinkingAdjustImpl.kt
  23. 167 4
      library_core/src/main/java/cn/yyxx/eyuangame/core/linking/channel/LinkingFacebookImpl.kt
  24. 141 3
      library_core/src/main/java/cn/yyxx/eyuangame/core/linking/channel/LinkingFirebaseImpl.kt
  25. 1 1
      library_core/src/main/java/cn/yyxx/eyuangame/core/network/Host.kt
  26. 19 2
      library_core/src/main/java/cn/yyxx/eyuangame/core/network/SdkRequest.kt
  27. 1 7
      library_core/src/main/java/cn/yyxx/eyuangame/core/network/VolleyRequest.kt
  28. 4 2
      library_core/src/main/java/cn/yyxx/eyuangame/core/ui/dialog/ScaleLoadingDialog.kt
  29. 4 2
      library_core/src/main/java/cn/yyxx/eyuangame/core/utils/MMKVUtils.kt
  30. 3 3
      library_core/src/main/java/cn/yyxx/eyuangame/core/utils/SessionUtils.kt
  31. BIN
      libs/yyxx_support_1.0.1.jar

+ 4 - 0
demo/src/main/assets/yyxx_game/ext_log.json

@@ -0,0 +1,4 @@
+{
+  "tutorial": "9pwnih",
+  "finish_marry": "avl1zv"
+}

+ 13 - 0
demo/src/main/assets/yyxx_game/sdk_log.json

@@ -0,0 +1,13 @@
+{
+  "open_app": "rjo5ax",
+  "choose_login_page": "eo8k08",
+  "sign_up": "mzvwmo",
+  "login_success_quick": "3igk4b",
+  "login_success_fb": "dwbri1",
+  "login_success_google": "tk971u",
+  "login_success_account": "wp73dt",
+  "ecommerce_purchase": "qum6x5",
+  "first_purchase": "r1mt2x",
+  "create_player": "apjl7l",
+  "enter_game": "qfd1ul"
+}

+ 1 - 3
demo/src/main/assets/yyxx_game/yyxx_cfg.properties

@@ -3,9 +3,7 @@ YYXX_GCP_CODE=G010101
 #分包标识
 YYXX_GAME_CODE=100001
 # 事件打点应用ID
-YYXX_ADJUST_APP_ID=3lb7knrx3yww
-# 事件打点开关,没配置的情况下默认开启(true)
-#YYXX_ADJUST_ENABLE=false
+YYXX_ADJUST_APP_ID=43gp4f912rgg
 # Google AppId
 YYXX_GOOGLE_APP_ID=70429070957
 # Google Server Client Id

+ 19 - 1
demo/src/main/java/com/eyuangame/demo/DemoActivity.kt

@@ -11,6 +11,7 @@ import android.view.View
 import android.widget.*
 import cn.yyxx.eyuangame.base.EYuanGame
 import cn.yyxx.eyuangame.base.entity.SdkChargeInfo
+import cn.yyxx.eyuangame.base.entity.SdkEvent
 import cn.yyxx.eyuangame.base.entity.SdkRoleInfo
 import cn.yyxx.eyuangame.base.internal.ICallback
 import cn.yyxx.support.hawkeye.LogUtils
@@ -34,6 +35,8 @@ class DemoActivity : Activity(), View.OnClickListener {
         Item(6, "06 Google应用内购"),
         Item(7, "07 第三方H5支付"),
         Item(8, "08 Crashlytics崩溃测试"),
+        Item(9, "09 模拟CP打点(玩家首次完成新手引导)"),
+        Item(10, "10 模拟CP打点(玩家首次完成结缘)")
     )
 
 
@@ -93,7 +96,7 @@ class DemoActivity : Activity(), View.OnClickListener {
 
     override fun onClick(v: View?) {
         v?.apply {
-//            mTextView.text = ""
+            mTextView.text = ""
             when (tag as Int) {
                 0 -> EnvActivity.start(this@DemoActivity)
                 1 -> {
@@ -143,6 +146,19 @@ class DemoActivity : Activity(), View.OnClickListener {
                     })
                 }
                 8 -> throw RuntimeException("Test Crashlytics Feature")
+                9 -> {
+                    val sdkEvent = SdkEvent()
+                    sdkEvent.eventName = "tutorial"
+                    sdkEvent.standard = true
+                    sdkEvent.fbAliasName = "fb_mobile_tutorial_completion"
+                    EYuanGame.getInstance().linkingEvent(this@DemoActivity, sdkEvent)
+                }
+                10 -> {
+                    val sdkEvent = SdkEvent()
+                    sdkEvent.eventName = "finish_marry"
+                    sdkEvent.standard = false
+                    EYuanGame.getInstance().linkingEvent(this@DemoActivity, sdkEvent)
+                }
             }
         }
     }
@@ -158,6 +174,7 @@ class DemoActivity : Activity(), View.OnClickListener {
             gameRoleInfo.roleName = roleName
             //角色等级
             gameRoleInfo.roleLevel = roleLevel
+            gameRoleInfo.roleCTime = roleCTime
             //服务器ID
             gameRoleInfo.serverId = serverCode
             //服务器名
@@ -166,6 +183,7 @@ class DemoActivity : Activity(), View.OnClickListener {
             gameRoleInfo.vipLevel = vipLevel
             //当前角色游戏币余额
             gameRoleInfo.balance = balance
+            gameRoleInfo.totalPurchase = totalPurchase
         }
         return gameRoleInfo
     }

+ 344 - 0
iabv3_backup/ChargeImpl.kt

@@ -0,0 +1,344 @@
+package cn.yyxx.eyuangame.core.impl.iab
+
+import android.app.Activity
+import android.text.TextUtils
+import cn.yyxx.eyuangame.base.entity.SdkChargeInfo
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.eyuangame.core.entity.ResultInfo
+import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
+import cn.yyxx.eyuangame.core.internal.IImplCallback
+import cn.yyxx.eyuangame.core.internal.IRequestCallback
+import cn.yyxx.eyuangame.core.network.SdkRequest
+import cn.yyxx.eyuangame.core.utils.MMKVUtils
+import cn.yyxx.support.ResUtils
+import cn.yyxx.support.hawkeye.ToastUtils
+import com.android.billingclient.api.*
+import org.json.JSONException
+import org.json.JSONObject
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/28
+ */
+class ChargeImpl : InAppBilling() {
+
+    //初始化IAB收银台客户端
+    //连接谷歌商店
+    private lateinit var implCallback: IImplCallback
+    private lateinit var chargeInfo: SdkChargeInfo
+
+
+    fun charge(activity: Activity, chargeInfo: SdkChargeInfo, callback: IImplCallback) {
+        if (!checkGoogleApiAvailability(activity)) {
+            ToastUtils.toastInfo(activity, "Your phone or Google account does not support In-app Billing")
+            callback.onResult(-1, "谷歌iab支付服务不可用")
+            return
+        }
+        this.implCallback = callback
+        this.chargeInfo = chargeInfo
+        showDialog(activity)
+
+//        checkLocalNotifyFailedOrder(activity)
+        getOrderId(activity)
+    }
+
+    override fun chargePurchasesUpdated(activity: Activity, purchase: Purchase) {
+        Logger.d("chargePurchasesUpdated")
+        notifyOrder2Backend(activity, chargeInfo.orderId, purchase, false)
+    }
+
+    override fun preRewardPurchasesUpdated(activity: Activity, purchase: Purchase) {
+    }
+
+    override fun queryRewardInfo(activity: Activity) {
+    }
+
+    /**
+     * 查询未消耗订单
+     */
+    override fun queryChargeInfo(activity: Activity) {
+        billingClient?.apply {
+            val list = queryPurchases(BillingClient.SkuType.INAPP).purchasesList
+            if (list.isNullOrEmpty()) {
+                //正常发起支付流程
+                querySkuDetails(activity)
+            } else {
+                Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
+                run breaking@{
+                    if (list.size > 0) {
+                        list.forEach { purchase ->
+                            if (purchase.sku == SdkBridgeImpl.initBean.rewardId) {
+                                Logger.e("存在阻塞的预注册奖励,停止支付流程")
+                                if (list.size == 1) {
+                                    dismissDialog()
+                                    disConnection()
+                                    ToastUtils.toastInfo(activity, "In-app Billing has some error , please restart app and try again")
+                                    implCallback.onResult(-1, "存在阻塞的预注册奖励,停止支付流程")
+                                }
+                                //跳出支付流程
+                                return@breaking
+                            } else {
+                                consumeCacheOrder(activity, purchase)
+                            }
+                        }
+                    } else {
+                        //发起正常支付流程
+                        querySkuDetails(activity)
+                    }
+                }
+            }
+
+
+//            queryPurchasesAsync(BillingClient.SkuType.INAPP, object : PurchasesResponseListener {
+//                override fun onQueryPurchasesResponse(billingResult: BillingResult, list: MutableList<Purchase>) {
+//                    logBillingResult("onQueryPurchasesResponse", billingResult)
+//                    if (list.isNullOrEmpty()) {
+//                        //正常发起支付流程
+//                        Logger.d("正常发起支付流程")
+//                        querySkuDetails(activity)
+//                    } else {
+//                        Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
+//                        run breaking@{
+//                            list.forEach { purchase ->
+//                                purchase.skus.forEach {
+//                                    if (it.equals(SdkBridgeImpl.initBean.rewardId)) {
+//                                        Logger.e("存在阻塞的预注册奖励,停止支付流程")
+//                                        if (list.size == 1) {
+//                                            dismissDialog()
+//                                            disConnection()
+//                                            ToastUtils.toastInfo(activity, "In-app Billing has some error , please restart app and try again")
+//                                            implCallback.onResult(-1, "存在阻塞的预注册奖励,停止支付流程")
+//                                        }
+//                                        //跳出支付流程
+//                                        return@breaking
+//                                    } else {
+//                                        consumeCacheOrder(activity, purchase)
+//                                    }
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
+//            })
+        }
+    }
+
+    override fun purchasesUpdatedFailed() {
+    }
+
+    override fun connectGooglePlayFailed() {
+    }
+
+    /**
+     * 检查本地通知发货失败订单
+     */
+    private fun checkLocalNotifyFailedOrder(activity: Activity) {
+
+    }
+
+    /**
+     * 获取订单号
+     */
+    private fun getOrderId(activity: Activity) {
+        SdkRequest.instance.createOrder(activity, chargeInfo, object : IRequestCallback {
+            override fun onResponse(resultInfo: ResultInfo) {
+                if (resultInfo.code == 1 && !TextUtils.isEmpty(resultInfo.data)) {
+                    try {
+                        val jsonObject = JSONObject(resultInfo.data)
+                        chargeInfo.orderId = jsonObject.getString("order_id")
+                        Logger.d("order_id ---> ${chargeInfo.orderId}")
+                        //获取订单号成功,初始化IAB收银台客户端
+                        Logger.d("获取订单号成功,初始化IAB收银台客户端")
+                        initializeBillingClient(activity)
+                        connectGooglePlay(activity, false)
+                    } catch (e: JSONException) {
+                        e.printStackTrace()
+                        dismissDialog()
+                        val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
+                            ResUtils.getResString(activity, "yyxx_charge_tv_error")
+                        } else {
+                            resultInfo.msg
+                        }
+                        ToastUtils.toastInfo(activity, msg)
+                        implCallback.onResult(-1, "获取订单异常")
+                    }
+                } else {
+                    dismissDialog()
+                    val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
+                        ResUtils.getResString(activity, "yyxx_charge_tv_error")
+                    } else {
+                        resultInfo.msg
+                    }
+                    ToastUtils.toastInfo(activity, msg)
+                    implCallback.onResult(-1, "获取订单异常")
+                }
+            }
+
+        })
+    }
+
+    /**
+     * 查询商品信息
+     */
+    private fun querySkuDetails(activity: Activity) {
+        val skus = mutableListOf<String>()
+        skus.add(chargeInfo.productId)
+        val params = SkuDetailsParams.newBuilder().setType(BillingClient.SkuType.INAPP).setSkusList(skus).build()
+        billingClient?.querySkuDetailsAsync(params) { billingResult, list ->
+            logBillingResult("onSkuDetailsResponse", billingResult)
+            dismissDialog()
+            if (list.isNullOrEmpty()) {
+                //查询商品信息失败
+                Logger.e("查询商品信息失败")
+                ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                implCallback.onResult(-1, "查询商品信息失败")
+                disConnection()
+            } else {
+                if (list.size == 1) {
+                    val skuDetails = list[0]
+                    Logger.d("product id : ${skuDetails.sku}")
+                    launchBillingFlow(activity, skuDetails)
+                } else {
+                    ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                    implCallback.onResult(-1, "查询商品信息异常")
+                    disConnection()
+                }
+            }
+        }
+    }
+
+    /**
+     * 启动收银台
+     *
+     */
+    private fun launchBillingFlow(activity: Activity, skuDetails: SkuDetails) {
+        billingClient?.apply {
+            if (isReady) {
+                val flowParams = BillingFlowParams.newBuilder().setObfuscatedAccountId(chargeInfo.orderId).setSkuDetails(skuDetails).build()
+
+                val billingResult = launchBillingFlow(activity, flowParams)
+                logBillingResult("launchBillingFlow", billingResult)
+                if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
+                    dismissDialog()
+                    disConnection()
+                    ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                    implCallback.onResult(-1, "启动谷歌收银台失败")
+                }
+            } else {
+                dismissDialog()
+                disConnection()
+                ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                implCallback.onResult(-1, "启动谷歌收银台失败")
+            }
+        }
+    }
+
+    /**
+     * 通知服务端发货
+     */
+    private fun notifyOrder2Backend(activity: Activity, orderId: String, purchase: Purchase, isCache: Boolean = false) {
+        SdkRequest.instance.notifyOrder(activity, orderId, purchase.originalJson, object : IRequestCallback {
+            override fun onResponse(resultInfo: ResultInfo) {
+                if (resultInfo.code == 1) {
+                    //消耗订单
+                    consumeAsync(activity, purchase, isCache)
+                } else {
+                    //失败则缓存订单
+                    saveOrderInfo(purchase.orderId, orderId)
+                    dismissDialog()
+                    disConnection()
+                    val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
+                        ResUtils.getResString(activity, "yyxx_charge_tv_error")
+                    } else {
+                        resultInfo.msg
+                    }
+                    ToastUtils.toastInfo(activity, msg)
+                    implCallback.onResult(-1, "发货失败")
+                }
+            }
+        })
+    }
+
+    /**
+     * 消耗缓存订单
+     */
+    private fun consumeCacheOrder(activity: Activity, purchase: Purchase) {
+        //消耗完了再发起支付
+        Logger.d("消耗缓存订单 : $purchase")
+        var orderId = ""
+        purchase.accountIdentifiers?.apply {
+            orderId = if (!TextUtils.isEmpty(obfuscatedAccountId)) {
+                obfuscatedAccountId!!
+            } else {
+                //TODO getLocalOrderId
+                getOrderInfo(purchase.orderId)
+            }
+        }
+        notifyOrder2Backend(activity, orderId, purchase, true)
+//        consumeAsync(activity, purchase.purchaseToken, true)
+
+    }
+
+    /**
+     * 消耗订单
+     */
+    private fun consumeAsync(activity: Activity, purchase: Purchase, isCache: Boolean = false) {
+        val consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchase.purchaseToken).build()
+        billingClient?.apply {
+            if (isReady) {
+                consumeAsync(consumeParams) { billingResult, token ->
+                    logBillingResult("onConsumeResponse", billingResult)
+                    dismissDialog()
+                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
+                        // saveOrder2Local()
+                        if (isCache) {
+                            querySkuDetails(activity)
+                        } else {
+                            implCallback.onResult(0, "支付成功")
+                            disConnection()
+                        }
+                        removeOrderInfo(purchase.orderId)
+                    } else {
+                        implCallback.onResult(-1, "消耗订单异常")
+                        disConnection()
+                        ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                    }
+                }
+            } else {
+                dismissDialog()
+                disConnection()
+                implCallback.onResult(-1, "消耗订单异常")
+                ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+            }
+        }
+    }
+
+    private fun saveOrderInfo(googleOrderId: String, orderId: String) {
+        try {
+            MMKVUtils.instance.orderKV.encode(googleOrderId, orderId)
+        } catch (e: JSONException) {
+            e.printStackTrace()
+        }
+    }
+
+    private fun getOrderInfo(googleOrderId: String): String {
+        val info = MMKVUtils.instance.orderKV.decodeString(googleOrderId)
+        Logger.d("getOrderInfo : $info")
+        return if (TextUtils.isEmpty(info)) {
+            ""
+        } else {
+            info!!
+        }
+    }
+
+    private fun removeOrderInfo(googleOrderId: String) {
+        MMKVUtils.instance.orderKV.removeValueForKey(googleOrderId)
+    }
+
+
+    companion object {
+        val instance: ChargeImpl by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+            ChargeImpl()
+        }
+    }
+}

+ 145 - 0
iabv3_backup/InAppBilling.kt

@@ -0,0 +1,145 @@
+package cn.yyxx.eyuangame.core.impl.iab
+
+import android.app.Activity
+import android.content.Context
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
+import cn.yyxx.eyuangame.core.ui.dialog.ScaleLoadingDialog
+import cn.yyxx.support.ResUtils
+import com.android.billingclient.api.BillingClient
+import com.android.billingclient.api.BillingClientStateListener
+import com.android.billingclient.api.BillingResult
+import com.android.billingclient.api.Purchase
+import com.google.android.gms.common.ConnectionResult
+import com.google.android.gms.common.GoogleApiAvailability
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/17
+ */
+abstract class InAppBilling {
+
+    protected var billingClient: BillingClient? = null
+    private var loadingDialog: ScaleLoadingDialog? = null
+
+    protected fun checkGoogleApiAvailability(activity: Activity): Boolean {
+        return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity) == ConnectionResult.SUCCESS
+    }
+
+    /**
+     * 初始化IAB收银台客户端
+     */
+    protected fun initializeBillingClient(activity: Activity) {
+        billingClient = BillingClient.newBuilder(activity).setListener { billingResult, list ->
+            //谷歌支付结果在这里回调
+            logBillingResult("onPurchasesUpdated", billingResult)
+            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
+                if (list != null && list.size > 0) {
+                    Logger.d(list.size)
+                    for (purchase in list) {
+                        if (purchase.sku == SdkBridgeImpl.initBean.rewardId) {
+                            //预注册
+                            preRewardPurchasesUpdated(activity, purchase)
+                        } else {
+                            //支付
+                            chargePurchasesUpdated(activity, purchase)
+                        }
+                    }
+                } else {
+                    purchasesUpdatedFailed()
+                }
+            } else {
+                purchasesUpdatedFailed()
+            }
+        }.enablePendingPurchases().build()
+    }
+
+
+    /**
+     * 连接谷歌商店
+     */
+    protected fun connectGooglePlay(activity: Activity, isPreReward: Boolean = false) {
+        billingClient?.apply {
+            if (!isReady) {
+                Logger.d("start connection Google Play ...")
+                startConnection(object : BillingClientStateListener {
+                    override fun onBillingSetupFinished(billingResult: BillingResult) {
+                        logBillingResult("onBillingSetupFinished", billingResult)
+                        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
+                            if (isPreReward) {
+                                queryRewardInfo(activity)
+                            } else {
+                                queryChargeInfo(activity)
+                            }
+                        } else {
+                            connectGooglePlayFailed()
+                        }
+                    }
+
+                    override fun onBillingServiceDisconnected() {
+                        Logger.e("onBillingServiceDisconnected")
+                        connectGooglePlay(activity, isPreReward)
+                    }
+                })
+            } else {
+                dismissDialog()
+                disConnection()
+            }
+        }
+    }
+
+//    protected fun handlePurchase(list)
+
+    protected fun disConnection() {
+        billingClient?.apply {
+            if (isReady) {
+                Logger.d("断开谷歌收银台连接,以清空被消耗或者失败的缓存订单")
+                endConnection()
+            }
+        }
+    }
+
+    protected fun logBillingResult(callbackFuncName: String, billingResult: BillingResult) {
+        val code = billingResult.responseCode
+        val msg = billingResult.debugMessage
+        Logger.d("$callbackFuncName , code : $code , msg : $msg")
+    }
+
+    protected fun showDialog(context: Context) {
+        loadingDialog?.apply {
+            dismiss()
+            loadingDialog = null
+        }
+
+        loadingDialog = ScaleLoadingDialog(context, ResUtils.getResString(context, "yyxx_charge_loading_tips"))
+        loadingDialog?.show()
+    }
+
+    protected fun dismissDialog() {
+        loadingDialog?.apply {
+            dismiss()
+            loadingDialog = null
+        }
+    }
+
+    /**
+     * charge
+     * Purchase{"orderId":"GPA.3325-4558-9050-03633","packageName":"com.flyfun.demo","productId":"com.flyfun.ylj.60","purchaseTime":1618367632652,"purchaseState":4,"purchaseToken":"mpfdmeeoemplddgfknnkgnlf.AO-J1Owpfua8OfxpU_sjOBTY_ZgRoN3Km-mNJdmie9Qpd1w-DDQjtkUfcWOGhScHHeJ9ogWqkP_01w5WHp9Pfnpvgx1_nffDYA","acknowledged":false}
+     */
+    protected abstract fun chargePurchasesUpdated(activity: Activity, purchase: Purchase)
+
+    /**
+     * pre reward
+     * Purchase{"packageName":"com.flyfun.demo","productId":"com.flyfun.demo70","purchaseTime":1618367980837,"purchaseState":0,"purchaseToken":"cdphbkooagehckdcmkhmbhmd.AO-J1OzHTtCRDhd8k1Qfp3FU0GgYQUSaCx6I6W6Oi_P2tiS3LWKIdb6jTkc-tTqfcCagPxw2nPqujl9s10KuCunTl3OLSiIN9A"}
+     */
+    protected abstract fun preRewardPurchasesUpdated(activity: Activity, purchase: Purchase)
+
+    protected abstract fun queryRewardInfo(activity: Activity)
+
+    protected abstract fun queryChargeInfo(activity: Activity)
+
+    protected abstract fun purchasesUpdatedFailed()
+
+    protected abstract fun connectGooglePlayFailed()
+
+}

+ 313 - 0
iabv4_backup/ChargeImpl.kt

@@ -0,0 +1,313 @@
+package cn.yyxx.eyuangame.core.impl.iab
+
+import android.app.Activity
+import android.text.TextUtils
+import cn.yyxx.eyuangame.base.entity.SdkChargeInfo
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.eyuangame.core.entity.ResultInfo
+import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
+import cn.yyxx.eyuangame.core.internal.IImplCallback
+import cn.yyxx.eyuangame.core.internal.IRequestCallback
+import cn.yyxx.eyuangame.core.network.SdkRequest
+import cn.yyxx.eyuangame.core.utils.MMKVUtils
+import cn.yyxx.support.ResUtils
+import cn.yyxx.support.hawkeye.ToastUtils
+import com.android.billingclient.api.*
+import org.json.JSONException
+import org.json.JSONObject
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/28
+ */
+class ChargeImpl : InAppBilling() {
+
+    //初始化IAB收银台客户端
+    //连接谷歌商店
+    private lateinit var implCallback: IImplCallback
+    private lateinit var chargeInfo: SdkChargeInfo
+
+
+    fun charge(activity: Activity, chargeInfo: SdkChargeInfo, callback: IImplCallback) {
+        if (!checkGoogleApiAvailability(activity)) {
+            ToastUtils.toastInfo(activity, "Your phone or Google account does not support In-app Billing")
+            callback.onResult(-1, "谷歌iab支付服务不可用")
+            return
+        }
+        this.implCallback = callback
+        this.chargeInfo = chargeInfo
+        showDialog(activity)
+
+//        checkLocalNotifyFailedOrder(activity)
+        getOrderId(activity)
+    }
+
+    override fun chargePurchasesUpdated(activity: Activity, purchase: Purchase) {
+        notifyOrder2Backend(activity, chargeInfo.orderId, purchase, false)
+    }
+
+    override fun preRewardPurchasesUpdated(activity: Activity, purchase: Purchase) {
+    }
+
+    override fun queryRewardInfo(activity: Activity) {
+    }
+
+    /**
+     * 查询未消耗订单
+     */
+    override fun queryChargeInfo(activity: Activity) {
+        billingClient?.apply {
+            queryPurchasesAsync(BillingClient.SkuType.INAPP, object : PurchasesResponseListener {
+                override fun onQueryPurchasesResponse(billingResult: BillingResult, list: MutableList<Purchase>) {
+                    logBillingResult("onQueryPurchasesResponse", billingResult)
+                    if (list.isNullOrEmpty()) {
+                        //正常发起支付流程
+                        Logger.d("正常发起支付流程")
+                        querySkuDetails(activity)
+                    } else {
+                        Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
+                        run breaking@{
+                            list.forEach { purchase ->
+                                purchase.skus.forEach {
+                                    if (it.equals(SdkBridgeImpl.initBean.rewardId)) {
+                                        Logger.e("存在阻塞的预注册奖励,停止支付流程")
+                                        if (list.size == 1) {
+                                            dismissDialog()
+                                            disConnection()
+                                            ToastUtils.toastInfo(activity, "In-app Billing has some error , please restart app and try again")
+                                            implCallback.onResult(-1, "存在阻塞的预注册奖励,停止支付流程")
+                                        }
+                                        //跳出支付流程
+                                        return@breaking
+                                    } else {
+                                        consumeCacheOrder(activity, purchase)
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            })
+        }
+    }
+
+    override fun purchasesUpdatedFailed() {
+    }
+
+    override fun connectGooglePlayFailed() {
+    }
+
+    /**
+     * 检查本地通知发货失败订单
+     */
+    private fun checkLocalNotifyFailedOrder(activity: Activity) {
+
+    }
+
+    /**
+     * 获取订单号
+     */
+    private fun getOrderId(activity: Activity) {
+        SdkRequest.instance.createOrder(activity, chargeInfo, object : IRequestCallback {
+            override fun onResponse(resultInfo: ResultInfo) {
+                if (resultInfo.code == 1 && !TextUtils.isEmpty(resultInfo.data)) {
+                    try {
+                        val jsonObject = JSONObject(resultInfo.data)
+                        chargeInfo.orderId = jsonObject.getString("order_id")
+                        Logger.d("order_id ---> ${chargeInfo.orderId}")
+                        //获取订单号成功,初始化IAB收银台客户端
+                        Logger.d("获取订单号成功,初始化IAB收银台客户端")
+                        initializeBillingClient(activity)
+                        connectGooglePlay(activity, false)
+                    } catch (e: JSONException) {
+                        e.printStackTrace()
+                        dismissDialog()
+                        val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
+                            ResUtils.getResString(activity, "yyxx_charge_tv_error")
+                        } else {
+                            resultInfo.msg
+                        }
+                        ToastUtils.toastInfo(activity, msg)
+                        implCallback.onResult(-1, "获取订单异常")
+                    }
+                } else {
+                    dismissDialog()
+                    val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
+                        ResUtils.getResString(activity, "yyxx_charge_tv_error")
+                    } else {
+                        resultInfo.msg
+                    }
+                    ToastUtils.toastInfo(activity, msg)
+                    implCallback.onResult(-1, "获取订单异常")
+                }
+            }
+
+        })
+    }
+
+    /**
+     * 查询商品信息
+     */
+    private fun querySkuDetails(activity: Activity) {
+        val skus = mutableListOf<String>()
+        skus.add(chargeInfo.productId)
+        val params = SkuDetailsParams.newBuilder().setType(BillingClient.SkuType.INAPP).setSkusList(skus).build()
+        billingClient?.querySkuDetailsAsync(params) { billingResult, list ->
+            logBillingResult("onSkuDetailsResponse", billingResult)
+            dismissDialog()
+            if (list.isNullOrEmpty()) {
+                //查询商品信息失败
+                Logger.e("查询商品信息失败")
+                ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                implCallback.onResult(-1, "查询商品信息失败")
+                disConnection()
+            } else {
+                if (list.size == 1) {
+                    val skuDetails = list[0]
+                    Logger.d("product id : ${skuDetails.sku}")
+                    launchBillingFlow(activity, skuDetails)
+                } else {
+                    ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                    implCallback.onResult(-1, "查询商品信息异常")
+                    disConnection()
+                }
+            }
+        }
+    }
+
+    /**
+     * 启动收银台
+     *
+     */
+    private fun launchBillingFlow(activity: Activity, skuDetails: SkuDetails) {
+        billingClient?.apply {
+            if (isReady) {
+                val flowParams = BillingFlowParams.newBuilder().setObfuscatedAccountId(chargeInfo.orderId).setSkuDetails(skuDetails).build()
+
+                val billingResult = launchBillingFlow(activity, flowParams)
+                logBillingResult("launchBillingFlow", billingResult)
+                if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
+                    dismissDialog()
+                    disConnection()
+                    ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                    implCallback.onResult(-1, "启动谷歌收银台失败")
+                }
+            } else {
+                dismissDialog()
+                disConnection()
+                ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+                implCallback.onResult(-1, "启动谷歌收银台失败")
+            }
+        }
+    }
+
+    /**
+     * 通知服务端发货
+     */
+    private fun notifyOrder2Backend(activity: Activity, orderId: String, purchase: Purchase, isCache: Boolean = false) {
+        SdkRequest.instance.notifyOrder(activity, orderId, purchase.originalJson, object : IRequestCallback {
+            override fun onResponse(resultInfo: ResultInfo) {
+                if (resultInfo.code == 1) {
+                    //消耗订单
+                    consumeAsync(activity, purchase, isCache)
+                } else {
+                    //失败则缓存订单
+                    saveOrderInfo(purchase.orderId, orderId)
+                    dismissDialog()
+                    disConnection()
+                    val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
+                        ResUtils.getResString(activity, "yyxx_charge_tv_error")
+                    } else {
+                        resultInfo.msg
+                    }
+                    ToastUtils.toastInfo(activity, msg)
+                    implCallback.onResult(-1, "发货失败")
+                }
+            }
+        })
+    }
+
+    /**
+     * 消耗缓存订单
+     */
+    private fun consumeCacheOrder(activity: Activity, purchase: Purchase) {
+        //消耗完了再发起支付
+        Logger.d("消耗缓存订单 : $purchase")
+        var orderId = ""
+        purchase.accountIdentifiers?.apply {
+            orderId = if (!TextUtils.isEmpty(obfuscatedAccountId)) {
+                obfuscatedAccountId!!
+            } else {
+                //TODO getLocalOrderId
+                getOrderInfo(purchase.orderId)
+            }
+        }
+        notifyOrder2Backend(activity, orderId, purchase, true)
+//        consumeAsync(activity, purchase.purchaseToken, true)
+
+    }
+
+    /**
+     * 消耗订单
+     */
+    private fun consumeAsync(activity: Activity, purchase: Purchase, isCache: Boolean = false) {
+        val consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchase.purchaseToken).build()
+        billingClient?.apply {
+            if (isReady) {
+                consumeAsync(consumeParams) { billingResult, _ ->
+                    logBillingResult("onConsumeResponse", billingResult)
+                    dismissDialog()
+                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
+                        // saveOrder2Local()
+                        if (isCache) {
+                            querySkuDetails(activity)
+                        } else {
+                            disConnection()
+                            implCallback.onResult(0, "支付成功")
+                        }
+                        removeOrderInfo(purchase.orderId)
+                    } else {
+                        disConnection()
+                        implCallback.onResult(-1, "消耗订单异常")
+                        ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+
+                    }
+                }
+            } else {
+                dismissDialog()
+                disConnection()
+                implCallback.onResult(-1, "消耗订单异常")
+                ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
+            }
+        }
+    }
+
+    private fun saveOrderInfo(googleOrderId: String, orderId: String) {
+        try {
+            MMKVUtils.instance.orderKV?.encode(googleOrderId, orderId)
+        } catch (e: JSONException) {
+            e.printStackTrace()
+        }
+    }
+
+    private fun getOrderInfo(googleOrderId: String): String {
+        val info = MMKVUtils.instance.orderKV?.decodeString(googleOrderId)
+        Logger.d("getOrderInfo : $info")
+        return if (TextUtils.isEmpty(info)) {
+            ""
+        } else {
+            info!!
+        }
+    }
+
+    private fun removeOrderInfo(googleOrderId: String) {
+        MMKVUtils.instance.orderKV?.removeValueForKey(googleOrderId)
+    }
+
+
+    companion object {
+        val instance: ChargeImpl by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+            ChargeImpl()
+        }
+    }
+}

+ 145 - 0
iabv4_backup/InAppBilling.kt

@@ -0,0 +1,145 @@
+package cn.yyxx.eyuangame.core.impl.iab
+
+import android.app.Activity
+import android.content.Context
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
+import cn.yyxx.eyuangame.core.ui.dialog.ScaleLoadingDialog
+import com.android.billingclient.api.BillingClient
+import com.android.billingclient.api.BillingClientStateListener
+import com.android.billingclient.api.BillingResult
+import com.android.billingclient.api.Purchase
+import com.google.android.gms.common.ConnectionResult
+import com.google.android.gms.common.GoogleApiAvailability
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/17
+ */
+abstract class InAppBilling {
+
+    protected var billingClient: BillingClient? = null
+    private var loadingDialog: ScaleLoadingDialog? = null
+
+    protected fun checkGoogleApiAvailability(activity: Activity): Boolean {
+        return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity) == ConnectionResult.SUCCESS
+    }
+
+    /**
+     * 初始化IAB收银台客户端
+     */
+    protected fun initializeBillingClient(activity: Activity) {
+        billingClient = BillingClient.newBuilder(activity).setListener { billingResult, list ->
+            //谷歌支付结果在这里回调
+            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
+                if (list.isNullOrEmpty()) {
+                    purchasesUpdatedFailed()
+                } else {
+                    for (purchase in list) {
+                        Logger.d(purchase.toString())
+                        purchase.skus.forEach {
+                            if (it.equals(SdkBridgeImpl.initBean.rewardId)) {
+                                //预注册
+                                preRewardPurchasesUpdated(activity, purchase)
+                            } else {
+                                //支付
+                                chargePurchasesUpdated(activity, purchase)
+                            }
+                        }
+                    }
+                }
+            } else {
+                purchasesUpdatedFailed()
+            }
+        }.enablePendingPurchases().build()
+    }
+
+
+    /**
+     * 连接谷歌商店
+     */
+    protected fun connectGooglePlay(activity: Activity, isPreReward: Boolean = false) {
+        billingClient?.apply {
+            if (!isReady) {
+                Logger.d("start connection Google Play ...")
+                startConnection(object : BillingClientStateListener {
+                    override fun onBillingSetupFinished(billingResult: BillingResult) {
+                        logBillingResult("onBillingSetupFinished", billingResult)
+                        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
+                            if (isPreReward) {
+                                queryRewardInfo(activity)
+                            } else {
+                                queryChargeInfo(activity)
+                            }
+                        } else {
+                            connectGooglePlayFailed()
+                        }
+                    }
+
+                    override fun onBillingServiceDisconnected() {
+                        Logger.e("onBillingServiceDisconnected")
+                        connectGooglePlay(activity, isPreReward)
+                    }
+                })
+            } else {
+                dismissDialog()
+                disConnection()
+            }
+        }
+    }
+
+//    protected fun handlePurchase(list)
+
+    protected fun disConnection() {
+        billingClient?.apply {
+            if (isReady) {
+                Logger.d("断开谷歌收银台连接,以清空被消耗或者失败的缓存订单")
+                endConnection()
+            }
+        }
+    }
+
+    protected fun logBillingResult(callbackFuncName: String, billingResult: BillingResult) {
+        val code = billingResult.responseCode
+        val msg = billingResult.debugMessage
+        Logger.d("$callbackFuncName , code : $code , msg : $msg")
+    }
+
+    protected fun showDialog(context: Context) {
+        loadingDialog?.apply {
+            dismiss()
+            loadingDialog = null
+        }
+
+        loadingDialog = ScaleLoadingDialog(context, "")
+        loadingDialog?.show()
+    }
+
+    protected fun dismissDialog() {
+        loadingDialog?.apply {
+            dismiss()
+            loadingDialog = null
+        }
+    }
+
+    /**
+     * charge
+     * Purchase{"orderId":"GPA.3325-4558-9050-03633","packageName":"com.flyfun.demo","productId":"com.flyfun.ylj.60","purchaseTime":1618367632652,"purchaseState":4,"purchaseToken":"mpfdmeeoemplddgfknnkgnlf.AO-J1Owpfua8OfxpU_sjOBTY_ZgRoN3Km-mNJdmie9Qpd1w-DDQjtkUfcWOGhScHHeJ9ogWqkP_01w5WHp9Pfnpvgx1_nffDYA","acknowledged":false}
+     */
+    protected abstract fun chargePurchasesUpdated(activity: Activity, purchase: Purchase)
+
+    /**
+     * pre reward
+     * Purchase{"packageName":"com.flyfun.demo","productId":"com.flyfun.demo70","purchaseTime":1618367980837,"purchaseState":0,"purchaseToken":"cdphbkooagehckdcmkhmbhmd.AO-J1OzHTtCRDhd8k1Qfp3FU0GgYQUSaCx6I6W6Oi_P2tiS3LWKIdb6jTkc-tTqfcCagPxw2nPqujl9s10KuCunTl3OLSiIN9A"}
+     */
+    protected abstract fun preRewardPurchasesUpdated(activity: Activity, purchase: Purchase)
+
+    protected abstract fun queryRewardInfo(activity: Activity)
+
+    protected abstract fun queryChargeInfo(activity: Activity)
+
+    protected abstract fun purchasesUpdatedFailed()
+
+    protected abstract fun connectGooglePlayFailed()
+
+}

+ 6 - 6
library_base/src/main/java/cn/yyxx/eyuangame/base/EYuanGame.kt

@@ -11,12 +11,12 @@ import androidx.annotation.Keep
 import cn.yyxx.eyuangame.Version
 import cn.yyxx.eyuangame.base.entity.Function
 import cn.yyxx.eyuangame.base.entity.SdkChargeInfo
+import cn.yyxx.eyuangame.base.entity.SdkEvent
 import cn.yyxx.eyuangame.base.entity.SdkRoleInfo
 import cn.yyxx.eyuangame.base.internal.ICallback
 import cn.yyxx.eyuangame.base.internal.IInitialize
 import cn.yyxx.eyuangame.base.utils.Logger
 import cn.yyxx.support.AppUtils
-import org.json.JSONObject
 
 /**
  * @author #Suyghur.
@@ -362,7 +362,7 @@ class EYuanGame private constructor() {
     }
 
     fun onNewIntent(activity: Activity, intent: Intent) {
-        if (checkSdkBridgeNull(Function.ON_START, null)) {
+        if (checkSdkBridgeNull(Function.ON_NEW_INTENT, null)) {
             return
         }
 
@@ -393,15 +393,15 @@ class EYuanGame private constructor() {
         return Version.VERSION_NAME
     }
 
-    fun linkingEvent(activity: Activity, params: JSONObject) {
-        if (checkSdkBridgeNull(Function.GET_CURRENT_USER_ID, null)) {
+    fun linkingEvent(context: Context, sdkEvent: SdkEvent) {
+        if (checkSdkBridgeNull(Function.LINKING_EVENT, null)) {
             return
         }
 
-        if (checkSdkNonInit(Function.GET_CURRENT_USER_ID, null)) {
+        if (checkSdkNonInit(Function.LINKING_EVENT, null)) {
             return
         }
-        SdkBridgeManager.call(Function.ON_DESTROY, arrayOf(Activity::class.java), arrayOf(activity))
+        SdkBridgeManager.call(Function.LINKING_EVENT, arrayOf(Context::class.java, SdkEvent::class.java), arrayOf(context, sdkEvent))
     }
 
 

+ 1 - 0
library_base/src/main/java/cn/yyxx/eyuangame/base/entity/Function.kt

@@ -33,4 +33,5 @@ object Function {
     const val HAS_BIND_ACCOUNT = "hasBindAccount"
     const val IS_GM_CENTER_ENABLE = "isGmCenterEnable"
     const val INVOKE_SDK_SHARING = "invokeSdkSharing"
+    const val LINKING_EVENT="linkingEvent"
 }

+ 18 - 0
library_base/src/main/java/cn/yyxx/eyuangame/base/entity/SdkEvent.kt

@@ -0,0 +1,18 @@
+package cn.yyxx.eyuangame.base.entity
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/07/08
+ */
+class SdkEvent {
+
+    var eventName = ""
+    var eventParams = ""
+    var standard = false
+    var fbAliasName = ""
+
+    override fun toString(): String {
+        return "SdkEvent(eventName='$eventName', eventParams='$eventParams', standard=$standard, fbAliasName='$fbAliasName')"
+    }
+
+}

+ 13 - 0
library_base/src/main/java/cn/yyxx/eyuangame/base/utils/ParamsUtils.kt

@@ -13,6 +13,7 @@ object ParamsUtils {
     private const val CONFIG_FILE = "yyxx_cfg.properties"
     private const val YYXX_GCP_CODE = "YYXX_GCP_CODE"
     private const val YYXX_GAME_CODE = "YYXX_GAME_CODE"
+    private const val YYXX_ADJSUT_APP_ID = "YYXX_ADJUST_APP_ID"
     private const val YYXX_GOOGLE_APP_ID = "YYXX_GOOGLE_APP_ID"
     private const val YYXX_GOOGLE_CLIENT_ID = "YYXX_GOOGLE_CLIENT_ID"
 
@@ -41,6 +42,18 @@ object ParamsUtils {
     }
 
 
+    fun getAdjustAppId(context: Context): String {
+        try {
+            val appId = PropertiesUtils.getValue4Properties(context, CONFIG_FILE, "yyxx_game", YYXX_ADJSUT_APP_ID)
+            if (!TextUtils.isEmpty(appId)) {
+                return appId
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+        return ""
+    }
+
     fun getGoogleAppId(context: Context): String {
         try {
             val appId = PropertiesUtils.getValue4Properties(context, CONFIG_FILE, "yyxx_game", YYXX_GOOGLE_APP_ID)

+ 8 - 3
library_core/build.gradle

@@ -77,17 +77,22 @@ dependencies {
     implementation 'androidx.fragment:fragment-ktx:1.3.5'
     implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
     implementation 'com.google.android.material:material:1.4.0'
+    implementation 'com.android.installreferrer:installreferrer:2.2'
+
     //google
     implementation 'com.google.android.play:core:1.10.0'
     implementation 'com.google.android.gms:play-services-auth:19.0.0'
-    implementation 'com.android.billingclient:billing-ktx:4.0.0'
+    //4.0.0的billing库消耗商品会回调两次,后续在排查,先用3.0.3
+    implementation "com.android.billingclient:billing-ktx:3.0.3"
     implementation 'com.google.firebase:firebase-analytics-ktx:19.0.0'
     implementation 'com.google.firebase:firebase-crashlytics-ktx:18.1.0'
+
     //facebook
     implementation 'com.facebook.android:facebook-login:9.0.0'
-    implementation 'com.facebook.android:facebook-android-sdk:5.15.3'
+    implementation 'com.facebook.android:facebook-android-sdk:8.2.0'
+
     //adjust
-    implementation 'com.adjust.sdk:adjust-android:4.25.0'
+    implementation 'com.adjust.sdk:adjust-android:4.28.2'
 
     api project(':library_base')
 //    api project(':library_comm')

+ 5 - 0
library_core/src/main/java/cn/yyxx/eyuangame/core/SdkBridge.kt

@@ -5,6 +5,7 @@ import android.app.Application
 import android.content.Context
 import android.content.Intent
 import cn.yyxx.eyuangame.base.entity.SdkChargeInfo
+import cn.yyxx.eyuangame.base.entity.SdkEvent
 import cn.yyxx.eyuangame.base.entity.SdkRoleInfo
 import cn.yyxx.eyuangame.base.internal.ICallback
 import cn.yyxx.eyuangame.base.internal.IInitialize
@@ -105,4 +106,8 @@ class SdkBridge constructor(context: Context) {
         }
     }
 
+    fun linkingEvent(context: Context, sdkEvent: SdkEvent) {
+        mImpl?.linkingEvent(context, sdkEvent)
+    }
+
 }

+ 0 - 10
library_core/src/main/java/cn/yyxx/eyuangame/core/entity/SubmitTiming.kt

@@ -1,10 +0,0 @@
-package cn.yyxx.eyuangame.core.entity
-
-/**
- * @author #Suyghur.
- * Created on 2021/07/07
- */
-enum class SubmitTiming {
-    ROLE_CREATE,
-    ROLE_LAUNCHER
-}

+ 27 - 6
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/SdkBridgeImpl.kt

@@ -6,6 +6,7 @@ import android.content.Context
 import android.content.Intent
 import android.text.TextUtils
 import cn.yyxx.eyuangame.base.entity.SdkChargeInfo
+import cn.yyxx.eyuangame.base.entity.SdkEvent
 import cn.yyxx.eyuangame.base.entity.SdkRoleInfo
 import cn.yyxx.eyuangame.base.internal.ICallback
 import cn.yyxx.eyuangame.base.internal.IInitialize
@@ -63,7 +64,6 @@ class SdkBridgeImpl(context: Context) {
     private var exitDialog: TipsDialog? = null
 
     private var initLoadingDialog: ScaleLoadingDialog? = null
-    private var chargeLoadingDialog: ScaleLoadingDialog? = null
 
 
     init {
@@ -90,7 +90,7 @@ class SdkBridgeImpl(context: Context) {
     fun initApplication(application: Application) {
         Logger.i("EYuanGameSdk initApplication ...")
         MMKVUtils.instance.init(application)
-        Linking.instance.attach(application)
+        Linking.instance.initialize(application)
     }
 
     fun initialize(activity: Activity, isLandscape: Boolean, callback: ICallback, initCallback: IInitialize) {
@@ -156,6 +156,7 @@ class SdkBridgeImpl(context: Context) {
                 if (resultInfo.code == 1 && !TextUtils.isEmpty(resultInfo.data)) {
                     initBean = InitBean.toBean(resultInfo.data)
                     //TODO 下载图片资源
+                    Linking.instance.create(activity)
                     showInitDialog(activity, callback, initCallback)
                     FloatCenterServiceManager.instance.init(activity)
                 } else {
@@ -220,6 +221,12 @@ class SdkBridgeImpl(context: Context) {
         LoginActivity.login(activity, isAutoLogin, object : IImplCallback {
             override fun onResult(code: Int, result: String) {
                 Logger.d("onResult code : $code , result : $result")
+                if (code == 0) {
+                    if (SdkBackLoginInfo.instance.isRegUser) {
+                        Linking.instance.register(activity)
+                    }
+                    Linking.instance.login(activity)
+                }
                 callback.onResult(code, result)
             }
         })
@@ -267,6 +274,9 @@ class SdkBridgeImpl(context: Context) {
         if (isIab) {
             ChargeImpl.instance.charge(activity, innerChargeInfo, object : IImplCallback {
                 override fun onResult(code: Int, result: String) {
+                    if (code == 0) {
+                        Linking.instance.charge(activity, innerChargeInfo.amount)
+                    }
                     callback.onResult(code, result)
                 }
             })
@@ -278,23 +288,27 @@ class SdkBridgeImpl(context: Context) {
 
     fun roleCreate(activity: Activity, roleInfo: SdkRoleInfo) {
         Logger.i("EYuanGameSdk roleCreate ...")
-        submitRoleData(activity, 0, roleInfo)
+        Linking.instance.roleCreate(activity)
+        isSubmitRoleData = true
     }
 
     fun roleLauncher(activity: Activity, roleInfo: SdkRoleInfo) {
         Logger.i("EYuanGameSdk roleLauncher ...")
-        submitRoleData(activity, 1, roleInfo)
+        Linking.instance.roleLauncher(activity)
+        isSubmitRoleData = true
+
     }
 
     fun roleLevelUp(activity: Activity, roleInfo: SdkRoleInfo) {
         Logger.i("EYuanGameSdk roleLevelUp ...")
     }
 
+    @Deprecated("暂时不需要向服务端上报角色信息")
     private fun submitRoleData(activity: Activity, timing: Int, roleInfo: SdkRoleInfo) {
         isSubmitRoleData = true
         SdkRequest.instance.submitRoleData(activity, timing, roleInfo, object : IRequestCallback {
             override fun onResponse(resultInfo: ResultInfo) {
-
+                Logger.d("submitRoleData code : ${resultInfo.code} , msg : ${resultInfo.msg}")
             }
 
         })
@@ -342,11 +356,13 @@ class SdkBridgeImpl(context: Context) {
     fun onResume(activity: Activity) {
         Logger.i("EYuanGameSdk onResume ...")
         FloatCenterServiceManager.instance.attach()
+        Linking.instance.resume(activity)
     }
 
     fun onPause(activity: Activity) {
         Logger.i("EYuanGameSdk onPause ...")
         FloatCenterServiceManager.instance.detach()
+        Linking.instance.pause(activity)
     }
 
     fun onStop(activity: Activity) {
@@ -356,7 +372,7 @@ class SdkBridgeImpl(context: Context) {
     fun onDestroy(activity: Activity) {
         Logger.i("EYuanGameSdk onDestroy ...")
         FloatCenterServiceManager.instance.release()
-        Linking.instance.detach()
+        Linking.instance.release()
     }
 
     fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, intent: Intent) {
@@ -372,6 +388,11 @@ class SdkBridgeImpl(context: Context) {
         return SdkBackLoginInfo.instance.userId
     }
 
+    fun linkingEvent(context: Context, sdkEvent: SdkEvent) {
+        Logger.i("EYuanGameSdk linkingEvent ...")
+        Linking.instance.extEvent(context, sdkEvent)
+    }
+
     private fun showInitLoadingDialog(context: Context) {
         initLoadingDialog?.apply {
             dismiss()

+ 64 - 33
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/iab/ChargeImpl.kt

@@ -43,6 +43,7 @@ class ChargeImpl : InAppBilling() {
     }
 
     override fun chargePurchasesUpdated(activity: Activity, purchase: Purchase) {
+        Logger.d("chargePurchasesUpdated")
         notifyOrder2Backend(activity, chargeInfo.orderId, purchase, false)
     }
 
@@ -57,37 +58,68 @@ class ChargeImpl : InAppBilling() {
      */
     override fun queryChargeInfo(activity: Activity) {
         billingClient?.apply {
-            queryPurchasesAsync(BillingClient.SkuType.INAPP, object : PurchasesResponseListener {
-                override fun onQueryPurchasesResponse(billingResult: BillingResult, list: MutableList<Purchase>) {
-                    logBillingResult("onQueryPurchasesResponse", billingResult)
-                    if (list.isNullOrEmpty()) {
-                        //正常发起支付流程
-                        Logger.d("正常发起支付流程")
-                        querySkuDetails(activity)
-                    } else {
-                        Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
-                        run breaking@{
-                            list.forEach { purchase ->
-                                purchase.skus.forEach {
-                                    if (it.equals(SdkBridgeImpl.initBean.rewardId)) {
-                                        Logger.e("存在阻塞的预注册奖励,停止支付流程")
-                                        if (list.size == 1) {
-                                            dismissDialog()
-                                            disConnection()
-                                            ToastUtils.toastInfo(activity, "In-app Billing has some error , please restart app and try again")
-                                            implCallback.onResult(-1, "存在阻塞的预注册奖励,停止支付流程")
-                                        }
-                                        //跳出支付流程
-                                        return@breaking
-                                    } else {
-                                        consumeCacheOrder(activity, purchase)
-                                    }
+            val list = queryPurchases(BillingClient.SkuType.INAPP).purchasesList
+            if (list.isNullOrEmpty()) {
+                //正常发起支付流程
+                querySkuDetails(activity)
+            } else {
+                Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
+                run breaking@{
+                    if (list.size > 0) {
+                        list.forEach { purchase ->
+                            if (purchase.sku == SdkBridgeImpl.initBean.rewardId) {
+                                Logger.e("存在阻塞的预注册奖励,停止支付流程")
+                                if (list.size == 1) {
+                                    dismissDialog()
+                                    disConnection()
+                                    ToastUtils.toastInfo(activity, "In-app Billing has some error , please restart app and try again")
+                                    implCallback.onResult(-1, "存在阻塞的预注册奖励,停止支付流程")
                                 }
+                                //跳出支付流程
+                                return@breaking
+                            } else {
+                                consumeCacheOrder(activity, purchase)
                             }
                         }
+                    } else {
+                        //发起正常支付流程
+                        querySkuDetails(activity)
                     }
                 }
-            })
+            }
+
+
+//            queryPurchasesAsync(BillingClient.SkuType.INAPP, object : PurchasesResponseListener {
+//                override fun onQueryPurchasesResponse(billingResult: BillingResult, list: MutableList<Purchase>) {
+//                    logBillingResult("onQueryPurchasesResponse", billingResult)
+//                    if (list.isNullOrEmpty()) {
+//                        //正常发起支付流程
+//                        Logger.d("正常发起支付流程")
+//                        querySkuDetails(activity)
+//                    } else {
+//                        Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
+//                        run breaking@{
+//                            list.forEach { purchase ->
+//                                purchase.skus.forEach {
+//                                    if (it.equals(SdkBridgeImpl.initBean.rewardId)) {
+//                                        Logger.e("存在阻塞的预注册奖励,停止支付流程")
+//                                        if (list.size == 1) {
+//                                            dismissDialog()
+//                                            disConnection()
+//                                            ToastUtils.toastInfo(activity, "In-app Billing has some error , please restart app and try again")
+//                                            implCallback.onResult(-1, "存在阻塞的预注册奖励,停止支付流程")
+//                                        }
+//                                        //跳出支付流程
+//                                        return@breaking
+//                                    } else {
+//                                        consumeCacheOrder(activity, purchase)
+//                                    }
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
+//            })
         }
     }
 
@@ -254,7 +286,7 @@ class ChargeImpl : InAppBilling() {
         val consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchase.purchaseToken).build()
         billingClient?.apply {
             if (isReady) {
-                consumeAsync(consumeParams) { billingResult, _ ->
+                consumeAsync(consumeParams) { billingResult, token ->
                     logBillingResult("onConsumeResponse", billingResult)
                     dismissDialog()
                     if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
@@ -262,15 +294,14 @@ class ChargeImpl : InAppBilling() {
                         if (isCache) {
                             querySkuDetails(activity)
                         } else {
-                            disConnection()
                             implCallback.onResult(0, "支付成功")
+                            disConnection()
                         }
                         removeOrderInfo(purchase.orderId)
                     } else {
-                        disConnection()
                         implCallback.onResult(-1, "消耗订单异常")
+                        disConnection()
                         ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
-
                     }
                 }
             } else {
@@ -284,14 +315,14 @@ class ChargeImpl : InAppBilling() {
 
     private fun saveOrderInfo(googleOrderId: String, orderId: String) {
         try {
-            MMKVUtils.instance.orderKV?.encode(googleOrderId, orderId)
+            MMKVUtils.instance.orderKV.encode(googleOrderId, orderId)
         } catch (e: JSONException) {
             e.printStackTrace()
         }
     }
 
     private fun getOrderInfo(googleOrderId: String): String {
-        val info = MMKVUtils.instance.orderKV?.decodeString(googleOrderId)
+        val info = MMKVUtils.instance.orderKV.decodeString(googleOrderId)
         Logger.d("getOrderInfo : $info")
         return if (TextUtils.isEmpty(info)) {
             ""
@@ -301,7 +332,7 @@ class ChargeImpl : InAppBilling() {
     }
 
     private fun removeOrderInfo(googleOrderId: String) {
-        MMKVUtils.instance.orderKV?.removeValueForKey(googleOrderId)
+        MMKVUtils.instance.orderKV.removeValueForKey(googleOrderId)
     }
 
 

+ 13 - 13
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/iab/InAppBilling.kt

@@ -5,6 +5,7 @@ import android.content.Context
 import cn.yyxx.eyuangame.base.utils.Logger
 import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
 import cn.yyxx.eyuangame.core.ui.dialog.ScaleLoadingDialog
+import cn.yyxx.support.ResUtils
 import com.android.billingclient.api.BillingClient
 import com.android.billingclient.api.BillingClientStateListener
 import com.android.billingclient.api.BillingResult
@@ -31,22 +32,21 @@ abstract class InAppBilling {
     protected fun initializeBillingClient(activity: Activity) {
         billingClient = BillingClient.newBuilder(activity).setListener { billingResult, list ->
             //谷歌支付结果在这里回调
+            logBillingResult("onPurchasesUpdated", billingResult)
             if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
-                if (list.isNullOrEmpty()) {
-                    purchasesUpdatedFailed()
-                } else {
+                if (list != null && list.size > 0) {
+                    Logger.d(list.size)
                     for (purchase in list) {
-                        Logger.d(purchase.toString())
-                        purchase.skus.forEach {
-                            if (it.equals(SdkBridgeImpl.initBean.rewardId)) {
-                                //预注册
-                                preRewardPurchasesUpdated(activity, purchase)
-                            } else {
-                                //支付
-                                chargePurchasesUpdated(activity, purchase)
-                            }
+                        if (purchase.sku == SdkBridgeImpl.initBean.rewardId) {
+                            //预注册
+                            preRewardPurchasesUpdated(activity, purchase)
+                        } else {
+                            //支付
+                            chargePurchasesUpdated(activity, purchase)
                         }
                     }
+                } else {
+                    purchasesUpdatedFailed()
                 }
             } else {
                 purchasesUpdatedFailed()
@@ -111,7 +111,7 @@ abstract class InAppBilling {
             loadingDialog = null
         }
 
-        loadingDialog = ScaleLoadingDialog(context, "")
+        loadingDialog = ScaleLoadingDialog(context, ResUtils.getResString(context, "yyxx_charge_loading_tips"))
         loadingDialog?.show()
     }
 

+ 5 - 1
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/login/LoginActivity.kt

@@ -11,6 +11,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.content.ContextCompat
 import androidx.core.view.ViewCompat
 import androidx.fragment.app.FragmentActivity
+import cn.yyxx.eyuangame.base.entity.SdkEvent
 import cn.yyxx.eyuangame.base.utils.Logger
 import cn.yyxx.eyuangame.core.entity.ClickType
 import cn.yyxx.eyuangame.core.entity.LoginType
@@ -18,10 +19,10 @@ import cn.yyxx.eyuangame.core.entity.Session
 import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
 import cn.yyxx.eyuangame.core.impl.login.fragment.LauncherFragment
 import cn.yyxx.eyuangame.core.internal.IImplCallback
+import cn.yyxx.eyuangame.core.linking.Linking
 import cn.yyxx.eyuangame.core.ui.NoScrollViewPager
 import cn.yyxx.eyuangame.core.ui.dialog.AutoLoginDialog
 import cn.yyxx.eyuangame.core.ui.dialog.ChooseLoginDialog
-import cn.yyxx.eyuangame.core.ui.dialog.ScaleLoadingDialog
 import cn.yyxx.eyuangame.core.utils.SessionUtils
 import cn.yyxx.eyuangame.core.utils.TimeDownUtils
 import cn.yyxx.support.AndroidBug5497Workaround
@@ -196,6 +197,9 @@ class LoginActivity : FragmentActivity(), View.OnClickListener {
 
             })
             show()
+            val sdkEvent = SdkEvent()
+            sdkEvent.eventName = "choose_login_page"
+            Linking.instance.sdkEvent(this@LoginActivity, sdkEvent)
         }
 
     }

+ 18 - 3
library_core/src/main/java/cn/yyxx/eyuangame/core/internal/IEventObserver.kt

@@ -1,6 +1,9 @@
 package cn.yyxx.eyuangame.core.internal
 
+import android.app.Activity
+import android.app.Application
 import android.content.Context
+import cn.yyxx.eyuangame.base.entity.SdkEvent
 
 /**
  * @author #Suyghur.
@@ -8,14 +11,26 @@ import android.content.Context
  */
 interface IEventObserver {
 
-    fun onInitialize(context: Context)
+    fun onInitialize(application: Application)
 
     fun onLogin(context: Context)
 
     fun onRegister(context: Context)
 
-    fun onCharge(context: Context)
+    fun onCharge(context: Context, amount: Int)
 
-    fun onEvent(context: Context)
+    fun onRoleCreate(context: Context)
+
+    fun onRoleLauncher(context: Context)
+
+    fun onCreate(activity: Activity)
+
+    fun onResume(activity: Activity)
+
+    fun onPause(activity: Activity)
+
+    fun onSdkEvent(context: Context, sdkEvent: SdkEvent)
+
+    fun onExtEvent(context: Context, sdkEvent: SdkEvent)
 
 }

+ 39 - 8
library_core/src/main/java/cn/yyxx/eyuangame/core/linking/Linking.kt

@@ -1,6 +1,9 @@
 package cn.yyxx.eyuangame.core.linking
 
+import android.app.Activity
+import android.app.Application
 import android.content.Context
+import cn.yyxx.eyuangame.base.entity.SdkEvent
 import cn.yyxx.eyuangame.core.internal.IEventObserver
 import cn.yyxx.eyuangame.core.linking.channel.LinkingAdjustImpl
 import cn.yyxx.eyuangame.core.linking.channel.LinkingFacebookImpl
@@ -14,14 +17,18 @@ class Linking private constructor() {
 
     private val observers: MutableList<IEventObserver> = mutableListOf()
 
-    fun attach(context: Context) {
+    fun initialize(application: Application) {
         observers.add(LinkingAdjustImpl())
         observers.add(LinkingFirebaseImpl())
         observers.add(LinkingFacebookImpl())
+
+        for (ob in observers) {
+            ob.onInitialize(application)
+        }
     }
 
 
-    fun detach() {
+    fun release() {
         if (!observers.isNullOrEmpty()) {
             observers.clear()
         }
@@ -40,27 +47,51 @@ class Linking private constructor() {
         }
     }
 
-    fun charge(context: Context) {
+    fun charge(context: Context, amount: Int) {
         for (ob in observers) {
-            ob.onCharge(context)
+            ob.onCharge(context, amount)
         }
     }
 
     fun roleCreate(context: Context) {
         for (ob in observers) {
-            ob.onCharge(context)
+            ob.onRoleCreate(context)
         }
     }
 
     fun roleLauncher(context: Context) {
         for (ob in observers) {
-            ob.onCharge(context)
+            ob.onRoleLauncher(context)
+        }
+    }
+
+    fun create(activity: Activity) {
+        for (ob in observers) {
+            ob.onCreate(activity)
+        }
+    }
+
+    fun resume(activity: Activity) {
+        for (ob in observers) {
+            ob.onResume(activity)
+        }
+    }
+
+    fun pause(activity: Activity) {
+        for (ob in observers) {
+            ob.onPause(activity)
+        }
+    }
+
+    fun sdkEvent(context: Context, sdkEvent: SdkEvent) {
+        for (ob in observers) {
+            ob.onSdkEvent(context, sdkEvent)
         }
     }
 
-    fun event(context: Context) {
+    fun extEvent(context: Context, sdkEvent: SdkEvent) {
         for (ob in observers) {
-            ob.onEvent(context)
+            ob.onExtEvent(context, sdkEvent)
         }
     }
 

+ 261 - 3
library_core/src/main/java/cn/yyxx/eyuangame/core/linking/channel/LinkingAdjustImpl.kt

@@ -1,7 +1,24 @@
 package cn.yyxx.eyuangame.core.linking.channel
 
+import android.app.Activity
+import android.app.Application
 import android.content.Context
+import android.text.TextUtils
+import cn.yyxx.eyuangame.base.entity.SdkEvent
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.eyuangame.base.utils.ParamsUtils
+import cn.yyxx.eyuangame.core.entity.LoginType
+import cn.yyxx.eyuangame.core.entity.SdkBackLoginInfo
 import cn.yyxx.eyuangame.core.internal.IEventObserver
+import cn.yyxx.eyuangame.core.utils.MMKVUtils
+import cn.yyxx.support.JsonUtils
+import com.adjust.sdk.Adjust
+import com.adjust.sdk.AdjustConfig
+import com.adjust.sdk.AdjustEvent
+import com.adjust.sdk.LogLevel
+import org.json.JSONObject
+import java.io.BufferedReader
+import java.io.InputStreamReader
 
 /**
  * @author #Suyghur.
@@ -9,19 +26,260 @@ import cn.yyxx.eyuangame.core.internal.IEventObserver
  */
 class LinkingAdjustImpl : IEventObserver {
 
-    override fun onInitialize(context: Context) {
+    private var isInitSuccess = false
+    private var sdkConfig: JSONObject? = null
+    private var extConfig: JSONObject? = null
+
+
+    override fun onInitialize(application: Application) {
+
+        this.sdkConfig = getSdkLogJson(application)
+        this.extConfig = getExtLogJson(application)
+
+        if (sdkConfig == null) {
+            Logger.e("adjust log 初始化失败,读取sdk_log.json异常")
+            return
+        }
+
+        val appId = ParamsUtils.getAdjustAppId(application)
+        if (TextUtils.isEmpty(appId)) {
+            Logger.e("adjust log 初始化失败,app id为空")
+            isInitSuccess = false
+            return
+        }
+
+        val config = AdjustConfig(application, appId, AdjustConfig.ENVIRONMENT_PRODUCTION, true)
+        config.setLogLevel(LogLevel.VERBOSE)
+        Adjust.onCreate(config)
+        if (MMKVUtils.instance.eventKV.decodeBool("adjust_activities")) {
+            isInitSuccess = true
+            return
+        }
+        sdkConfig?.apply {
+            if (JsonUtils.hasJsonKey(this, "open_app")) {
+                Adjust.trackEvent(AdjustEvent(this.getString("open_app")))
+                Logger.d("adjust log open app success")
+                MMKVUtils.instance.eventKV.encode("adjust_activities", true)
+                isInitSuccess = true
+            }
+        }
     }
 
     override fun onLogin(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("adjust log failed , user is null")
+            return
+        }
+
+        sdkConfig?.apply {
+            when (SdkBackLoginInfo.instance.loginType) {
+                LoginType.TYPE_GUEST_LOGIN -> {
+                    if (JsonUtils.hasJsonKey(this, "login_success_quick")) {
+                        Adjust.trackEvent(AdjustEvent(this.getString("login_success_quick")))
+                        Logger.d("adjust log guest login success")
+                    }
+                }
+                LoginType.TYPE_FACEBOOK_LOGIN -> {
+                    if (JsonUtils.hasJsonKey(this, "login_success_fb")) {
+                        Adjust.trackEvent(AdjustEvent(this.getString("login_success_fb")))
+                        Logger.d("adjust log facebook login success")
+                    }
+                }
+                LoginType.TYPE_GOOGLE_LOGIN -> {
+                    if (JsonUtils.hasJsonKey(this, "login_success_google")) {
+                        Adjust.trackEvent(AdjustEvent(this.getString("login_success_google")))
+                        Logger.d("adjust log google login success")
+                    }
+                }
+                LoginType.TYPE_ACCOUNT_LOGIN -> {
+                    if (JsonUtils.hasJsonKey(this, "login_success_account")) {
+                        Adjust.trackEvent(AdjustEvent(this.getString("login_success_account")))
+                        Logger.d("adjust log account login success")
+                    }
+                }
+            }
+        }
     }
 
     override fun onRegister(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("adjust log failed , user is null")
+            return
+        }
+
+        sdkConfig?.apply {
+            if (JsonUtils.hasJsonKey(this, "sign_up")) {
+                Adjust.trackEvent(AdjustEvent(this.getString("sign_up")))
+                Logger.d("adjust log register success")
+            }
+        }
+    }
+
+    override fun onCharge(context: Context, amount: Int) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("adjust log failed , user is null")
+            return
+        }
+
+        sdkConfig?.apply {
+            if (!MMKVUtils.instance.eventKV.decodeBool("adjust_first_purchase")) {
+                if (JsonUtils.hasJsonKey(this, "first_purchase")) {
+                    val event = AdjustEvent(this.getString("first_purchase"))
+                    event.setRevenue(amount.toDouble(), "USD")
+                    Adjust.trackEvent(event)
+                    Logger.d("adjust log first charge success")
+                    MMKVUtils.instance.eventKV.encode("adjust_first_purchase", true)
+                }
+            }
+
+            if (JsonUtils.hasJsonKey(this, "ecommerce_purchase")) {
+                val event = AdjustEvent(this.getString("ecommerce_purchase"))
+                event.setRevenue(amount.toDouble(), "USD")
+                Adjust.trackEvent(event)
+                Logger.d("adjust log charge success")
+            }
+        }
+    }
+
+    override fun onRoleCreate(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("adjust log failed , user is null")
+            return
+        }
+
+        sdkConfig?.apply {
+            if (JsonUtils.hasJsonKey(this, "create_player")) {
+                Adjust.trackEvent(AdjustEvent(this.getString("create_player")))
+                Logger.d("adjust log create player success")
+            }
+        }
     }
 
-    override fun onCharge(context: Context) {
+    override fun onRoleLauncher(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("adjust log failed , user is null")
+            return
+        }
+
+        sdkConfig?.apply {
+            if (JsonUtils.hasJsonKey(this, "enter_game")) {
+                Adjust.trackEvent(AdjustEvent(this.getString("enter_game")))
+                Logger.d("adjust log enter game success")
+            }
+        }
     }
 
-    override fun onEvent(context: Context) {
+    override fun onCreate(activity: Activity) {
+    }
+
+    override fun onResume(activity: Activity) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+        Adjust.onResume()
+    }
+
+    override fun onPause(activity: Activity) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+        Adjust.onPause()
+    }
+
+    override fun onSdkEvent(context: Context, sdkEvent: SdkEvent) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+
+        sdkConfig?.apply {
+            if (JsonUtils.hasJsonKey(this, sdkEvent.eventName)) {
+                Adjust.trackEvent(AdjustEvent(this.getString(sdkEvent.eventName)))
+                Logger.d("adjust log sdk event ${sdkEvent.eventName} success")
+            }
+        }
+    }
+
+    override fun onExtEvent(context: Context, sdkEvent: SdkEvent) {
+        if (!isInitSuccess) {
+            Logger.e("adjust log failed , component initialize failed")
+            return
+        }
+
+        extConfig?.apply {
+            if (JsonUtils.hasJsonKey(this, sdkEvent.eventName)) {
+                Adjust.trackEvent(AdjustEvent(this.getString(sdkEvent.eventName)))
+                Logger.d("adjust log ext event ${sdkEvent.eventName} success")
+            }
+        }
+    }
+
+    private fun getSdkLogJson(context: Context): JSONObject? {
+        val path = "yyxx_game/sdk_log.json"
+        val sb = StringBuilder()
+        try {
+            val assetManager = context.assets
+            BufferedReader(InputStreamReader(assetManager.open(path))).use {
+                var line = ""
+                while (true) {
+                    line = it.readLine() ?: break
+                    sb.append(line)
+                }
+            }
+            if (!TextUtils.isEmpty(sb.toString())) {
+                return JSONObject(sb.toString())
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+        return null
+    }
 
+    private fun getExtLogJson(context: Context): JSONObject? {
+        val path = "yyxx_game/ext_log.json"
+        val sb = StringBuilder()
+        try {
+            val assetManager = context.assets
+            BufferedReader(InputStreamReader(assetManager.open(path))).use {
+                var line = ""
+                while (true) {
+                    line = it.readLine() ?: break
+                    sb.append(line)
+                }
+            }
+            if (!TextUtils.isEmpty(sb.toString())) {
+                return JSONObject(sb.toString())
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+        return null
     }
 }

+ 167 - 4
library_core/src/main/java/cn/yyxx/eyuangame/core/linking/channel/LinkingFacebookImpl.kt

@@ -1,7 +1,21 @@
 package cn.yyxx.eyuangame.core.linking.channel
 
+import android.app.Activity
+import android.app.Application
 import android.content.Context
+import android.text.TextUtils
+import cn.yyxx.eyuangame.base.entity.SdkEvent
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.eyuangame.core.entity.LoginType
+import cn.yyxx.eyuangame.core.entity.SdkBackLoginInfo
 import cn.yyxx.eyuangame.core.internal.IEventObserver
+import cn.yyxx.eyuangame.core.utils.MMKVUtils
+import com.facebook.FacebookSdk
+import com.facebook.LoggingBehavior
+import com.facebook.appevents.AppEventsConstants
+import com.facebook.appevents.AppEventsLogger
+import java.math.BigDecimal
+import java.util.*
 
 /**
  * @author #Suyghur.
@@ -9,19 +23,168 @@ import cn.yyxx.eyuangame.core.internal.IEventObserver
  */
 class LinkingFacebookImpl : IEventObserver {
 
-    override fun onInitialize(context: Context) {
+    private lateinit var fbLogger: AppEventsLogger
+    private var isInitSuccess = false
+
+    override fun onInitialize(application: Application) {
+
+        FacebookSdk.setIsDebugEnabled(true)
+        FacebookSdk.addLoggingBehavior(LoggingBehavior.APP_EVENTS)
+
+        fbLogger = AppEventsLogger.newLogger(application)
+
+        if (MMKVUtils.instance.eventKV.decodeBool("facebook_activities")) {
+            isInitSuccess = true
+            return
+        }
+        fbLogger.logEvent("open_app")
+        Logger.d("facebook log open app success")
+        MMKVUtils.instance.eventKV.encode("facebook_activities", true)
+        isInitSuccess = true
     }
 
     override fun onLogin(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("facebook log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("facebook log failed , user is null")
+            return
+        }
+
+        when (SdkBackLoginInfo.instance.loginType) {
+            LoginType.TYPE_GUEST_LOGIN -> {
+                fbLogger.logEvent("login_success_quick")
+                Logger.d("facebook log guest login success")
+            }
+            LoginType.TYPE_FACEBOOK_LOGIN -> {
+                fbLogger.logEvent("login_success_fb")
+                Logger.d("facebook log facebook login success")
+            }
+            LoginType.TYPE_GOOGLE_LOGIN -> {
+                fbLogger.logEvent("login_success_google")
+                Logger.d("facebook log google login success")
+            }
+            LoginType.TYPE_ACCOUNT_LOGIN -> {
+                fbLogger.logEvent("login_success_account")
+                Logger.d("facebook log account login success")
+            }
+        }
     }
 
     override fun onRegister(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("facebook log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("facebook log failed , user is null")
+            return
+        }
+
+        fbLogger.logEvent(AppEventsConstants.EVENT_NAME_COMPLETED_REGISTRATION)
+        Logger.d("facebook log sign up success")
     }
 
-    override fun onCharge(context: Context) {
+    override fun onCharge(context: Context, amount: Int) {
+        if (!isInitSuccess) {
+            Logger.e("facebook log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("facebook log failed , user is null")
+            return
+        }
+
+        if (!MMKVUtils.instance.eventKV.decodeBool("facebook_first_purchase")) {
+            fbLogger.logEvent("first_purchase", amount.toDouble())
+            Logger.d("facebook log first charge success")
+            MMKVUtils.instance.eventKV.encode("facebook_first_purchase", true)
+        }
+
+        fbLogger.logPurchase(BigDecimal.valueOf(amount.toDouble()), Currency.getInstance("USD"))
+        Logger.d("facebook log charge success")
     }
 
-    override fun onEvent(context: Context) {
+    override fun onRoleCreate(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("facebook log failed , component initialize failed")
+            return
+        }
 
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("facebook log failed , user is null")
+            return
+        }
+        fbLogger.logEvent("create_player")
+        Logger.d("facebook log create player success")
     }
-}
+
+    override fun onRoleLauncher(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("facebook log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("facebook log failed , user is null")
+            return
+        }
+        fbLogger.logEvent("enter_game")
+        Logger.d("facebook log create player success")
+    }
+
+    override fun onCreate(activity: Activity) {
+        if (!isInitSuccess) {
+            Logger.e("facebook log failed , component initialize failed")
+            return
+        }
+        AppEventsLogger.activateApp(activity.application)
+    }
+
+    override fun onResume(activity: Activity) {
+    }
+
+    override fun onPause(activity: Activity) {
+    }
+
+    override fun onSdkEvent(context: Context, sdkEvent: SdkEvent) {
+        if (!isInitSuccess) {
+            Logger.e("facebook log failed , component initialize failed")
+            return
+        }
+        fbLogger.logEvent(sdkEvent.eventName)
+        Logger.d("facebook log sdk event ${sdkEvent.eventName} success")
+    }
+
+    override fun onExtEvent(context: Context, sdkEvent: SdkEvent) {
+        if (!isInitSuccess) {
+            Logger.e("facebook log failed , component initialize failed")
+            return
+        }
+        if (sdkEvent.standard) {
+            val eventName = when (sdkEvent.fbAliasName) {
+                "fb_mobile_tutorial_completion" -> AppEventsConstants.EVENT_NAME_COMPLETED_TUTORIAL
+                "fb_mobile_level_achieved" -> AppEventsConstants.EVENT_NAME_ACHIEVED_LEVEL
+                "fb_mobile_spent_credits" -> AppEventsConstants.EVENT_NAME_SPENT_CREDITS
+                "fb_mobile_add_payment_info" -> AppEventsConstants.EVENT_NAME_ADDED_PAYMENT_INFO
+                "fb_mobile_initiated_checkout" -> AppEventsConstants.EVENT_NAME_INITIATED_CHECKOUT
+                "fb_mobile_add_to_cart" -> AppEventsConstants.EVENT_NAME_ADDED_TO_CART
+                "fb_mobile_add_to_wishlist" -> AppEventsConstants.EVENT_NAME_ADDED_TO_WISHLIST
+                "fb_mobile_achievement_unlocked" -> AppEventsConstants.EVENT_NAME_UNLOCKED_ACHIEVEMENT
+                "fb_mobile_search" -> AppEventsConstants.EVENT_NAME_SEARCHED
+                "fb_mobile_rate" -> AppEventsConstants.EVENT_NAME_RATED
+                else -> ""
+            }
+            fbLogger.logEvent(eventName)
+        } else {
+            fbLogger.logEvent(sdkEvent.eventName)
+        }
+        Logger.d("facebook log ext event ${sdkEvent.eventName} success")
+    }
+}
+

+ 141 - 3
library_core/src/main/java/cn/yyxx/eyuangame/core/linking/channel/LinkingFirebaseImpl.kt

@@ -1,7 +1,19 @@
 package cn.yyxx.eyuangame.core.linking.channel
 
+import android.app.Activity
+import android.app.Application
 import android.content.Context
+import android.text.TextUtils
+import cn.yyxx.eyuangame.base.entity.SdkEvent
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.eyuangame.core.entity.LoginType
+import cn.yyxx.eyuangame.core.entity.SdkBackLoginInfo
 import cn.yyxx.eyuangame.core.internal.IEventObserver
+import cn.yyxx.eyuangame.core.utils.MMKVUtils
+import com.google.firebase.analytics.FirebaseAnalytics
+import com.google.firebase.analytics.ktx.analytics
+import com.google.firebase.analytics.ktx.logEvent
+import com.google.firebase.ktx.Firebase
 
 /**
  * @author #Suyghur.
@@ -9,18 +21,144 @@ import cn.yyxx.eyuangame.core.internal.IEventObserver
  */
 class LinkingFirebaseImpl : IEventObserver {
 
-    override fun onInitialize(context: Context) {
+    private var isInitSuccess = false
+
+    override fun onInitialize(application: Application) {
+        if (MMKVUtils.instance.eventKV.decodeBool("firebase_activities")) {
+            isInitSuccess = true
+            return
+        }
+        Firebase.analytics.logEvent("open_app", null)
+        Logger.d("firebase log open app success")
+        MMKVUtils.instance.eventKV.encode("firebase_activities", true)
+        isInitSuccess = true
     }
 
     override fun onLogin(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("firebase log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("firebase log failed , user is null")
+            return
+        }
+
+        when (SdkBackLoginInfo.instance.loginType) {
+            LoginType.TYPE_GUEST_LOGIN -> {
+                Firebase.analytics.logEvent("login_success_quick", null)
+                Logger.d("firebase log guest login success")
+            }
+            LoginType.TYPE_FACEBOOK_LOGIN -> {
+                Firebase.analytics.logEvent("login_success_fb", null)
+                Logger.d("firebase log facebook login success")
+            }
+            LoginType.TYPE_GOOGLE_LOGIN -> {
+                Firebase.analytics.logEvent("login_success_google", null)
+                Logger.d("firebase log google login success")
+            }
+            LoginType.TYPE_ACCOUNT_LOGIN -> {
+                Firebase.analytics.logEvent("login_success_account", null)
+                Logger.d("firebase log account login success")
+            }
+        }
     }
 
     override fun onRegister(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("firebase log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("firebase log failed , user is null")
+            return
+        }
+
+        Firebase.analytics.logEvent("sign_up", null)
+        Logger.d("firebase log sign up success")
+    }
+
+    override fun onCharge(context: Context, amount: Int) {
+        if (!isInitSuccess) {
+            Logger.e("firebase log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("firebase log failed , user is null")
+            return
+        }
+
+        if (!MMKVUtils.instance.eventKV.decodeBool("firebase_first_purchase")) {
+            Firebase.analytics.logEvent("first_purchase") {
+                param(FirebaseAnalytics.Param.PRICE, amount.toString())
+            }
+            Logger.d("firebase log first charge success")
+            MMKVUtils.instance.eventKV.encode("firebase_first_purchase", true)
+        }
+
+        Firebase.analytics.logEvent("ecommerce_purchase") {
+            param(FirebaseAnalytics.Param.PRICE, amount.toString())
+        }
+        Logger.d("firebase log charge success")
+
+    }
+
+    override fun onRoleCreate(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("firebase log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("firebase log failed , user is null")
+            return
+        }
+        Firebase.analytics.logEvent("create_player", null)
+        Logger.d("firebase log create player success")
+    }
+
+    override fun onRoleLauncher(context: Context) {
+        if (!isInitSuccess) {
+            Logger.e("firebase log failed , component initialize failed")
+            return
+        }
+
+        if (TextUtils.isEmpty(SdkBackLoginInfo.instance.userId)) {
+            Logger.e("firebase log failed , user is null")
+            return
+        }
+        Firebase.analytics.logEvent("enter_game", null)
+        Logger.d("firebase log enter game success")
+    }
+
+    override fun onCreate(activity: Activity) {
+    }
+
+    override fun onResume(activity: Activity) {
     }
 
-    override fun onCharge(context: Context) {
+    override fun onPause(activity: Activity) {
+    }
+
+
+    override fun onSdkEvent(context: Context, sdkEvent: SdkEvent) {
+        if (!isInitSuccess) {
+            Logger.e("firebase log failed , component initialize failed")
+            return
+        }
+        Firebase.analytics.logEvent(sdkEvent.eventName, null)
+        Logger.d("firebase log sdk event ${sdkEvent.eventName} success")
     }
 
-    override fun onEvent(context: Context) {
+    override fun onExtEvent(context: Context, sdkEvent: SdkEvent) {
+        if (!isInitSuccess) {
+            Logger.e("firebase log failed , component initialize failed")
+            return
+        }
+        Firebase.analytics.logEvent(sdkEvent.eventName, null)
+        Logger.d("firebase log ext event ${sdkEvent.eventName} success")
     }
 }

+ 1 - 1
library_core/src/main/java/cn/yyxx/eyuangame/core/network/Host.kt

@@ -31,7 +31,7 @@ object Host {
     const val BASIC_ROUTE_CREATE_ORDER = "iap_init"
     const val BASIC_ROUTE_NOTIFY_ORDER = "iap_notify"
     const val BASIC_ROUTE_NOTIFY_REWARD = ""
-    const val BASIC_ROUTE_SUBMIT_ROLE_INFO = ""
+    const val BASIC_ROUTE_SUBMIT_ROLE_INFO = "game_role_report"
 
 
     fun initHostModel(context: Context) {

+ 19 - 2
library_core/src/main/java/cn/yyxx/eyuangame/core/network/SdkRequest.kt

@@ -97,6 +97,7 @@ class SdkRequest {
     fun createOrder(context: Context, chargeInfo: SdkChargeInfo, callback: IRequestCallback) {
         val jsonObject = JSONObject()
         try {
+            jsonObject.put("route_path", Host.BASIC_ROUTE_CREATE_ORDER)
             jsonObject.put("login_type", SdkBackLoginInfo.instance.loginType)
             jsonObject.put("uid", chargeInfo.userId)
             jsonObject.put("role_id", chargeInfo.roleId)
@@ -113,7 +114,6 @@ class SdkRequest {
             jsonObject.put("cp_ext", chargeInfo.cpExt)
             jsonObject.put("cp_pay_time", chargeInfo.cpPayTime)
             jsonObject.put("cp_pay_sign", chargeInfo.cpPaySign)
-            jsonObject.put("route_path", Host.BASIC_ROUTE_CREATE_ORDER)
         } catch (e: JSONException) {
             e.printStackTrace()
         }
@@ -134,7 +134,24 @@ class SdkRequest {
     }
 
     fun submitRoleData(context: Context, timing: Int, roleInfo: SdkRoleInfo, callback: IRequestCallback) {
-
+        val jsonObject = JSONObject()
+        try {
+            jsonObject.put("route_path", Host.BASIC_ROUTE_SUBMIT_ROLE_INFO)
+            jsonObject.put("report_type", timing)
+            jsonObject.put("uid", roleInfo.userId)
+            jsonObject.put("role_id", roleInfo.roleId)
+            jsonObject.put("role_name", roleInfo.roleName)
+            jsonObject.put("role_level", roleInfo.roleLevel)
+            jsonObject.put("role_ctime", roleInfo.roleCTime)
+            jsonObject.put("server_id", roleInfo.serverId)
+            jsonObject.put("server_name", roleInfo.serverName)
+            jsonObject.put("vip_level", roleInfo.vipLevel)
+            jsonObject.put("balance", roleInfo.balance)
+            jsonObject.put("total_purchase", roleInfo.totalPurchase)
+        } catch (e: JSONException) {
+            e.printStackTrace()
+        }
+        VolleyRequest.post(context, jsonObject, callback)
     }
 
     companion object {

+ 1 - 7
library_core/src/main/java/cn/yyxx/eyuangame/core/network/VolleyRequest.kt

@@ -62,6 +62,7 @@ object VolleyRequest {
                 val resultInfo = ResultInfo()
                 resultInfo.code = -1
                 resultInfo.msg = "接口请求异常"
+                Logger.d(it)
                 it?.apply {
                     try {
                         resultInfo.code = it.getInt("code")
@@ -75,7 +76,6 @@ object VolleyRequest {
 //                            responseObj.put("p", hexP2)
 //                            SdkDrive.parseJob(context, responseObj.toString())
                             parseResponse(context, it.getJSONObject("data"))
-
                         } else {
                             ""
                         }
@@ -111,12 +111,6 @@ object VolleyRequest {
 
     private fun parseResponse(context: Context, data: JSONObject): String {
         try {
-//            val p = data.getString("p")
-//            val ts = data.getString("ts")
-//            val aesKey = Md5Utils.encodeByMD5(ts + StrUtils.reverseString(ts))
-//            return AesUtils.decrypt(aesKey.substring(8, 24), p)
-//            return SdkDrive.parseJob()
-//                            val p = data.getString("p")
             val ts = data.getString("ts")
             val aesKey = Md5Utils.encodeByMD5(ts + StrUtils.reverseString(ts))
             val base64P = data.getString("p")

+ 4 - 2
library_core/src/main/java/cn/yyxx/eyuangame/core/ui/dialog/ScaleLoadingDialog.kt

@@ -41,8 +41,9 @@ class ScaleLoadingDialog constructor(context: Context, desc: String) : Dialog(co
         val viewSize = DensityUtils.dip2px(context, 60f)
         val divideSize = DensityUtils.dip2px(context, 3f)
         val count = 5
-        val color = Color.parseColor("#1DB1AD")
-        loadingView = ScaleLoadingView(context, viewSize, divideSize, count, color)
+        val startColor = Color.parseColor("#7EB944")
+        val endColor = Color.parseColor("#1DB1AD")
+        loadingView = ScaleLoadingView(context, viewSize, divideSize, count, startColor, endColor)
         val loadingViewParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
         loadingViewParams.gravity = Gravity.CENTER
         layout.addView(loadingView, loadingViewParams)
@@ -50,6 +51,7 @@ class ScaleLoadingDialog constructor(context: Context, desc: String) : Dialog(co
         if (!TextUtils.isEmpty(desc)) {
             val textView = TextView(context)
             textView.text = desc
+            textView.setTextColor(Color.WHITE)
             val textViewParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
             textViewParams.gravity = Gravity.CENTER
             layout.addView(textView, textViewParams)

+ 4 - 2
library_core/src/main/java/cn/yyxx/eyuangame/core/utils/MMKVUtils.kt

@@ -15,8 +15,9 @@ import java.io.File
  */
 class MMKVUtils private constructor() : MMKVHandler {
 
-    var userKV: MMKV? = null
-    var orderKV: MMKV? = null
+    lateinit var userKV: MMKV
+    lateinit var orderKV: MMKV
+    lateinit var eventKV: MMKV
 
     fun init(context: Context) {
         val dir = context.getExternalFilesDir("")!!.absolutePath + File.separator + "/sdk_info"
@@ -24,6 +25,7 @@ class MMKVUtils private constructor() : MMKVHandler {
         MMKV.registerHandler(this)
         userKV = MMKV.mmkvWithID("user_info")
         orderKV = MMKV.mmkvWithID("order_info")
+        eventKV = MMKV.mmkvWithID("event_info")
     }
 
     override fun onMMKVCRCCheckFail(mmapID: String?): MMKVRecoverStrategic {

+ 3 - 3
library_core/src/main/java/cn/yyxx/eyuangame/core/utils/SessionUtils.kt

@@ -57,7 +57,7 @@ class SessionUtils private constructor() {
                 HostModelUtils.ENV_TEST -> "test"
                 else -> "online"
             }
-            MMKVUtils.instance.userKV?.encode(keyName, jsonObject.toString())
+            MMKVUtils.instance.userKV.encode(keyName, jsonObject.toString())
 //            FileUtils.writeFile(jsonObject.toString(), filePath)
         }
     }
@@ -102,7 +102,7 @@ class SessionUtils private constructor() {
             HostModelUtils.ENV_TEST -> "test"
             else -> "online"
         }
-        val json = MMKVUtils.instance.userKV?.decodeString(keyName)
+        val json = MMKVUtils.instance.userKV.decodeString(keyName)
 //        val json = FileUtils.readFile(FileUtils.getUserInfoFilePath(context))
         return if (TextUtils.isEmpty(json)) {
             mutableListOf()
@@ -151,7 +151,7 @@ class SessionUtils private constructor() {
             HostModelUtils.ENV_TEST -> "test"
             else -> "online"
         }
-        MMKVUtils.instance.userKV?.encode(keyName, jsonObject.toString())
+        MMKVUtils.instance.userKV.encode(keyName, jsonObject.toString())
 //        FileUtils.writeFile(jsonObject.toString(), filePath)
     }
 

BIN
libs/yyxx_support_1.0.1.jar