Browse Source

dev开发:测试jenkins构建

#Suyghur 3 years ago
parent
commit
06e6bdb50c

+ 5 - 2
build.gradle

@@ -1,11 +1,14 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 buildscript {
 
+    // demo远程依赖
+    ext.REMOTE_LIBRARY = false
+    // 发布开关
     ext.PUBLISH_ENABLE = false
     // 混淆开关
     ext.MINIFY_ENABLE = true
     // ndk版本
-    ext.NDK_VERSION = '21.3.6528147'
+    ext.NDK_VERSION = '21.4.7075529'
     // kotlin版本
     ext.KOTLIN_VERSION = '1.4.20'
     // compileSdkVersion
@@ -27,7 +30,7 @@ buildscript {
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
 //        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
         //jitpack
-        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
+//        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files

+ 39 - 31
demo/build.gradle

@@ -71,37 +71,45 @@ android {
 
 dependencies {
 
-    api project(':library_core')
-//    implementation 'io.github.yyxxgame.sdk:eyuangame-sdk-ktx:0.0.1'
-
-//    //mmkv
-//    implementation 'com.tencent:mmkv-static:1.2.10'
-//
-//    //日志采集框架
-//    implementation 'io.github.suyghur.dolin:zap:1.0.0'
-//
-//    implementation 'androidx.core:core-ktx:1.6.0'
-//    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'
-//    //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:8.2.0'
-//
-//    //adjust
-//    implementation 'com.adjust.sdk:adjust-android:4.28.2'
-//
-//    api(name: 'library_core-release', ext: 'aar')
+    if (PUBLISH_ENABLE) {
+        if (REMOTE_LIBRARY) {
+            implementation 'io.github.yyxxgame.sdk:eyuangame-sdk-ktx:0.0.1'
+        } else {
+            api(name: 'library_core-release', ext: 'aar')
+
+            implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
+
+            //mmkv
+            implementation 'com.tencent:mmkv-static:1.2.10'
+
+            //日志采集框架
+            implementation 'io.github.suyghur.dolin:zap:1.0.0'
+
+            implementation 'androidx.core:core-ktx:1.6.0'
+            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'
+            //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'
+            implementation 'com.google.firebase:firebase-crashlytics-ndk:18.1.0'
+
+            //facebook
+            implementation 'com.facebook.android:facebook-login:9.0.0'
+            implementation 'com.facebook.android:facebook-android-sdk:8.2.0'
+
+            //adjust
+            implementation 'com.adjust.sdk:adjust-android:4.28.2'
+        }
+    } else {
+        api project(':library_core')
+    }
     debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
 
 }

BIN
demo/libs/library_core-release.aar


+ 20 - 6
demo/src/main/java/com/eyuangame/demo/DemoActivity.kt

@@ -14,8 +14,13 @@ 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.utils.Logger
 import cn.yyxx.support.hawkeye.LogUtils
 import cn.yyxx.support.hawkeye.ToastUtils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 import kotlin.system.exitProcess
 
 
@@ -34,9 +39,9 @@ class DemoActivity : Activity(), View.OnClickListener {
         Item(5, "05 角色升级上报"),
         Item(6, "06 Google应用内购"),
         Item(7, "07 第三方H5支付"),
-        Item(8, "08 Crashlytics崩溃测试"),
-        Item(9, "09 模拟CP打点(玩家首次完成新手引导)"),
-        Item(10, "10 模拟CP打点(玩家首次完成结缘)")
+        Item(8, "08 模拟CP打点(玩家首次完成新手引导)"),
+        Item(0, "09 模拟CP打点(玩家首次完成结缘)"),
+        Item(10, "10 crashlytics崩溃测试"),
     )
 
 
@@ -145,24 +150,33 @@ class DemoActivity : Activity(), View.OnClickListener {
 
                     })
                 }
-                8 -> throw RuntimeException("Test Crashlytics Feature")
-                9 -> {
+                8 -> {
                     val sdkEvent = SdkEvent()
                     sdkEvent.eventName = "tutorial"
                     sdkEvent.standard = true
                     sdkEvent.fbAliasName = "fb_mobile_tutorial_completion"
                     EYuanGame.getInstance().linkingEvent(this@DemoActivity, sdkEvent)
                 }
-                10 -> {
+                9 -> {
                     val sdkEvent = SdkEvent()
                     sdkEvent.eventName = "finish_marry"
                     sdkEvent.standard = false
                     EYuanGame.getInstance().linkingEvent(this@DemoActivity, sdkEvent)
                 }
+                10 -> throw RuntimeException("Test Crashlytics Feature")
+//                10 -> {
+//                    TimeDownUtils.startScope(60, object : TimeDownUtils.TimeCallback {
+//                        override fun onTime(time: Int) {
+//                            Logger.d(time)
+//                        }
+//
+//                    })
+//                }
             }
         }
     }
 
+
     private fun getGameRoleInfo(): SdkRoleInfo {
         val gameRoleInfo = SdkRoleInfo()
         //用户ID

+ 3 - 3
gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
-#Sun Jun 27 19:44:37 CST 2021
+#Tue Jul 13 11:20:06 CST 2021
 distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
 distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
+zipStoreBase=GRADLE_USER_HOME

+ 3 - 1
library_base/proguard-rules.pro

@@ -140,5 +140,7 @@
 -keep class cn.yyxx.eyuangame.base.EYuanGameApplication{public <fields>; public <methods>;}
 -keep class cn.yyxx.eyuangame.Version{public <fields>; public <methods>;}
 
-
+# firebase
+-keepattributes SourceFile,LineNumberTable        # Keep file names and line numbers.
+-keep public class * extends java.lang.Exception  # Optional: Keep custom exceptions.
 

+ 3 - 0
library_core/build.gradle

@@ -66,6 +66,8 @@ android {
 
 dependencies {
 
+    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
+
     //mmkv
     implementation 'com.tencent:mmkv-static:1.2.10'
 
@@ -85,6 +87,7 @@ dependencies {
     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'
+    implementation 'com.google.firebase:firebase-crashlytics-ndk:18.1.0'
 
     //facebook
     implementation 'com.facebook.android:facebook-login:9.0.0'

+ 3 - 2
library_core/proguard-rules.pro

@@ -136,6 +136,7 @@
 -keep class cn.yyxx.eyuangame.core.SdkBridge{public <fields>; public <methods>;}
 -keep class cn.yyxx.eyuangame.core.impl.SdkDrive{public <fields>; public <methods>;}
 
-
-
+# firebase
+-keepattributes SourceFile,LineNumberTable        # Keep file names and line numbers.
+-keep public class * extends java.lang.Exception  # Optional: Keep custom exceptions.
 

+ 1 - 0
library_core/src/main/AndroidManifest.xml

@@ -14,6 +14,7 @@
 
     <application
         android:allowBackup="true"
+        android:allowNativeHeapPointerTagging="false"
         android:supportsRtl="true"
         android:usesCleartextTraffic="true">
 

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

@@ -11,6 +11,8 @@ class FloatCfg {
 
     var switch = 0
     var floatIconUrl = ""
+    var floatIconLeftUrl=""
+    var floatIconRightUrl=""
     lateinit var memberCfg: FeatureCfg
     lateinit var gifCfg: FeatureCfg
     lateinit var gmCfg: FeatureCfg
@@ -38,6 +40,14 @@ class FloatCfg {
                 bean.floatIconUrl = floatCfg.getString("float_icon_line")
             }
 
+            if (JsonUtils.hasJsonKey(floatCfg, "float_icon_left_line")) {
+                bean.floatIconLeftUrl = floatCfg.getString("float_icon_left_line")
+            }
+
+            if (JsonUtils.hasJsonKey(floatCfg, "float_icon_right_line")) {
+                bean.floatIconRightUrl = floatCfg.getString("float_icon_right_line")
+            }
+
             if (JsonUtils.hasJsonKey(floatCfg, "member_cfg")) {
                 bean.memberCfg = FeatureCfg.toBean(floatCfg.getJSONObject("member_cfg"))
             }

+ 34 - 0
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/SdkBridgeImpl.kt

@@ -34,6 +34,7 @@ import cn.yyxx.support.device.DeviceInfoUtils
 import cn.yyxx.support.gaid.GAIDUtils
 import cn.yyxx.support.hawkeye.LogUtils
 import cn.yyxx.support.hawkeye.OwnDebugUtils
+import com.google.firebase.crashlytics.FirebaseCrashlytics
 import java.util.concurrent.atomic.AtomicInteger
 
 
@@ -79,9 +80,11 @@ class SdkBridgeImpl(context: Context) {
             if (code == 0) {
                 Logger.i("谷歌框架可以访问,请求gaid")
                 SdkDrive.instance.setParam("device_id", GAIDUtils.getGoogleAdid())
+                FirebaseCrashlytics.getInstance().setCustomKey("device_id", GAIDUtils.getGoogleAdid())
             } else {
                 Logger.e("谷歌框架不可访问,使用android id替代")
                 SdkDrive.instance.setParam("device_id", DeviceInfoUtils.getAndroidDeviceId(application))
+                FirebaseCrashlytics.getInstance().setCustomKey("device_id", DeviceInfoUtils.getAndroidDeviceId(application))
             }
             hasReadGaid = true
         }
@@ -156,6 +159,8 @@ class SdkBridgeImpl(context: Context) {
                 if (resultInfo.code == 1 && !TextUtils.isEmpty(resultInfo.data)) {
                     initBean = InitBean.toBean(resultInfo.data)
                     //TODO 下载图片资源
+                    cacheImageResource(activity)
+
                     Linking.instance.create(activity)
                     showInitDialog(activity, callback, initCallback)
                     FloatCenterServiceManager.instance.init(activity)
@@ -168,6 +173,33 @@ class SdkBridgeImpl(context: Context) {
         })
     }
 
+
+    private fun cacheImageResource(activity: Activity) {
+        //浮标icon
+        initBean.floatCfg.floatIconUrl =
+            "http://gogs.yyxxgame.com/Client/EYuanGameSdk-KTX/raw/eb71e59d47ea88a5200cfe691e550334b38fff48/library_core/src/main/res/drawable-xhdpi/yyxx_float_logo_img.png"
+        initBean.floatCfg.floatIconLeftUrl =
+            "http://gogs.yyxxgame.com/Client/EYuanGameSdk-KTX/raw/eb71e59d47ea88a5200cfe691e550334b38fff48/library_core/src/main/res/drawable-xhdpi/yyxx_float_logo_left_img.png"
+        initBean.floatCfg.floatIconRightUrl =
+            "http://gogs.yyxxgame.com/Client/EYuanGameSdk-KTX/raw/eb71e59d47ea88a5200cfe691e550334b38fff48/library_core/src/main/res/drawable-xhdpi/yyxx_float_logo_right_img.png"
+
+        SdkRequest.instance.downloadImageFile(activity, initBean.floatCfg.floatIconUrl)
+        //左边
+        SdkRequest.instance.downloadImageFile(activity, initBean.floatCfg.floatIconLeftUrl)
+        //右边
+        SdkRequest.instance.downloadImageFile(activity, initBean.floatCfg.floatIconRightUrl)
+//        //会员中心
+//        SdkRequest.instance.downloadImageFile(activity, initBean.floatCfg.floatIconUrl)
+//        //礼包
+//        SdkRequest.instance.downloadImageFile(activity, initBean.floatCfg.floatIconUrl)
+//        //客服
+//        SdkRequest.instance.downloadImageFile(activity, initBean.floatCfg.floatIconUrl)
+//        //储值
+//        SdkRequest.instance.downloadImageFile(activity, initBean.floatCfg.floatIconUrl)
+//        //邀请
+//        SdkRequest.instance.downloadImageFile(activity, initBean.floatCfg.floatIconUrl)
+    }
+
     private fun showInitDialog(activity: Activity, callback: ICallback, initCallback: IInitialize) {
         isShowInitDialog = false
         initState = true
@@ -225,6 +257,7 @@ class SdkBridgeImpl(context: Context) {
                     if (SdkBackLoginInfo.instance.isRegUser) {
                         Linking.instance.register(activity)
                     }
+                    FirebaseCrashlytics.getInstance().setUserId(SdkBackLoginInfo.instance.userId)
                     Linking.instance.login(activity)
                 }
                 callback.onResult(code, result)
@@ -237,6 +270,7 @@ class SdkBridgeImpl(context: Context) {
 
         this.roleInfo = null
         SdkBackLoginInfo.instance.reset()
+        FirebaseCrashlytics.getInstance().setUserId("")
         FloatCenterServiceManager.instance.detach()
         callback.onResult(0, "用户登出成功")
     }

+ 41 - 5
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/floatball/FloatCenterService.kt

@@ -2,9 +2,13 @@ package cn.yyxx.eyuangame.core.impl.floatball
 
 import android.app.Activity
 import android.app.Service
+import android.content.Context
 import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
 import android.os.Binder
 import android.os.IBinder
+import android.text.TextUtils
 import android.widget.ImageView
 import cn.yyxx.eyuangame.core.entity.FloatFeature
 import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
@@ -13,6 +17,9 @@ import cn.yyxx.eyuangame.core.impl.center.MemberActivity
 import cn.yyxx.eyuangame.core.ui.floatview.FloatingBall
 import cn.yyxx.eyuangame.core.ui.floatview.FloatingBallMenu
 import cn.yyxx.support.ResUtils
+import cn.yyxx.support.encryption.Md5Utils
+import java.io.FileInputStream
+import java.io.FileNotFoundException
 
 /**
  * @author #Suyghur.
@@ -25,18 +32,35 @@ class FloatCenterService : Service() {
 
     private val callback = object : FloatingBall.FloatingBallCallback {
         override fun onUpdateBallView(ballView: ImageView, isLeftLocation: Boolean, isHide: Boolean) {
-            val resId = if (isHide) {
+            if (isHide) {
                 ballView.alpha = 0.8f
                 if (isLeftLocation) {
-                    ResUtils.getResId(mActivity, "yyxx_float_logo_left_img", "drawable")
+                    if (TextUtils.isEmpty(SdkBridgeImpl.initBean.floatCfg.floatIconLeftUrl)) {
+                        val resId = ResUtils.getResId(mActivity, "yyxx_float_logo_left_img", "drawable")
+                        ballView.setBackgroundResource(resId)
+                    } else {
+                        val name = Md5Utils.encodeByMD5(SdkBridgeImpl.initBean.floatCfg.floatIconLeftUrl)
+                        ballView.setImageBitmap(getLocalBitmap(mActivity!!, name))
+                    }
                 } else {
-                    ResUtils.getResId(mActivity, "yyxx_float_logo_right_img", "drawable")
+                    if (TextUtils.isEmpty(SdkBridgeImpl.initBean.floatCfg.floatIconRightUrl)) {
+                        val resId = ResUtils.getResId(mActivity, "yyxx_float_logo_right_img", "drawable")
+                        ballView.setBackgroundResource(resId)
+                    } else {
+                        val name = Md5Utils.encodeByMD5(SdkBridgeImpl.initBean.floatCfg.floatIconRightUrl)
+                        ballView.setImageBitmap(getLocalBitmap(mActivity!!, name))
+                    }
                 }
             } else {
                 ballView.alpha = 1.0f
-                ResUtils.getResId(mActivity, "yyxx_float_logo_img", "drawable")
+                if (TextUtils.isEmpty(SdkBridgeImpl.initBean.floatCfg.floatIconUrl)) {
+                    val resId = ResUtils.getResId(mActivity, "yyxx_float_logo_img", "drawable")
+                    ballView.setBackgroundResource(resId)
+                } else {
+                    val name = Md5Utils.encodeByMD5(SdkBridgeImpl.initBean.floatCfg.floatIconUrl)
+                    ballView.setImageBitmap(getLocalBitmap(mActivity!!, name))
+                }
             }
-            ballView.setBackgroundResource(resId)
         }
 
         override fun onInitMenuData(): MutableList<FloatingBallMenu.FloatingBallMenuItem> {
@@ -104,6 +128,18 @@ class FloatCenterService : Service() {
         floatingBall?.release()
     }
 
+
+    private fun getLocalBitmap(context: Context, name: String): Bitmap? {
+        try {
+            val path = "${context.getExternalFilesDir("cache")!!.absolutePath}/$name"
+            val fis = FileInputStream(path)
+            return BitmapFactory.decodeStream(fis)
+        } catch (e: FileNotFoundException) {
+            e.printStackTrace()
+        }
+        return null
+    }
+
     override fun onBind(intent: Intent?): IBinder {
         return FloatCenterServiceBinder()
     }

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

@@ -43,7 +43,6 @@ class ChargeImpl : InAppBilling() {
     }
 
     override fun chargePurchasesUpdated(activity: Activity, purchase: Purchase) {
-        Logger.d("chargePurchasesUpdated")
         notifyOrder2Backend(activity, chargeInfo.orderId, purchase, false)
     }
 
@@ -215,7 +214,6 @@ class ChargeImpl : InAppBilling() {
         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) {

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

@@ -35,7 +35,6 @@ abstract class InAppBilling {
             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) {
                             //预注册

+ 12 - 2
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/login/UserSignInImpl.kt

@@ -3,6 +3,7 @@ package cn.yyxx.eyuangame.core.impl.login
 import android.app.Activity
 import android.content.Context
 import android.content.Intent
+import android.os.Looper
 import android.text.TextUtils
 import cn.yyxx.eyuangame.base.utils.Logger
 import cn.yyxx.eyuangame.base.utils.ParamsUtils
@@ -26,6 +27,9 @@ import com.google.android.gms.common.ConnectionResult
 import com.google.android.gms.common.GoogleApiAvailability
 import com.google.android.gms.common.api.ApiException
 import com.google.android.gms.tasks.Task
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
 import org.json.JSONException
 import org.json.JSONObject
 import java.util.*
@@ -174,7 +178,10 @@ class UserSignInImpl constructor(val activity: LoginActivity, private val callba
                                 loginType = SdkBackLoginInfo.instance.loginType
                                 this.userName = userName
                                 this.pwd = pwd
-                                SessionUtils.instance.saveSession(context, this)
+                                GlobalScope.launch(Dispatchers.IO) {
+                                    Logger.d("with io coroutines do save session")
+                                    SessionUtils.instance.saveSession(context, this@with)
+                                }
                             }
                             callback.onSuccess(SdkBackLoginInfo.instance.toJsonString())
                         } catch (e: JSONException) {
@@ -215,7 +222,10 @@ class UserSignInImpl constructor(val activity: LoginActivity, private val callba
                                 userName = loginParams.getString("uname")
                                 pwd = loginParams.getString("pwd")
                             }
-                            SessionUtils.instance.saveSession(context, this)
+                            GlobalScope.launch(Dispatchers.IO) {
+                                Logger.d("with io coroutines do save session")
+                                SessionUtils.instance.saveSession(context, this@with)
+                            }
                         }
                         callback.onSuccess(SdkBackLoginInfo.instance.toJsonString())
                     } catch (e: JSONException) {

+ 2 - 1
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/login/fragment/LauncherFragment.kt

@@ -327,7 +327,8 @@ class LauncherFragment : Fragment(), View.OnClickListener {
             dismiss()
             agreementDialog = null
         }
-        agreementDialog = AgreementDialog(requireContext(), SdkBridgeImpl.initBean.privacyCfg.url, SdkBridgeImpl.isLand)
+//                agreementDialog = AgreementDialog(requireContext(), SdkBridgeImpl.initBean.privacyCfg.url, SdkBridgeImpl.isLand)
+        agreementDialog = AgreementDialog(requireContext(), "http://www.eyuangame.com/agreement_user.html", SdkBridgeImpl.isLand)
         agreementDialog?.apply {
             loginImpl.hideLoginView()
             ivReturn.setOnClickListener {

+ 15 - 0
library_core/src/main/java/cn/yyxx/eyuangame/core/network/SdkRequest.kt

@@ -3,9 +3,12 @@ package cn.yyxx.eyuangame.core.network
 import android.content.Context
 import cn.yyxx.eyuangame.base.entity.SdkChargeInfo
 import cn.yyxx.eyuangame.base.entity.SdkRoleInfo
+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.IFileRequestCallback
 import cn.yyxx.eyuangame.core.internal.IRequestCallback
+import cn.yyxx.support.volley.source.VolleyError
 import org.json.JSONException
 import org.json.JSONObject
 
@@ -154,6 +157,18 @@ class SdkRequest {
         VolleyRequest.post(context, jsonObject, callback)
     }
 
+    fun downloadImageFile(context: Context, url: String) {
+        VolleyRequest.downloadImageFile(context, url, object : IFileRequestCallback {
+            override fun onResponse(result: String) {
+                Logger.d("downloadImageFile onResponse $result")
+            }
+
+            override fun onErrorResponse(error: VolleyError) {
+                Logger.e("downloadImageFile onErrorResponse")
+            }
+        })
+    }
+
     companion object {
         val instance: SdkRequest by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
             SdkRequest()

+ 56 - 5
library_core/src/main/java/cn/yyxx/eyuangame/core/network/VolleyRequest.kt

@@ -5,19 +5,25 @@ import android.text.TextUtils
 import cn.yyxx.eyuangame.base.utils.Logger
 import cn.yyxx.eyuangame.core.entity.ResultInfo
 import cn.yyxx.eyuangame.core.impl.SdkDrive
+import cn.yyxx.eyuangame.core.internal.IFileRequestCallback
 import cn.yyxx.eyuangame.core.internal.IRequestCallback
+import cn.yyxx.support.FileUtils
 import cn.yyxx.support.JsonUtils
 import cn.yyxx.support.StrUtils
 import cn.yyxx.support.encryption.Base64Utils
 import cn.yyxx.support.encryption.HexUtils
 import cn.yyxx.support.encryption.Md5Utils
 import cn.yyxx.support.volley.VolleySingleton
-import cn.yyxx.support.volley.source.DefaultRetryPolicy
-import cn.yyxx.support.volley.source.Response
-import cn.yyxx.support.volley.source.VolleyError
+import cn.yyxx.support.volley.source.*
+import cn.yyxx.support.volley.source.toolbox.HttpHeaderParser
 import cn.yyxx.support.volley.source.toolbox.JsonObjectRequest
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
 import org.json.JSONException
 import org.json.JSONObject
+import java.io.File
+import java.io.IOException
 
 /**
  * @author #Suyghur.
@@ -102,13 +108,58 @@ object VolleyRequest {
             }
             //设置超时时间
             request.retryPolicy = DefaultRetryPolicy(MAX_TIMEOUT, 1, 1.0f)
-            VolleySingleton.getInstance(context.applicationContext)
-                .addToRequestQueue(context.applicationContext, request)
+            VolleySingleton.getInstance(context.applicationContext).addToRequestQueue(context.applicationContext, request)
         } catch (e: Exception) {
             e.printStackTrace()
         }
     }
 
+    fun downloadImageFile(context: Context, url: String, callback: IFileRequestCallback) {
+        val cacheFolder = File(context.getExternalFilesDir("cache")!!.absolutePath)
+        if (!cacheFolder.exists()) {
+            cacheFolder.mkdirs()
+        }
+        val fileName = Md5Utils.encodeByMD5(url)
+        val filePath = "$cacheFolder/$fileName"
+        Logger.d(filePath)
+        if (File(filePath).exists()) {
+            callback.onResponse("image has been cached locally")
+            return
+        }
+        val request: Request<ByteArray> = object : Request<ByteArray>(Method.GET, url, Response.ErrorListener {
+            callback.onErrorResponse(it)
+        }) {
+            override fun parseNetworkResponse(response: NetworkResponse): Response<ByteArray> {
+                return try {
+                    if (response.data == null) {
+                        Response.error(ParseError(response))
+                    } else {
+                        Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response))
+                    }
+                } catch (e: OutOfMemoryError) {
+                    e.printStackTrace()
+                    Response.error(ParseError(e))
+                }
+            }
+
+            override fun deliverResponse(response: ByteArray) {
+                Logger.d("volley download image file success, start to save file ...")
+                try {
+                    GlobalScope.launch(Dispatchers.IO){
+                        Logger.d("with io coroutines do save file")
+                        FileUtils.saveFile(filePath, response)
+                    }
+                    callback.onResponse("download file success, path: $filePath")
+                } catch (e: IOException) {
+                    e.printStackTrace()
+                    callback.onErrorResponse(ParseError(e))
+                }
+            }
+        }
+
+        VolleySingleton.getInstance(context.applicationContext).addToRequestQueue(context.applicationContext, request)
+    }
+
     private fun parseResponse(context: Context, data: JSONObject): String {
         try {
             val ts = data.getString("ts")

+ 0 - 123
library_core/src/main/java/cn/yyxx/eyuangame/core/utils/FileUtils.kt

@@ -1,123 +0,0 @@
-package cn.yyxx.eyuangame.core.utils
-
-import android.content.Context
-import android.text.TextUtils
-import cn.yyxx.eyuangame.base.utils.Logger
-import cn.yyxx.eyuangame.core.network.Host
-import cn.yyxx.support.HostModelUtils
-import cn.yyxx.support.encryption.aes.AesUtils
-
-import java.io.*
-
-/**
- * @author #Suyghur.
- * Created on 2020/12/10
- */
-object FileUtils {
-
-    private const val AES_KEY = "yyxxgamecolumbus"
-    private const val USER_DAT = "USER.DAT"
-    private const val USER_TEST_DAT = "USER_TEST.DAT"
-    private const val USER_DEV_DAT = "USER_DEV.DAT"
-
-    fun getUserInfoFilePath(context: Context): String {
-        val filePath = getUserInfoBySDCard(context)
-        val file = File(filePath)
-        if (!file.exists()) {
-            try {
-                if (file.createNewFile()) {
-                    Logger.d("创建用户文件成功:$filePath")
-                } else {
-                    Logger.e("创建用户文件失败:$filePath")
-                }
-            } catch (e: IOException) {
-                e.printStackTrace()
-            }
-        }
-        return filePath
-    }
-
-
-    private fun getUserInfoBySDCard(context: Context): String {
-        var fileName = ""
-        when (Host.IP_MODEL) {
-            HostModelUtils.ENV_DEV -> {
-                fileName = USER_DEV_DAT
-                Logger.d("dev环境,读取文件:$fileName")
-            }
-            HostModelUtils.ENV_TEST -> {
-                fileName = USER_TEST_DAT
-                Logger.d("test环境,读取文件:$fileName")
-            }
-            HostModelUtils.ENV_ONLINE -> fileName = USER_DAT
-        }
-        return context.getExternalFilesDir(null)?.absolutePath + File.separator + fileName
-    }
-
-    /**
-     * 从文件中读取数据并解密
-     *
-     * @param filePath
-     * @return
-     */
-    fun readFile(filePath: String): String {
-        var content = StringBuilder()
-        try {
-            val file = File(filePath)
-            // 判断文件是否存在,如果不存在则返回空
-            if (!file.exists() || !file.isFile) {
-                return ""
-            }
-            val reader = BufferedReader(FileReader(file))
-            var tempString: String?
-            while (reader.readLine().also { tempString = it } != null) {
-                content.append(tempString)
-            }
-            reader.close()
-
-            // AES解密
-            content = if (!TextUtils.isEmpty(content.toString())) {
-                StringBuilder(AesUtils.decrypt(AES_KEY, content.toString()))
-            } else {
-                return ""
-            }
-        } catch (e: Exception) {
-            e.printStackTrace()
-        }
-        return content.toString()
-    }
-
-    /**
-     * 将数据写入到文件中保存并加密
-     *
-     * @param content  内容
-     * @param filePath 文件路径
-     */
-    fun writeFile(content: String, filePath: String) {
-        try {
-            val file = File(filePath)
-            //取文件的上级目录
-            val fileDir = filePath.substring(0, filePath.lastIndexOf(File.separator) + 1)
-            val parentFile = File(fileDir)
-            //如果文件夹不存在或者不是文件夹,则创建文件夹
-            if (!parentFile.exists() || !parentFile.isDirectory) {
-                parentFile.mkdirs()
-            }
-            //如果文件不存在,则创建一个文件
-            if (!file.exists() || !file.isFile) {
-                file.createNewFile()
-            }
-            val fileWriter = FileWriter(file, false)
-
-            //AES加密
-            val enc = AesUtils.encrypt(AES_KEY, content)
-            if (!TextUtils.isEmpty(enc)) {
-                fileWriter.write(enc)
-            }
-            fileWriter.close()
-        } catch (e: Exception) {
-            e.printStackTrace()
-        }
-    }
-
-}

+ 31 - 0
library_core/src/main/java/cn/yyxx/eyuangame/core/utils/TimeDownUtils.kt

@@ -1,6 +1,11 @@
 package cn.yyxx.eyuangame.core.utils
 
+import android.os.Looper
 import cn.yyxx.eyuangame.base.utils.Logger
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
 
 
 /**
@@ -12,6 +17,8 @@ object TimeDownUtils {
     var isRunning = false
     private var isCancel = false
 
+    var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + Job())
+
     @Volatile
     private var times: Times? = null
 
@@ -26,6 +33,7 @@ object TimeDownUtils {
         }
     }
 
+
     fun cancel() {
         isCancel = true
         if (isRunning) {
@@ -44,6 +52,29 @@ object TimeDownUtils {
         }
     }
 
+    fun startScope(time: Int, callback: TimeCallback) {
+        scope.launch {
+            timeScope(time, callback)
+        }
+    }
+
+    private fun timeScope(time: Int, callback: TimeCallback) {
+//        callback.onTime(time)
+        Logger.d("timeScope 倒计时开始... , ${Looper.getMainLooper().thread == Thread.currentThread()}")
+        for (i in time downTo 0) {
+            try {
+                Thread.sleep(1000)
+            } catch (e: InterruptedException) {
+                e.printStackTrace()
+            }
+//            if (isCancel) {
+//                Logger.d("TimeDownUtils 线程已退出")
+//                return
+//            }
+            callback.onTime(i)
+        }
+    }
+
 //    fun isRunning(): Boolean {
 //        return isRunning
 //    }