從 Flutter 應用程式啟動 Jetpack Compose Activity
瞭解如何在 Flutter 應用中啟動原生 Android Activity。
原生 Android Activity 允許你啟動由 Android 平臺完全執行的全屏介面。在這些檢視中,你只需編寫 Kotlin 程式碼(儘管它們可以與 Dart 程式碼進行訊息傳遞),並且可以訪問 Android 原生的全部功能。
新增此功能需要對 Flutter 應用及其內部生成的 Android 應用進行多項更改。在 Flutter 端,你需要建立一個新的平臺 MethodChannel 並呼叫其 invokeMethod 方法。在 Android 端,你需要註冊一個匹配的原生 MethodChannel 來接收來自 Dart 的訊號,然後啟動一個新的 Activity。請記住,所有的 Flutter 應用(在 Android 上執行時)都存在於一個完全被 Flutter 應用佔用的 Android Activity 中。因此,正如你在程式碼示例中看到的那樣,原生 MethodChannel 回撥的作用是啟動第二個 Activity。
並非所有的 Android Activity 都使用 Jetpack Compose,但本教程假設你想使用 Compose。
在 Dart 側
#在 Dart 端,建立一個 Method Channel,並在特定的使用者互動(例如點選按鈕)時呼叫它。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// SECTION 1: START COPYING HERE
const platformMethodChannel = MethodChannel(
// Note: You can change this string value, but it must match
// the `CHANNEL` attribute in the next step.
'com.example.flutter_android_activity',
);
// SECTION 1: END COPYING HERE
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
// SECTION 2: START COPYING HERE
void _launchAndroidActivity() {
platformMethodChannel.invokeMethod(
// Note: You can change this value, but it must match
// the `call.method` value in the next section.
'launchActivity',
// Note: You can pass any primitive data types you like.
// To pass complex types, use package:pigeon to generate
// matching Dart and Kotlin classes that share serialization logic.
{'message': 'Hello from Flutter'},
);
}
// SECTION 2: END COPYING HERE
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: const Center(child: Text('Hello World!')),
floatingActionButton: FloatingActionButton(
// SECTION 3: Call `_launchAndroidActivity` somewhere.
onPressed: _launchAndroidActivity,
// SECTION 3: End
tooltip: 'Launch Android activity',
child: const Icon(Icons.launch),
),
),
);
}
}
Dart 程式碼和 Kotlin 程式碼之間有 3 個必須匹配的重要值
- 通道名稱(在本示例中,值為
"com.example.flutter_android_activity")。 - 方法名稱(在本示例中,值為
"launchActivity")。 - Dart 傳遞的資料結構與 Kotlin 預期接收的資料結構。在本例中,資料是一個包含單個
"message"鍵的 Map。
在 Android 端
#你需要修改生成的 Android 應用中的 4 個檔案,以便為啟動新的 Compose Activity 做好準備。
第一個需要修改的檔案是 android/app/build.gradle。
-
將以下內容新增到現有的
android塊中android/app/build.gradle.ktskotlinandroid { // Begin adding here buildFeatures { compose = true } composeOptions { // https://developer.android.com/jetpack/androidx/releases/compose-kotlin kotlinCompilerExtensionVersion = "1.4.8" } // End adding here }android/app/build.gradlegroovyandroid { // Begin adding here buildFeatures { compose true } composeOptions { // https://developer.android.com/jetpack/androidx/releases/compose-kotlin kotlinCompilerExtensionVersion = "1.4.8" } // End adding here }訪問程式碼片段中的 developer.android.com 連結,並根據需要調整
kotlinCompilerExtensionVersion。只有在flutter run過程中出現錯誤且錯誤資訊提示你機器上安裝的版本時,才需要執行此操作。 -
接下來,在檔案底部、根級別新增以下塊
android/app/build.gradle.ktskotlindependencies { implementation("androidx.core:core-ktx:1.10.1") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1") implementation("androidx.activity:activity-compose") implementation(platform("androidx.compose:compose-bom:2024.06.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.material:material") implementation("androidx.compose.material3:material3") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") androidTestImplementation(platform("androidx.compose:compose-bom:2024.06.00")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") androidTestImplementation("androidx.compose.ui:ui-test-junit4") debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-test-manifest") }android/app/build.gradlegroovydependencies { implementation "androidx.core:core-ktx:1.10.1" implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1" implementation "androidx.activity:activity-compose" implementation platform("androidx.compose:compose-bom:2024.06.00") implementation "androidx.compose.ui:ui" implementation "androidx.compose.ui:ui-graphics" implementation "androidx.compose.ui:ui-tooling-preview" implementation "androidx.compose.material:material" implementation "androidx.compose.material3:material3" testImplementation "junit:junit:4.13.2" androidTestImplementation "androidx.test.ext:junit:1.1.5" androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1" androidTestImplementation platform("androidx.compose:compose-bom:2023.08.00") androidTestImplementation "androidx.compose.ui:ui-test-junit4" debugImplementation "androidx.compose.ui:ui-tooling" debugImplementation "androidx.compose.ui:ui-test-manifest" }第二個需要修改的檔案是
android/build.gradle。 -
將以下 buildscript 塊新增到檔案頂部
android/build.gradle.ktskotlinbuildscript { dependencies { // Replace with the latest version. classpath("com.android.tools.build:gradle:8.1.1") } repositories { google() mavenCentral() } }android/build.gradlegroovybuildscript { dependencies { // Replace with the latest version. classpath 'com.android.tools.build:gradle:8.1.1' } repositories { google() mavenCentral() } }第三個需要修改的檔案是
android/app/src/main/AndroidManifest.xml。 -
在根 application 塊中,新增以下
<activity>宣告android/app/src/main/AndroidManifest.xmlxml<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:label="flutter_android_activity" android:name="${applicationName}" android:icon="@mipmap/ic_launcher"> // START COPYING HERE <activity android:name=".SecondActivity" android:exported="true" android:theme="@style/LaunchTheme"></activity> // END COPYING HERE <activity android:name=".MainActivity" …></activity> … </manifest>第四個也是最後一個需要修改的程式碼位於
android/app/src/main/kotlin/com/example/flutter_android_activity/MainActivity.kt。在這裡,你將為你想要實現的 Android 功能編寫 Kotlin 程式碼。 -
在檔案頂部新增必要的匯入
MainActivity.ktkotlinpackage com.example.flutter_android_activity import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.ui.Modifier import androidx.core.app.ActivityCompat import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugins.GeneratedPluginRegistrant -
透過新增
CHANNEL欄位和configureFlutterEngine方法來修改生成的MainActivity類MainActivity.ktkotlinclass MainActivity: FlutterActivity() { // This value must match the `MethodChannel` name in your Dart code. private val CHANNEL = "com.example.flutter_android_activity" override fun configureFlutterEngine(flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call: MethodCall, result: MethodChannel.Result -> when (call.method) { // Note: This must match the first parameter passed to // `platformMethodChannel.invokeMethod` in your Dart code. "launchActivity" -> { try { // Takes an object, in this case a String. val message = call.arguments val intent = Intent(this@MainActivity, SecondActivity::class.java) intent.putExtra("message", message.toString()) startActivity(intent) } catch (e: Exception){} result.success(true) } else -> {} } } } } -
在檔案底部新增第二個
Activity,即你在之前修改AndroidManifest.xml時引用的那個MainActivity.ktkotlinclass SecondActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { Column { Text(text = "Second Activity") // Note: This must match the shape of the data passed from your Dart code. Text("" + getIntent()?.getExtras()?.getString("message")) Button(onClick = { finish() }) { Text("Exit") } } } } } }
這些步驟展示瞭如何從 Flutter 應用啟動原生 Android Activity,這有時是連線特定 Android 功能的簡單方法。