2. 项目初始化与依赖配置

本章将引导你从零搭建一个以离线优先为核心理念的 Android 项目,并完成核心依赖库的引入与 Gradle 配置。我们将依次完成:项目骨架创建、依赖版本管理、Room / WorkManager / 网络库 / 依赖注入框架的集成,以及构建脚本的优化。正确的初始化与配置是后续章节所有离线能力的基石。

2.1 创建 Android 项目

使用 Android Studio 的 New Project 向导,选择 Empty Views Activity 模板,包名建议采用 com.yourdomain.offlinefirst。最低 SDK 版本推荐 API 24(Android 7.0),以确保 Room 和 WorkManager 的完整支持。项目创建后,立即检查 gradle/libs.versions.toml 是否存在——如果使用 Android Studio Hedgehog 或更高版本,项目默认采用版本目录(Version Catalog)管理依赖,这正是我们需要的。

提示: 如果向导未自动生成 libs.versions.toml,可在项目根目录下手动创建 gradle/libs.versions.toml 文件。版本目录是大型团队协作的最佳实践,能统一所有模块的依赖版本。

2.2 版本目录与核心依赖声明

编辑 gradle/libs.versions.toml,定义全局版本变量与依赖库坐标。下面的配置涵盖了离线优先应用最关键的四个组件:

[versions]
kotlin = "1.9.22"
agp = "8.2.2"
room = "2.6.1"
work = "2.9.0"
retrofit = "2.9.0"
okhttp = "4.12.0"
hilt = "2.50"
ksp = "1.9.22-1.0.17"
coroutines = "1.8.0"

[libraries]
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
work-runtime = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "work" }
retrofit-core = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }

2.3 模块级 build.gradle.kts 配置

在 app/build.gradle.kts 中应用插件并添加依赖库。注意 Room 的编译器使用 KSP 而非 kapt,这能显著提升注解处理速度。

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.ksp)
    alias(libs.plugins.hilt)
}

android {
    namespace = "com.yourdomain.offlinefirst"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.yourdomain.offlinefirst"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0.0"
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = "17"
    }

    // 开启 BuildConfig 以在代码中使用版本号等常量
    buildFeatures {
        buildConfig = true
    }

    // 如果使用 Room 的实体多表关联,需要启用 schema 导出
    ksp {
        arg("room.schemaLocation", "$projectDir/schemas")
    }
}

dependencies {
    // Room
    implementation(libs.room.runtime)
    implementation(libs.room.ktx)
    ksp(libs.room.compiler)

    // WorkManager
    implementation(libs.work.runtime)

    // 网络层
    implementation(libs.retrofit.core)
    implementation(libs.retrofit.gson)
    implementation(libs.okhttp.logging)

    // 依赖注入
    implementation(libs.hilt.android)
    ksp(libs.hilt.compiler)

    // 协程
    implementation(libs.coroutines.core)

    // 测试依赖(可选)
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}

2.4 项目级 build.gradle.kts 与 settings.gradle.kts

确保项目级文件正确应用了版本目录和 KSP 插件。典型配置如下:

// 项目根 build.gradle.kts
plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.kotlin.android) apply false
    alias(libs.plugins.ksp) apply false
    alias(libs.plugins.hilt) apply false
}

// settings.gradle.kts
pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "OfflineFirstApp"
include(":app")
注意: 如果你使用 Android Studio 内置的 Hilt 插件安装向导,可能会同时依赖 kapt。请务必手动移除 kapt 并用 ksp 替代,否则会出现重复注解处理。检查 app/build.gradle.kts 中不应出现 kapt 相关行。

2.5 添加 Application 类与 Hilt 入口

Hilt 要求应用提供 @HiltAndroidApp 注解的 Application 子类。在 OfflineFirstApp.kt 中添加:

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class OfflineFirstApp : Application()

记得在 AndroidManifest.xml 的 <application> 标签中指定 android:name=".OfflineFirstApp"。

2.6 网络层与 WorkManager 初始化配置

在 OfflineFirstApp 中或者通过独立的 Hilt Module 配置 OkHttp 客户端和 Retrofit 实例。WorkManager 不需要额外初始化代码,只要依赖添加正确即可自动使用默认配置。若需自定义 WorkManager 初始化(例如更改线程池大小),可在 AndroidManifest.xml 中用 android:name="androidx.work.impl.WorkManagerInitializer" 节点覆盖默认 provider。

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}

2.7 常见错误与调试

错误现象原因解决方案
Room 编译报错:Cannot find symbolKSP 插件版本与 Room 版本不兼容,或未添加 KSP 插件检查 libs.versions.toml 中 ksp 版本号是否与 Kotlin 版本匹配(例如 1.9.22‑1.0.17)
WorkManager 在 Android 12+ 上崩溃未添加 android:foregroundServiceType 权限声明在 AndroidManifest.xml 的 <service> 中设置 android:foregroundServiceType="dataSync"
Hilt 注入时出现 Dagger does not support injection into @HiltViewModelViewModel 未使用 @HiltViewModel 注解添加 @HiltViewModel 并使用 @Inject constructor
Retrofit 接口调用无网络日志OkHttp 日志拦截器等级设置不正确使用 BODY 或 HEADERS,并确保调试 Build 下生效(可添加 addNetworkInterceptor)

2.8 性能与稳定性优化建议

  • 使用版本目录(Version Catalog):避免硬编码版本号,避免多模块版本漂移。
  • 启用 Room 的 WAL 模式:在 Room.databaseBuilder() 中调用 .setJournalMode(JournalMode.WRITE_AHEAD_LOGGING) 可提升并发写入性能。
  • WorkManager 的唯一工作名称:为同步任务指定唯一 WorkRequest 名称(OneTimeWorkRequest.from),防止重复调度。
  • 网络超时设置:在 OkHttp 中设置合理的 connectTimeout 和 readTimeout(例如 15 秒),避免无响应挂起。
  • 保留混淆规则:添加 proguard-rules.pro,保留 Room 实体、Retrofit 接口、Hilt 生成的类:
-keep class * extends androidx.room.RoomDatabase { *; }
-keepclassmembers,allowobfuscation class * {
    @com.google.gson.annotations.SerializedName <fields>;
}
-keep class dagger.hilt.** { *; }
本章核心成果: 完成了一个具备离线存储(Room)、后台任务(WorkManager)、网络请求(Retrofit+OkHttp)和依赖注入(Hilt)的可运行 Android 项目骨架。此时执行 ./gradlew assembleDebug 应能成功编译。
项目初始化与依赖配置架构 项目初始化与依赖配置架构图 app 模块 build.gradle.kts (模块级) + libs.versions.toml 插件应用 · 编译选项 · 依赖声明 · KSP 参数 Room 运行时 · KTX · 编译器(KSP) WorkManager work-runtime-ktx 网络层 Retrofit · OkHttp · Gson Hilt (DI) hilt-android · compiler(KSP) Kotlin 协程 异步基石,配合 Room / WorkManager AndroidManifest Application 声明 · 权限 · ForegroundService 所有深色节点内文字均使用 #ffffff,确保高对比度可读性

上图展示了离线优先应用的依赖层次:app 模块通过 Gradle 配置与版本目录 引入 Room / WorkManager / 网络层 / Hilt 四大核心库,底部辅助工具(协程与 Manifest 配置)为骨架提供运行时支持。箭头方向表示配置依赖关系。接下来每一章都将基于此骨架扩展功能。