Kotlin与Flutter:跨平台开发的互补之道与实战指南

7 阅读3分钟

在跨平台开发领域,Kotlin Multiplatform(KMP)与Flutter的协同使用正在成为新趋势。本文通过完整的代码示例和架构拆解,展示二者如何实现1+1>2的开发效能提升。

一、混合开发实战:电商应用案例

项目结构

mobile-app/
├── shared/                 # KMP核心模块
│   ├── src/commonMain/     # 公共业务逻辑
│   ├── src/androidMain/    # Android平台实现
│   └── src/iosMain/        # iOS平台实现
├── flutter_ui/             # Flutter界面层
└── native_android/         # 原生容器(可选)

1. 业务逻辑共享层(KMP)

// shared/src/commonMain/kotlin/com/example/shared/ProductRepository.kt
expect class PlatformHttpClient {
    fun get(url: String): String
}

class ProductRepository(private val httpClient: PlatformHttpClient) {
    suspend fun fetchProduct(id: Int): Product {
        val json = httpClient.get("https://api.example.com/products/$id")
        return Json.decodeFromString(json)
    }
}

// Android实现
actual class PlatformHttpClient {
    actual fun get(url: String): String {
        return runBlocking {
            HttpClient(Android) {
                install(JsonFeature) {
                    serializer = KotlinxSerializer()
                }
            }.use { client ->
                client.get(url).bodyAsText()
            }
        }
    }
}

// iOS实现
actual class PlatformHttpClient {
    actual fun get(url: String): String {
        return NSString.stringWithContentsOfURL(
            NSURL.URLWithString(url)!,
            encoding = NSUTF8StringEncoding,
            error = null
        ) as String
    }
}

2. Flutter UI层实现

// flutter_ui/lib/product_detail.dart
class ProductDetailPage extends StatelessWidget {
  final int productId;

  ProductDetailPage({required this.productId});

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Product>(
      future: _fetchProduct(productId),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return Scaffold(
            appBar: AppBar(title: Text(snapshot.data!.name)),
            body: _buildProductDetail(snapshot.data!),
          );
        } else if (snapshot.hasError) {
          return ErrorWidget(snapshot.error!);
        }
        return CircularProgressIndicator();
      },
    );
  }

  Future<Product> _fetchProduct(int id) async {
    // 通过MethodChannel调用KMP模块
    const channel = MethodChannel('com.example.product');
    final json = await channel.invokeMethod('getProduct', {'id': id});
    return Product.fromJson(jsonDecode(json));
  }

  Widget _buildProductDetail(Product product) {
    return ListView(
      children: [
        Image.network(product.imageUrl),
        Text('\$${product.price}', style: TextStyle(fontSize: 24)),
        Platform.isIOS 
            ? CupertinoButton(onPressed: _addToCart, child: Text("添加到购物车"))
            : ElevatedButton(onPressed: _addToCart, child: Text("加入购物车")),
      ],
    );
  }
}

3. 原生平台桥接层(Android示例)

// native_android/app/src/main/java/com/example/MainActivity.kt
class MainActivity : FlutterActivity() {
    private val productRepo by lazy { ProductRepository(PlatformHttpClient()) }

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.product")
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "getProduct" -> {
                        val id = call.argument<Int>("id") ?: 0
                        CoroutineScope(Dispatchers.IO).launch {
                            try {
                                val product = productRepo.fetchProduct(id)
                                result.success(Json.encodeToString(product))
                            } catch (e: Exception) {
                                result.error("FETCH_ERROR", e.message, null)
                            }
                        }
                    }
                    else -> result.notImplemented()
                }
            }
    }
}

二、深度集成方案

1. 状态管理跨平台同步

// shared/src/commonMain/kotlin/com/example/shared/CartManager.kt
class CartManager {
    private val _cartItems = MutableStateFlow<List<CartItem>>(emptyList())
    val cartItems: StateFlow<List<CartItem>> = _cartItems

    fun addItem(item: CartItem) {
        _cartItems.update { current -> current + item }
    }
}

// Flutter端状态监听
void _connectCartState() {
  const eventChannel = EventChannel('com.example.cart/updates');
  eventChannel.receiveBroadcastStream().listen((data) {
    final items = (data as List).map((e) => CartItem.fromJson(e)).toList();
    context.read<CartProvider>().updateItems(items);
  });
}

2. 性能关键路径优化

// shared/src/commonMain/kotlin/com/example/shared/ImageProcessor.kt
expect class NativeImageProcessor {
    fun applyFilter(bitmap: ByteArray, filterType: Int): ByteArray
}

// Android使用RenderScript加速
actual class NativeImageProcessor {
    actual fun applyFilter(bitmap: ByteArray, filterType: Int): ByteArray {
        val rs = RenderScript.create(context)
        val input = Allocation.createFromBitmap(rs, BitmapFactory.decodeByteArray(bitmap))
        val output = Allocation.createTyped(rs, input.type)
        ScriptC_contrast(rs).apply {
            _amount = 1.5f
            forEach_root(input, output)
        }
        val result = Bitmap.createBitmap(input.width, input.height, Bitmap.Config.ARGB_8888)
        output.copyTo(result)
        return result.toByteArray()
    }
}

三、构建与部署配置

1. 多模块Gradle配置

// shared/build.gradle.kts
kotlin {
    androidTarget()
    iosX64()
    iosArm64()
    iosSimulatorArm64()

    sourceSets {
        commonMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
            implementation("io.ktor:ktor-client-core:2.3.4")
        }
        androidMain.dependencies {
            implementation("io.ktor:ktor-client-okhttp:2.3.4")
        }
    }
}

2. Flutter混合打包脚本

#!/bin/bash
# build_kmp_and_flutter.sh

# 编译KMP共享库
./gradlew :shared:assemble

# 生成iOS Framework
cp -R shared/build/bin/iosArm64/releaseFramework/shared.framework flutter_ui/ios/

# 构建Flutter产物
cd flutter_ui && flutter build ios --release

四、调试与监控体系

1. 跨平台日志收集

// shared/src/commonMain/kotlin/com/example/shared/Logger.kt
expect fun logToCrashlytics(tag: String, message: String)

// Flutter端实现
actual fun logToCrashlytics(tag: String, message: String) {
    FirebaseCrashlytics.instance.log("[$tag] $message")
}

// 统一调用入口
fun logError(exception: Throwable) {
    logToCrashlytics("ERROR", exception.stackTraceToString())
    exception.printStackTrace()
}

2. 性能监控面板

// flutter_ui/lib/perf_monitor.dart
class PerformanceOverlay extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<PerfMetric>(
      stream: NativePerformance.metricsStream(),
      builder: (context, snapshot) {
        return CustomPaint(
          painter: _PerfPainter(snapshot.data),
          size: Size.infinite,
        );
      },
    );
  }
}

class _PerfPainter extends CustomPainter {
  final PerfMetric? data;

  void paint(Canvas canvas, Size size) {
    if (data == null) return;
    // 绘制CPU/内存曲线图
    _drawGraph(canvas, data!.cpuUsage);
    _drawGraph(canvas, data!.memoryUsage);
  }
}

五、演进路线建议

  1. 初期阶段:使用Flutter快速搭建UI原型,核心业务逻辑仍保留在原生侧
  2. 中期过渡:逐步将通用业务逻辑迁移到KMP,形成清晰的模块边界
  3. 成熟阶段:实现Flutter与KMP的深度整合,建立自动化CI/CD流程
  4. 扩展阶段:向桌面端(Windows/macOS/Linux)及嵌入式设备延伸

结语:通过KMP与Flutter的有机组合,开发者既能享受Flutter高效的UI开发体验,又能通过KMP保障核心业务逻辑的性能与一致性。这种架构模式特别适用于中大型项目,建议从关键模块开始渐进式改造,最终实现全栈式的跨平台能力升级。