Jetpack Compose电商应用开发实战:从零构建完整电商项目

一、项目概述与设计思路

在移动应用开发领域,电商类应用一直是技术复杂度最高、功能模块最丰富的应用类型之一。本文将以”青商城”项目为例,详细介绍如何基于Kotlin + Jetpack Compose构建一个功能完善的Android电商应用。该项目采用现代化的技术栈和模块化架构,为开发者提供了一套完整的电商应用开发解决方案。

1.1 项目核心价值

青商城是一个完全开源免费的Android电商项目,专为国内开发环境设计,旨在为社区提供实用的Compose代码参考,帮助开发者快速掌握现代Android开发技术。项目采用100% Kotlin开发,全面拥抱现代语言特性,结合Jetpack Compose声明式UI框架,显著提升开发效率。

项目亮点

  • 现代化技术栈:采用MVVM + Clean Architecture架构,结合Hilt依赖注入、Coroutines协程、Flow响应式编程等主流技术
  • 模块化设计:参考Google官方Now in Android最佳实践,实现职责分离和并行开发
  • 完整电商功能:涵盖用户认证、商品展示、购物车、支付、订单管理等核心业务流程
  • 性能优化:支持深色模式、国际化、分页加载等高级特性,确保流畅的用户体验

二、技术选型与架构设计

2.1 核心技术栈

项目采用当前Android开发的主流技术栈,确保技术先进性和可维护性:

核心技术

  • 编程语言:Kotlin 2.2.21,100% Kotlin开发
  • UI框架:Jetpack Compose 2025.11.01,声明式UI框架
  • 架构模式:MVVM + Clean Architecture,清晰的分层架构
  • 依赖注入:Hilt 2.57.2,基于Dagger的依赖注入框架
  • 异步处理:Coroutines + Flow 1.9.0,协程和响应式编程

功能模块技术

  • 导航:Navigation Compose 2.9.6,Compose导航组件
  • 网络请求:Retrofit + OkHttp 3.0.0 + 5.3.2,HTTP客户端
  • 数据序列化:Kotlinx Serialization 1.9.0,JSON序列化处理
  • 图片加载:Coil Compose 2.7.0,图片加载与缓存
  • 动画效果:Lottie Compose 6.7.1,After Effects动画支持
  • 权限管理:XXPermissions 28.0,动态权限申请

数据存储

  • 数据库:Room 2.8.4,SQLite数据库
  • 本地存储:MMKV 2.2.4,高性能键值存储

2.2 模块化架构设计

项目采用模块化架构,参考Google官方的Now in Android最佳实践,目录结构清晰:

app/                    # 应用入口模块
build-logic/            # 构建逻辑
core/                   # 核心模块
  common/               # 通用工具和扩展
  data/                 # 数据层
  database/             # 数据库
  datastore/            # 数据存储
  designsystem/         # 设计系统
  model/                # 数据模型
  network/              # 网络层
  result/               # 结果处理
  ui/                   # UI组件
  util/                 # 工具类
feature/                # 功能模块
  auth/                 # 认证模块
  common/               # 公共模块
  cs/                   # 客服模块
  feedback/             # 反馈模块
  goods/                # 商品模块
  launch/               # 启动模块
  main/                 # 主模块
  market/               # 营销模块
  order/                # 订单模块
  user/                 # 用户模块
navigation/             # 导航模块

模块化优势

  • 职责分离:降低模块间耦合,提高代码可维护性
  • 并行开发:支持团队协作,提升开发效率
  • 增量编译:显著提升构建速度,优化开发体验
  • 便于测试:模块化设计便于单元测试和功能验证

三、核心功能模块实现

3.1 用户认证模块

认证模块实现了完整的用户登录注册流程,支持多种登录方式:

// 登录页面
@Composable
fun LoginScreen(
    viewModel: LoginViewModel = hiltViewModel(),
    onLoginSuccess: () -> Unit
) {
    val uiState by viewModel.uiState.collectAsState()
    
    Scaffold(
        topBar = { TopBar(title = "登录") }
    ) { paddingValues ->
        Column(
            modifier = Modifier
                .padding(paddingValues)
                .fillMaxSize()
                .padding(16.dp)
        ) {
            // 账号输入框
            OutlinedTextField(
                value = uiState.username,
                onValueChange = { viewModel.onUsernameChange(it) },
                label = { Text("手机号/邮箱") },
                modifier = Modifier.fillMaxWidth()
            )
            
            Spacer(modifier = Modifier.height(16.dp))
            
            // 密码输入框
            OutlinedTextField(
                value = uiState.password,
                onValueChange = { viewModel.onPasswordChange(it) },
                label = { Text("密码") },
                visualTransformation = PasswordVisualTransformation(),
                modifier = Modifier.fillMaxWidth()
            )
            
            Spacer(modifier = Modifier.height(24.dp))
            
            // 登录按钮
            Button(
                onClick = { viewModel.login() },
                modifier = Modifier.fillMaxWidth(),
                enabled = uiState.isFormValid
            ) {
                Text("登录")
            }
            
            // 注册和忘记密码
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween
            ) {
                TextButton(onClick = { /* 跳转注册 */ }) {
                    Text("立即注册")
                }
                TextButton(onClick = { /* 忘记密码 */ }) {
                    Text("忘记密码")
                }
            }
        }
    }
}

ViewModel实现

@HiltViewModel
class LoginViewModel @Inject constructor(
    private val authRepository: AuthRepository
) : ViewModel() {
    
    private val _uiState = MutableStateFlow(LoginUiState())
    val uiState: StateFlow<LoginUiState> = _uiState.asStateFlow()
    
    fun onUsernameChange(username: String) {
        _uiState.update { it.copy(username = username) }
        validateForm()
    }
    
    fun onPasswordChange(password: String) {
        _uiState.update { it.copy(password = password) }
        validateForm()
    }
    
    fun login() {
        viewModelScope.launch {
            _uiState.update { it.copy(isLoading = true) }
            try {
                val result = authRepository.login(
                    username = _uiState.value.username,
                    password = _uiState.value.password
                )
                if (result.isSuccess) {
                    onLoginSuccess()
                } else {
                    _uiState.update { it.copy(error = result.errorMessage) }
                }
            } catch (e: Exception) {
                _uiState.update { it.copy(error = "网络异常,请重试") }
            } finally {
                _uiState.update { it.copy(isLoading = false) }
            }
        }
    }
    
    private fun validateForm() {
        val currentState = _uiState.value
        val isValid = currentState.username.isNotBlank() && 
                     currentState.password.isNotBlank()
        _uiState.update { it.copy(isFormValid = isValid) }
    }
}

3.2 商品展示模块

商品模块实现了商品列表、搜索、分类等功能,采用LazyColumn实现高效分页加载:

// 商品列表页面
@Composable
fun ProductListScreen(
    categoryId: String? = null,
    viewModel: ProductListViewModel = hiltViewModel()
) {
    val products by viewModel.products.collectAsState()
    val isLoading by viewModel.isLoading.collectAsState()
    
    Scaffold(
        topBar = { SearchTopBar(onSearch = { viewModel.searchProducts(it) }) }
    ) { paddingValues ->
        Box(modifier = Modifier.padding(paddingValues)) {
            LazyColumn(
                modifier = Modifier.fillMaxSize(),
                contentPadding = PaddingValues(8.dp)
            ) {
                items(
                    items = products,
                    key = { it.id }
                ) { product ->
                    ProductItem(
                        product = product,
                        onItemClick = { /* 跳转详情 */ }
                    )
                }
                
                // 加载更多
                item {
                    if (isLoading) {
                        CircularProgressIndicator(
                            modifier = Modifier
                                .fillMaxWidth()
                                .wrapContentWidth()
                                .padding(16.dp)
                        )
                    }
                }
            }
        }
    }
    
    LaunchedEffect(categoryId) {
        viewModel.loadProducts(categoryId)
    }
}

// 商品项组件
@Composable
fun ProductItem(
    product: Product,
    onItemClick: (Product) -> Unit
) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
            .clickable { onItemClick(product) },
        elevation = 4.dp
    ) {
        Column {
            // 商品图片
            AsyncImage(
                model = product.imageUrl,
                contentDescription = product.name,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp),
                contentScale = ContentScale.Crop
            )
            
            // 商品信息
            Column(modifier = Modifier.padding(16.dp)) {
                Text(
                    text = product.name,
                    style = MaterialTheme.typography.h6,
                    maxLines = 2,
                    overflow = TextOverflow.Ellipsis
                )
                
                Spacer(modifier = Modifier.height(8.dp))
                
                Text(
                    text = "¥${product.price}",
                    style = MaterialTheme.typography.subtitle1,
                    color = MaterialTheme.colorScheme.primary
                )
                
                Spacer(modifier = Modifier.height(8.dp))
                
                // 销量和评价
                Row(
                    horizontalArrangement = Arrangement.SpaceBetween,
                    modifier = Modifier.fillMaxWidth()
                ) {
                    Text(
                        text = "销量:${product.sales}",
                        style = MaterialTheme.typography.body2,
                        color = Color.Gray
                    )
                    Text(
                        text = "评价:${product.rating}",
                        style = MaterialTheme.typography.body2,
                        color = Color.Gray
                    )
                }
            }
        }
    }
}

3.3 购物车模块

购物车模块实现了商品添加、数量修改、价格计算等功能:

// 购物车页面
@Composable
fun CartScreen(
    viewModel: CartViewModel = hiltViewModel()
) {
    val cartItems by viewModel.cartItems.collectAsState()
    val totalPrice by viewModel.totalPrice.collectAsState()
    
    Scaffold(
        topBar = { TopBar(title = "购物车") },
        bottomBar = {
            CartBottomBar(
                totalPrice = totalPrice,
                onCheckout = { /* 结算 */ }
            )
        }
    ) { paddingValues ->
        if (cartItems.isEmpty()) {
            EmptyCart()
        } else {
            LazyColumn(
                modifier = Modifier.padding(paddingValues),
                contentPadding = PaddingValues(8.dp)
            ) {
                items(
                    items = cartItems,
                    key = { it.id }
                ) { cartItem ->
                    CartItem(
                        cartItem = cartItem,
                        onIncrease = { viewModel.increaseQuantity(cartItem.id) },
                        onDecrease = { viewModel.decreaseQuantity(cartItem.id) },
                        onRemove = { viewModel.removeFromCart(cartItem.id) }
                    )
                }
            }
        }
    }
}

// 购物车项组件
@Composable
fun CartItem(
    cartItem: CartItem,
    onIncrease: () -> Unit,
    onDecrease: () -> Unit,
    onRemove: () -> Unit
) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp),
        elevation = 2.dp
    ) {
        Row(
            modifier = Modifier.padding(16.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            // 商品图片
            AsyncImage(
                model = cartItem.imageUrl,
                contentDescription = cartItem.name,
                modifier = Modifier
                    .size(80.dp)
                    .clip(RoundedCornerShape(8.dp)),
                contentScale = ContentScale.Crop
            )
            
            Spacer(modifier = Modifier.width(16.dp))
            
            // 商品信息
            Column(
                modifier = Modifier.weight(1f)
            ) {
                Text(
                    text = cartItem.name,
                    style = MaterialTheme.typography.h6,
                    maxLines = 2,
                    overflow = TextOverflow.Ellipsis
                )
                
                Spacer(modifier = Modifier.height(4.dp))
                
                Text(
                    text = "¥${cartItem.price}",
                    style = MaterialTheme.typography.subtitle1,
                    color = MaterialTheme.colorScheme.primary
                )
            }
            
            // 数量操作
            Row(
                verticalAlignment = Alignment.CenterVertically
            ) {
                IconButton(
                    onClick = onDecrease,
                    enabled = cartItem.quantity > 1
                ) {
                    Icon(Icons.Default.Remove, contentDescription = "减少")
                }
                
                Text(
                    text = cartItem.quantity.toString(),
                    modifier = Modifier.padding(horizontal = 8.dp)
                )
                
                IconButton(onClick = onIncrease) {
                    Icon(Icons.Default.Add, contentDescription = "增加")
                }
                
                Spacer(modifier = Modifier.width(8.dp))
                
                IconButton(onClick = onRemove) {
                    Icon(Icons.Default.Delete, contentDescription = "删除")
                }
            }
        }
    }
}

3.4 订单模块

订单模块实现了订单创建、支付、详情查看等功能:

// 订单确认页面
@Composable
fun OrderConfirmScreen(
    viewModel: OrderConfirmViewModel = hiltViewModel()
) {
    val order by viewModel.order.collectAsState()
    val address by viewModel.selectedAddress.collectAsState()
    
    Scaffold(
        topBar = { TopBar(title = "确认订单") },
        bottomBar = {
            OrderBottomBar(
                totalAmount = order.totalAmount,
                onPlaceOrder = { viewModel.placeOrder() }
            )
        }
    ) { paddingValues ->
        LazyColumn(
            modifier = Modifier.padding(paddingValues),
            contentPadding = PaddingValues(8.dp)
        ) {
            // 收货地址
            item {
                AddressCard(
                    address = address,
                    onClick = { /* 选择地址 */ }
                )
            }
            
            // 商品列表
            items(
                items = order.items,
                key = { it.id }
            ) { item ->
                OrderItem(item = item)
            }
            
            // 价格明细
            item {
                PriceDetail(
                    subtotal = order.subtotal,
                    shippingFee = order.shippingFee,
                    discount = order.discount,
                    totalAmount = order.totalAmount
                )
            }
        }
    }
}

// 订单支付页面
@Composable
fun OrderPayScreen(
    orderId: String,
    viewModel: OrderPayViewModel = hiltViewModel()
) {
    val paymentMethods by viewModel.paymentMethods.collectAsState()
    val selectedMethod by viewModel.selectedMethod.collectAsState()
    
    Scaffold(
        topBar = { TopBar(title = "支付订单") },
        bottomBar = {
            PaymentBottomBar(
                amount = viewModel.orderAmount,
                onPay = { viewModel.payOrder() }
            )
        }
    ) { paddingValues ->
        Column(
            modifier = Modifier.padding(paddingValues)
        ) {
            // 支付方式选择
            Text(
                text = "选择支付方式",
                style = MaterialTheme.typography.h6,
                modifier = Modifier.padding(16.dp)
            )
            
            paymentMethods.forEach { method ->
                PaymentMethodItem(
                    method = method,
                    isSelected = method == selectedMethod,
                    onSelect = { viewModel.selectPaymentMethod(method) }
                )
            }
        }
    }
}

四、性能优化实践

4.1 状态管理优化

在Compose开发中,状态管理是性能优化的关键。通过合理使用remember和derivedStateOf,可以避免不必要的重组:

@Composable
fun ProductListScreen(
    viewModel: ProductListViewModel = hiltViewModel()
) {
    val products by viewModel.products.collectAsState()
    
    // 使用derivedStateOf优化滚动状态
    val listState = rememberLazyListState()
    val shouldLoadMore by remember {
        derivedStateOf {
            val layoutInfo = listState.layoutInfo
            val totalItems = layoutInfo.totalItemsCount
            val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0
            lastVisibleItem >= totalItems - 5
        }
    }
    
    LaunchedEffect(shouldLoadMore) {
        if (shouldLoadMore && !viewModel.isLoading.value) {
            viewModel.loadMore()
        }
    }
    
    LazyColumn(state = listState) {
        items(products, key = { it.id }) { product ->
            ProductItem(product = product)
        }
    }
}

4.2 图片加载优化

使用Coil进行图片加载时,通过配置缓存策略和占位图提升用户体验:

@Composable
fun ProductImage(
    imageUrl: String,
    contentDescription: String? = null
) {
    AsyncImage(
        model = ImageRequest.Builder(LocalContext.current)
            .data(imageUrl)
            .crossfade(true)
            .diskCachePolicy(CachePolicy.ENABLED)
            .memoryCachePolicy(CachePolicy.ENABLED)
            .placeholder(R.drawable.placeholder_product)
            .error(R.drawable.error_product)
            .build(),
        contentDescription = contentDescription,
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .fillMaxWidth()
            .height(200.dp)
            .clip(RoundedCornerShape(8.dp))
    )
}

4.3 网络请求优化

通过Retrofit和OkHttp配置网络请求,实现缓存和超时控制:

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = if (BuildConfig.DEBUG) {
                    HttpLoggingInterceptor.Level.BODY
                } else {
                    HttpLoggingInterceptor.Level.NONE
                }
            })
            .addInterceptor { chain ->
                val request = chain.request().newBuilder()
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Accept", "application/json")
                    .build()
                chain.proceed(request)
            }
            .build()
    }
    
    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl(BuildConfig.BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
            .build()
    }
}

五、主题与样式系统

5.1 设计系统定义

通过MaterialTheme扩展自定义主题,实现统一的设计规范:

@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colors = if (darkTheme) {
        DarkColorScheme
    } else {
        LightColorScheme
    }
    
    MaterialTheme(
        colorScheme = colors,
        typography = Typography,
        shapes = Shapes,
        content = content
    )
}

private val LightColorScheme = lightColorScheme(
    primary = Color(0xFF6200EE),
    primaryContainer = Color(0xFF3700B3),
    secondary = Color(0xFF03DAC6),
    secondaryContainer = Color(0xFF018786),
    background = Color(0xFFFFFFFF),
    surface = Color(0xFFFFFFFF),
    error = Color(0xFFB00020),
    onPrimary = Color.White,
    onSecondary = Color.Black,
    onBackground = Color.Black,
    onSurface = Color.Black,
    onError = Color.White
)

private val DarkColorScheme = darkColorScheme(
    primary = Color(0xFFBB86FC),
    primaryContainer = Color(0xFF3700B3),
    secondary = Color(0xFF03DAC6),
    secondaryContainer = Color(0xFF03DAC6),
    background = Color(0xFF121212),
    surface = Color(0xFF121212),
    error = Color(0xFFCF6679),
    onPrimary = Color.Black,
    onSecondary = Color.Black,
    onBackground = Color.White,
    onSurface = Color.White,
    onError = Color.Black
)

val Typography = Typography(
    displayLarge = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 57.sp,
        lineHeight = 64.sp,
        letterSpacing = (-0.25).sp
    ),
    // 其他文本样式...
)

val Shapes = Shapes(
    small = RoundedCornerShape(4.dp),
    medium = RoundedCornerShape(8.dp),
    large = RoundedCornerShape(12.dp)
)

5.2 自定义组件

通过Compose的@Composable函数封装可复用的UI组件:

@Composable
fun PrimaryButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    isLoading: Boolean = false
) {
    Button(
        onClick = onClick,
        modifier = modifier
            .fillMaxWidth()
            .height(48.dp),
        enabled = enabled && !isLoading,
        colors = ButtonDefaults.buttonColors(
            containerColor = MaterialTheme.colorScheme.primary,
            contentColor = MaterialTheme.colorScheme.onPrimary
        )
    ) {
        if (isLoading) {
            CircularProgressIndicator(
                color = MaterialTheme.colorScheme.onPrimary,
                strokeWidth = 2.dp,
                modifier = Modifier.size(20.dp)
            )
        } else {
            Text(
                text = text,
                style = MaterialTheme.typography.labelLarge
            )
        }
    }
}

@Composable
fun PriceText(
    price: Double,
    originalPrice: Double? = null,
    modifier: Modifier = Modifier
) {
    Row(
        modifier = modifier,
        verticalAlignment = Alignment.CenterVertically
    ) {
        Text(
            text = "¥${price.formatPrice()}",
            style = MaterialTheme.typography.titleMedium,
            color = MaterialTheme.colorScheme.primary
        )
        
        originalPrice?.let {
            Spacer(modifier = Modifier.width(8.dp))
            Text(
                text = "¥${it.formatPrice()}",
                style = MaterialTheme.typography.bodyMedium,
                color = Color.Gray,
                textDecoration = TextDecoration.LineThrough
            )
        }
    }
}

private fun Double.formatPrice(): String {
    return String.format("%.2f", this)
}

六、测试与调试

6.1 单元测试

通过JUnit和MockK编写ViewModel和Repository的单元测试:

class ProductListViewModelTest {
    
    @get:Rule
    val testRule = InstantTaskExecutorRule()
    
    private lateinit var viewModel: ProductListViewModel
    private lateinit var productRepository: ProductRepository
    
    @Before
    fun setup() {
        productRepository = mockk()
        viewModel = ProductListViewModel(productRepository)
    }
    
    @Test
    fun `loadProducts should update products when successful`() = runTest {
        // Arrange
        val mockProducts = listOf(
            Product(
                id = "1",
                name = "Test Product",
                price = 99.99,
                imageUrl = "https://example.com/image.jpg"
            )
        )
        coEvery { productRepository.getProducts(any()) } returns Result.success(mockProducts)
        
        // Act
        viewModel.loadProducts()
        
        // Assert
        val uiState = viewModel.products.value
        assertThat(uiState).isEqualTo(mockProducts)
    }
    
    @Test
    fun `loadProducts should handle error`() = runTest {
        // Arrange
        coEvery { productRepository.getProducts(any()) } returns Result.failure("Network error")
        
        // Act
        viewModel.loadProducts()
        
        // Assert
        val errorState = viewModel.error.value
        assertThat(errorState).isEqualTo("Network error")
    }
}

6.2 UI测试

使用Compose的测试API编写UI组件测试:

class ProductItemTest {
    
    @get:Rule
    val composeTestRule = createComposeRule()
    
    @Test
    fun productItem_shouldDisplayCorrectInformation() {
        val product = Product(
            id = "1",
            name = "Test Product",
            price = 99.99,
            imageUrl = "https://example.com/image.jpg"
        )
        
        composeTestRule.setContent {
            AppTheme {
                ProductItem(product = product, onItemClick = {})
            }
        }
        
        composeTestRule.onNodeWithText("Test Product").assertExists()
        composeTestRule.onNodeWithText("¥99.99").assertExists()
    }
    
    @Test
    fun productItem_shouldTriggerOnClick() {
        val product = Product(
            id = "1",
            name = "Test Product",
            price = 99.99,
            imageUrl = "https://example.com/image.jpg"
        )
        var clicked = false
        
        composeTestRule.setContent {
            AppTheme {
                ProductItem(
                    product = product,
                    onItemClick = { clicked = true }
                )
            }
        }
        
        composeTestRule.onNodeWithText("Test Product").performClick()
        assertThat(clicked).isTrue()
    }
}

6.3 性能测试

使用Macrobenchmark进行性能基准测试:

@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
    
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()
    
    @Test
    fun startup() {
        benchmarkRule.measureRepeated(
            packageName = "com.qingmall.app",
            metrics = listOf(
                StartupTimingMetric(),
                FrameTimingMetric()
            ),
            iterations = 5,
            startupMode = StartupMode.COLD
        ) {
            pressHome()
            startActivityAndWait()
            
            // 模拟用户操作
            device.waitForIdle()
            device.wait(Until.hasObject(By.res("home_screen")), 5000)
        }
    }
}

七、部署与发布

7.1 构建配置

通过Gradle配置实现多环境构建:

// app/build.gradle.kts
android {
    compileSdk = 34
    
    defaultConfig {
        applicationId = "com.qingmall.app"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0.0"
        
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }
    
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        debug {
            applicationIdSuffix = ".debug"
            isDebuggable = true
        }
    }
    
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    
    kotlinOptions {
        jvmTarget = "17"
    }
    
    buildFeatures {
        compose = true
    }
    
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.11"
    }
    
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
    
    flavorDimensions += "environment"
    productFlavors {
        create("dev") {
            dimension = "environment"
            applicationIdSuffix = ".dev"
            versionNameSuffix = "-dev"
            buildConfigField("String", "BASE_URL", "\"https://dev.api.qingmall.com/\"")
        }
        create("prod") {
            dimension = "environment"
            buildConfigField("String", "BASE_URL", "\"https://api.qingmall.com/\"")
        }
    }
}

7.2 持续集成

通过GitHub Actions实现自动化构建和测试:

name: Android CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main, develop ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'temurin'
        cache: gradle
        
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
        
    - name: Build with Gradle
      run: ./gradlew build
        
    - name: Run tests
      run: ./gradlew test
        
    - name: Upload APK
      uses: actions/upload-artifact@v3
      with:
        name: app
        path: app/build/outputs/apk/

八、总结与展望

通过”青商城”项目的完整实现,我们展示了如何使用Kotlin + Jetpack Compose构建现代化Android电商应用的全过程。项目采用MVVM + Clean Architecture架构,结合Hilt、Coroutines、Room等主流技术,实现了用户认证、商品展示、购物车、订单管理等核心功能。

项目特色

  • 现代化技术栈:全面采用Kotlin和Jetpack Compose,提升开发效率和代码质量
  • 模块化设计:清晰的架构分层,便于团队协作和功能扩展
  • 性能优化:通过状态管理、图片加载、网络请求等多方面优化,确保流畅体验
  • 完整功能:覆盖电商应用的核心业务流程,可直接用于实际项目开发

未来规划

  • 完善商品评价、优惠券、营销活动等高级功能
  • 支持更多支付方式和物流跟踪
  • 优化性能监控和错误追踪系统
  • 扩展多平台支持(如平板、折叠屏设备)

该项目不仅是一个功能完善的电商应用,更是一个学习现代Android开发技术的优秀参考案例。通过阅读和理解项目代码,开发者可以快速掌握Jetpack Compose、MVVM架构、协程编程等核心技术,为实际项目开发打下坚实基础。

版权声明:本文为JienDa博主的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
若内容若侵犯到您的权益,请发送邮件至:platform_service@jienda.com我们将第一时间处理!
所有资源仅限于参考和学习,版权归JienDa作者所有,更多请访问JienDa首页。

给TA赞助
共{{data.count}}人
人已赞助
Android

Flutter气泡弹窗库封装实战:从零到一打造精致UI组件

2025-12-23 22:25:07

Android

Android Studio新版本Activity模板解析:全面屏与Edge-to-Edge适配指南

2025-12-24 23:27:04

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索