diff --git a/Lib_Base/build.gradle b/Lib_Base/build.gradle index c3f6848..b36ab1a 100644 --- a/Lib_Base/build.gradle +++ b/Lib_Base/build.gradle @@ -1,19 +1,20 @@ import com.quyunshuo.androidbaseframemvvm.build.* -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'kotlin-kapt' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-kapt' +} android { - compileSdkVersion BuildConfig.compileSdkVersion - buildToolsVersion BuildConfig.buildToolsVersion + compileSdkVersion ProjectBuildConfig.compileSdkVersion + buildToolsVersion ProjectBuildConfig.buildToolsVersion defaultConfig { - minSdkVersion BuildConfig.minSdkVersion - targetSdkVersion BuildConfig.targetSdkVersion - versionCode BuildConfig.versionCode - versionName BuildConfig.versionName + minSdkVersion ProjectBuildConfig.minSdkVersion + targetSdkVersion ProjectBuildConfig.targetSdkVersion + versionCode ProjectBuildConfig.versionCode + versionName ProjectBuildConfig.versionName testInstrumentationRunner AndroidX.AndroidJUnitRunner consumerProguardFiles "consumer-rules.pro" } @@ -71,6 +72,7 @@ dependencies { api GitHub.StatusBar api GitHub.EventBus api GitHub.Bugly + api GitHub.BuglyNative api GitHub.PermissionX kapt GitHub.GlideCompiler diff --git a/Lib_Base/src/main/java/com/quyunshuo/base/BaseApplication.kt b/Lib_Base/src/main/java/com/quyunshuo/base/BaseApplication.kt index 61405e9..4b43dce 100644 --- a/Lib_Base/src/main/java/com/quyunshuo/base/BaseApplication.kt +++ b/Lib_Base/src/main/java/com/quyunshuo/base/BaseApplication.kt @@ -1,11 +1,11 @@ package com.quyunshuo.base -import android.app.Application +import android.annotation.SuppressLint import android.content.Context -import androidx.multidex.MultiDex -import com.alibaba.android.arouter.launcher.ARouter -import com.quyunshuo.base.utils.SpUtils -import com.tencent.bugly.crashreport.CrashReport +import android.util.Log +import androidx.multidex.MultiDexApplication +import kotlinx.coroutines.* +import kotlin.system.measureTimeMillis /** * @Author: QuYunShuo @@ -13,39 +13,87 @@ import com.tencent.bugly.crashreport.CrashReport * @Class: BaseApplication * @Remark: 自定义Application的基类 */ -open class BaseApplication : Application() { +abstract class BaseApplication : MultiDexApplication() { + + private val mCoroutineScope by lazy(mode = LazyThreadSafetyMode.NONE) { MainScope() } companion object { // 全局Context + @SuppressLint("StaticFieldLeak") lateinit var context: Context } override fun onCreate() { super.onCreate() context = applicationContext - initialize() + // 策略初始化第三方依赖 + initDepends() } /** - * 进行一些初始化的操作 + * 需要立即进行初始化的放在这里进行并行初始化 + * 需要必须在主线程初始化的放在[InitDepend.mainThreadDepends],反之放在[InitDepend.workerThreadDepends] + * @return InitDepend 初始化方法集合 */ - protected open fun initialize() { - // 腾讯 MMKV 初始化 - SpUtils.initMMKV(this) + abstract fun initByFrontDesk(): InitDepend - // 阿里路由 ARouter 初始化 - if (BuildConfig.DEBUG) { - ARouter.openLog() // 打印日志 - ARouter.openDebug() // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险) + /** + * 不需要立马初始化的放在这里进行后台初始化 + */ + abstract suspend fun initByBackstage() + + /** + * 初始化第三方依赖 + * + * 步骤: + * * 1. 首先开启一个后台协程对不会立即使用的第三方进行初始化 + * * 2. 对需要被立即使用的第三方进行初始化 + * * 2.1 首先是并行对非必须要在主线程初始化的依赖进行初始化 此时不用管初始化是否完成 紧接着进行下一步 + * * 2.2 对必须要在主线程初始化的依赖进行初始化 由于是在主线程 所以后面的操作等待初始化完成 这部分时间不能浪费掉 这就是为什么先并行初始化非主线程的 因为这部分时间会被利用上 + * * 2.3 等待所有并行初始化的job完成就结束了整个初始化过程 + */ + private fun initDepends() { + // 开启一个 Default Coroutine 进行初始化不会立即使用的第三方 + mCoroutineScope.launch(Dispatchers.Default) { + initByBackstage() } - ARouter.init(this) - // Bugly 初始化 第三个参数为SDK调试模式开关 - CrashReport.initCrashReport(this, "申请的id", BuildConfig.DEBUG) + // 初始化需要被立即初始化的第三方 多线程并行,并阻塞至全部完成 + val measureTimeMillis = measureTimeMillis { + mCoroutineScope.launch(Dispatchers.Main.immediate) { + val depends = initByFrontDesk() + + // 1. 对非必须在主线程初始化的第三方依赖发起并行初始化 + // 并行job + var jobs: MutableList>? = null + if (depends.workerThreadDepends != null) { + jobs = mutableListOf() + depends.workerThreadDepends.forEach { + jobs.add(async(Dispatchers.Default) { it() }) + } + } + + // 2. 对必须在主线程初始化的第三方依赖进行初始化 + if (depends.mainThreadDepends != null) { + depends.mainThreadDepends.forEach { it() } + } + + // 3. 等待每一个子线程初始化的依赖完成 + jobs?.forEach { it.await() } + } + } + Log.d("ApplicationInit", "初始化完成 $measureTimeMillis ms") } - override fun attachBaseContext(base: Context?) { - super.attachBaseContext(base) - MultiDex.install(base) - } + /** + * 需要立即进行初始化的依赖列表 有的依赖可能必须要在主线程进行初始化,就放在[mainThreadDepends]里面就可以 + * 其余的非必须要在主线程进行初始化的放在[workerThreadDepends]里面,这部分依赖会被后台线程并行初始化 + * + * @property mainThreadDepends MutableList<() -> String>? 必须要在主线程初始化的依赖 + * @property workerThreadDepends MutableList<() -> String>? 非必须要在主线程初始化的依赖 + */ + data class InitDepend( + val mainThreadDepends: MutableList<() -> String>?, + val workerThreadDepends: MutableList<() -> String>? + ) } \ No newline at end of file diff --git a/Lib_Common/build.gradle b/Lib_Common/build.gradle index 9f91c8b..d2a3eb8 100644 --- a/Lib_Common/build.gradle +++ b/Lib_Common/build.gradle @@ -2,20 +2,23 @@ import com.quyunshuo.androidbaseframemvvm.build.* apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android { - compileSdkVersion BuildConfig.compileSdkVersion - buildToolsVersion BuildConfig.buildToolsVersion + compileSdkVersion ProjectBuildConfig.compileSdkVersion + buildToolsVersion ProjectBuildConfig.buildToolsVersion defaultConfig { - minSdkVersion BuildConfig.minSdkVersion - targetSdkVersion BuildConfig.targetSdkVersion - versionCode BuildConfig.versionCode - versionName BuildConfig.versionName + minSdkVersion ProjectBuildConfig.minSdkVersion + targetSdkVersion ProjectBuildConfig.targetSdkVersion + versionCode ProjectBuildConfig.versionCode + versionName ProjectBuildConfig.versionName testInstrumentationRunner AndroidX.AndroidJUnitRunner consumerProguardFiles "consumer-rules.pro" + + // 相关自定义配置 + resValue "string", "VERSION_STATUS", ProjectBuildConfig.versionStatus + resValue "string", "BUGLY_APP_ID", SDKKeyConfig.BUGLY_APP_ID } compileOptions { diff --git a/Lib_Common/src/main/java/com/quyunshuo/common/CommonApplication.kt b/Lib_Common/src/main/java/com/quyunshuo/common/CommonApplication.kt index 363b239..7689267 100644 --- a/Lib_Common/src/main/java/com/quyunshuo/common/CommonApplication.kt +++ b/Lib_Common/src/main/java/com/quyunshuo/common/CommonApplication.kt @@ -3,8 +3,12 @@ package com.quyunshuo.common import android.app.Activity import android.app.Application import android.os.Bundle +import com.alibaba.android.arouter.launcher.ARouter import com.quyunshuo.base.BaseApplication +import com.quyunshuo.base.BaseApplication.InitDepend import com.quyunshuo.base.utils.ActivityStackManager +import com.quyunshuo.base.utils.SpUtils +import com.tencent.bugly.crashreport.CrashReport /** * @Author: QuYunShuo @@ -14,12 +18,70 @@ import com.quyunshuo.base.utils.ActivityStackManager */ open class CommonApplication : BaseApplication(), Application.ActivityLifecycleCallbacks { + /** + * 项目当前的版本状态 + */ + val versionStatus: String by lazy { getString(R.string.VERSION_STATUS) } + override fun onCreate() { super.onCreate() // 全局监听 Activity 生命周期 registerActivityLifecycleCallbacks(this) } + /** + * 需要立即进行初始化的放在这里进行并行初始化 + * 需要必须在主线程初始化的放在[InitDepend.mainThreadDepends],反之放在[InitDepend.workerThreadDepends] + * @return InitDepend 初始化方法集合 + */ + override fun initByFrontDesk(): InitDepend { + val worker = mutableListOf<() -> String>() + worker.add { initMMKV() } + worker.add { initARouter() } + worker.add { initTencentBugly() } + return InitDepend(null, worker) + } + + /** + * 不需要立马初始化的放在这里进行后台初始化 + */ + override suspend fun initByBackstage() {} + + /** + * 腾讯 MMKV 初始化 + */ + private fun initMMKV(): String { + val result = SpUtils.initMMKV(this) + return "MMKV -->> $result" + } + + /** + * 阿里路由 ARouter 初始化 + */ + private fun initARouter(): String { + // 测试环境下打开ARouter的日志和调试模式 正式环境需要关闭 + if (versionStatus == "VERSION_STATUS_ALPHA" || versionStatus == "VERSION_STATUS_BETA") { + ARouter.openLog() // 打印日志 + ARouter.openDebug() // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险) + } + ARouter.init(this) + return "ARouter -->> init complete" + } + + /** + * 初始化 腾讯Bugly + * 测试环境应该与正式环境的日志收集渠道分隔开 + */ + private fun initTencentBugly(): String { + // 第三个参数为SDK调试模式开关 + CrashReport.initCrashReport( + this, + getString(R.string.BUGLY_APP_ID), + versionStatus == "VERSION_STATUS_ALPHA" || versionStatus == "VERSION_STATUS_BETA" + ) + return "Bugly -->> init complete" + } + override fun onActivityCreated(activity: Activity, bundle: Bundle?) { ActivityStackManager.addActivityToStack(activity) } diff --git a/app/build.gradle b/app/build.gradle index 7dd1ab4..8a949ca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,19 +1,21 @@ import com.quyunshuo.androidbaseframemvvm.build.* -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'com.alibaba.arouter' +} android { - compileSdkVersion BuildConfig.compileSdkVersion - buildToolsVersion BuildConfig.buildToolsVersion + compileSdkVersion ProjectBuildConfig.compileSdkVersion + buildToolsVersion ProjectBuildConfig.buildToolsVersion defaultConfig { - applicationId BuildConfig.applicationId - minSdkVersion BuildConfig.minSdkVersion - targetSdkVersion BuildConfig.targetSdkVersion - versionCode BuildConfig.versionCode - versionName BuildConfig.versionName + applicationId ProjectBuildConfig.applicationId + minSdkVersion ProjectBuildConfig.minSdkVersion + targetSdkVersion ProjectBuildConfig.targetSdkVersion + versionCode ProjectBuildConfig.versionCode + versionName ProjectBuildConfig.versionName testInstrumentationRunner AndroidX.AndroidJUnitRunner multiDexKeepProguard file("multidexKeep.pro") } @@ -37,7 +39,7 @@ android { if (outputFileName != null && outputFileName.endsWith('.apk') && 'release' == variant.buildType.name) { - outputFileName = "${BuildConfig.applicationId}_${defaultConfig.versionCode}(${defaultConfig.versionName}).apk" + outputFileName = "${ProjectBuildConfig.applicationId}_${defaultConfig.versionCode}(${defaultConfig.versionName}).apk" } } } @@ -50,7 +52,7 @@ android { if (outputFileName != null && outputFileName.endsWith('.apk') && 'debug' == variant.buildType.name) { - outputFileName = "${BuildConfig.applicationId}_${defaultConfig.versionCode}(${defaultConfig.versionName}).apk" + outputFileName = "${ProjectBuildConfig.applicationId}_${defaultConfig.versionCode}(${defaultConfig.versionName}).apk" } } } @@ -69,7 +71,7 @@ android { dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) - if (!BuildConfig.isAppMode) { + if (!ProjectBuildConfig.isAppMode) { // 有业务组件时 把这个去掉 这里只是为了使用base里的依赖库 implementation project(path: ':Lib_Common') } else { diff --git a/app/src/main/java/com/quyunshuo/androidbaseframemvvm/AppApplication.kt b/app/src/main/java/com/quyunshuo/androidbaseframemvvm/AppApplication.kt index eb6e545..0bb6bd5 100644 --- a/app/src/main/java/com/quyunshuo/androidbaseframemvvm/AppApplication.kt +++ b/app/src/main/java/com/quyunshuo/androidbaseframemvvm/AppApplication.kt @@ -11,12 +11,12 @@ import org.greenrobot.eventbus.EventBus */ class AppApplication : CommonApplication() { - override fun initialize() { + override fun onCreate() { // 开启EventBusAPT,优化反射效率 EventBus .builder() // .addIndex() .installDefaultEventBus() - super.initialize() + super.onCreate() } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 34aa573..88ddc8f 100644 --- a/build.gradle +++ b/build.gradle @@ -10,6 +10,7 @@ buildscript { dependencies { classpath ProjectPluginManager.AndroidToolsPlugin classpath ProjectPluginManager.KotlinPlugin + classpath ProjectPluginManager.ARouterRegister } } diff --git a/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/BuildConfig.kt b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/BuildConfig.kt deleted file mode 100644 index 8e5f3e3..0000000 --- a/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/BuildConfig.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.quyunshuo.androidbaseframemvvm.build - -/** - * 项目相关参数配置 - */ -object BuildConfig { - const val compileSdkVersion = 30 - const val buildToolsVersion = "30.0.1" - const val applicationId = "com.quyunshuo.androidbaseframemvvm" - const val minSdkVersion = 21 - const val targetSdkVersion = 30 - const val versionCode = 1 - const val versionName = "1.0" - const val isAppMode = false -} \ No newline at end of file diff --git a/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/DependencyManager.kt b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/DependencyManager.kt index 4572e09..27256f5 100644 --- a/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/DependencyManager.kt +++ b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/DependencyManager.kt @@ -18,8 +18,8 @@ object Version { const val Junit = "4.13" // Kotlin---------------------------------------------------------------- - const val Kotlin = "1.4.0" - const val Coroutines = "1.3.7" // 协程 + const val Kotlin = "1.4.31" // Kotlin + const val Coroutines = "1.4.3" // 协程 // JetPack--------------------------------------------------------------- const val LifecycleViewModel = "2.2.0" @@ -35,12 +35,13 @@ object Version { const val MMKV = "1.2.2" // 腾讯 MMKV 替代SP const val AutoSize = "1.2.1" // 屏幕适配 const val Glide = "4.11.0" // Glide - const val ARoute = "1.5.0" // 阿里路由 - const val ARouteCompiler = "1.2.2" // 阿里路由 APT + const val ARoute = "1.5.1" // 阿里路由 + const val ARouteCompiler = "1.5.1" // 阿里路由 APT const val RecyclerViewAdapter = "3.0.4" // RecyclerViewAdapter const val StatusBar = "1.5.1" // 状态栏 const val EventBus = "3.2.0" // 事件总线 - const val Bugly = "3.2.33" // Bugly 异常上报 + const val Bugly = "3.3.7" // Bugly 异常上报 + const val BuglyNative = "3.8.0" // Bugly native异常上报 const val PermissionX = "1.3.0" // 权限申请 const val LeakCanary = "2.4" // 检测内存泄漏 const val Chuck = "1.1.0" // OkHttp 请求信息拦截器(UI) @@ -99,6 +100,7 @@ object GitHub { const val EventBus = "org.greenrobot:eventbus:${Version.EventBus}" const val EventBusAPT = "org.greenrobot:eventbus-annotation-processor:${Version.EventBus}" const val Bugly = "com.tencent.bugly:crashreport:${Version.Bugly}" + const val BuglyNative = "com.tencent.bugly:nativecrashreport:${Version.BuglyNative}" const val PermissionX = "com.permissionx.guolindev:permissionx:${Version.PermissionX}" const val LeakCanary = "com.squareup.leakcanary:leakcanary-android:${Version.LeakCanary}" const val Chuck = "com.readystatesoftware.chuck:library:${Version.Chuck}" diff --git a/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/ProjectBuildConfig.kt b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/ProjectBuildConfig.kt new file mode 100644 index 0000000..c668797 --- /dev/null +++ b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/ProjectBuildConfig.kt @@ -0,0 +1,23 @@ +package com.quyunshuo.androidbaseframemvvm.build + +/** + * 项目相关参数配置 + */ +object ProjectBuildConfig { + const val compileSdkVersion = 30 + const val buildToolsVersion = "30.0.1" + const val applicationId = "com.quyunshuo.androidbaseframemvvm" + const val minSdkVersion = 21 + const val targetSdkVersion = 30 + const val versionCode = 1 + const val versionName = "1.0" + const val isAppMode = false + + /** + * 项目当前的版本状态 + * 该状态直接反映当前App是测试版 还是正式版 或者预览版 + * 打包前记得修改该状态 + * 正式版:RELEASE、预览版(α)-内部测试版:ALPHA、测试版(β)-公开测试版:BETA + */ + const val versionStatus = /*"VERSION_STATUS_RELEASE"*/ "VERSION_STATUS_ALPHA" /*"VERSION_STATUS_BETA"*/ +} \ No newline at end of file diff --git a/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/ProjectPluginManager.kt b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/ProjectPluginManager.kt index ed74a20..027a0e8 100644 --- a/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/ProjectPluginManager.kt +++ b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/ProjectPluginManager.kt @@ -4,6 +4,7 @@ package com.quyunshuo.androidbaseframemvvm.build * 项目级插件管理 */ object ProjectPluginManager { - const val AndroidToolsPlugin = "com.android.tools.build:gradle:4.0.1" - const val KotlinPlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0" + const val AndroidToolsPlugin = "com.android.tools.build:gradle:4.1.2" + const val KotlinPlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31" + const val ARouterRegister = "com.alibaba:arouter-register:1.0.2" } \ No newline at end of file diff --git a/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/SDKKeyConfig.kt b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/SDKKeyConfig.kt new file mode 100644 index 0000000..894b653 --- /dev/null +++ b/buildSrc/src/main/java/com.quyunshuo.androidbaseframemvvm.build/SDKKeyConfig.kt @@ -0,0 +1,13 @@ +package com.quyunshuo.androidbaseframemvvm.build + +/** + * 存放需要存在本地的SDK的密钥 + */ +object SDKKeyConfig { + + /** + * Bugly APP_ID + * 正式环境需要与测试环境分开 正式ID:""、测试ID:"" + */ + const val BUGLY_APP_ID = "" +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e6128ab..2f9852d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip \ No newline at end of file diff --git a/moduleBase.gradle b/moduleBase.gradle index 0ababc3..d15a8fd 100644 --- a/moduleBase.gradle +++ b/moduleBase.gradle @@ -1,23 +1,22 @@ import com.quyunshuo.androidbaseframemvvm.build.* -if (BuildConfig.isAppMode) { +if (ProjectBuildConfig.isAppMode) { apply plugin: 'com.android.application' } else { apply plugin: 'com.android.library' } apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android { - compileSdkVersion BuildConfig.compileSdkVersion - buildToolsVersion BuildConfig.buildToolsVersion + compileSdkVersion ProjectBuildConfig.compileSdkVersion + buildToolsVersion ProjectBuildConfig.buildToolsVersion defaultConfig { - minSdkVersion BuildConfig.minSdkVersion - targetSdkVersion BuildConfig.targetSdkVersion - versionCode BuildConfig.versionCode - versionName BuildConfig.versionName + minSdkVersion ProjectBuildConfig.minSdkVersion + targetSdkVersion ProjectBuildConfig.targetSdkVersion + versionCode ProjectBuildConfig.versionCode + versionName ProjectBuildConfig.versionName testInstrumentationRunner AndroidX.AndroidJUnitRunner } @@ -37,7 +36,7 @@ android { //根据不同的模式加载不同的AndroidManifest文件 sourceSets { main { - if (BuildConfig.isAppMode) { + if (ProjectBuildConfig.isAppMode) { manifest.srcFile 'src/main/java/debug/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' @@ -64,7 +63,7 @@ android { kapt { arguments { arg("AROUTER_MODULE_NAME", project.name) - arg("eventBusIndex", "${BuildConfig.applicationId}.eventbus.index.${project.name.replace('Lib_', '')}EventIndex") + arg("eventBusIndex", "${ProjectBuildConfig.applicationId}.eventbus.index.${project.name.replace('Lib_', '')}EventIndex") } }