可將 Java 的 Activity 整合進 Flutter 專案,由 Flutter Page 跳轉到 Java Page。
Version
Flutter 3.24
Dart 3.5
Flutter
- 主頁為 Flutter view,按下
Open Android Native Page
後顯示 Android 原生的 view
Create Project
$ flutter create -a java --platforms=android native_integration
- 使用
flutter create
建立 Flutter 專案 -a java
:以 Java 為 Android 的語言--platforms=android
:只包含 Android 平台native_integration
:專案名稱
Java Class
android/src/main/java/com.example.native_integration/NativeActivity.java
package com.example.native_integration;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class NativePageActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setText("Android Hello World");
textView.setTextSize(24);
setContentView(textView);
}
}
- Android 原生的 Java activity
Java Activity Wrapper
android/src/main/java/com.example.callback_plugin/MainActivity.java
package com.example.native_integration;
import android.content.Intent;
import android.os.Bundle;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example/native_route";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MethodChannel(getFlutterEngine().getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("openNativePage")) {
openNativePage();
result.success(null);
} else {
result.notImplemented();
}
}
);
}
private void openNativePage() {
Intent intent = new Intent(this, NativePageActivity.class);
startActivity(intent);
}
}
- Java 的 activity wrapper
Line 10
public class MainActivity extends FlutterActivity {
}
MainActivity
必須繼承FlutterActivity
Line 13
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MethodChannel(getFlutterEngine().getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("openNativePage")) {
openNativePage();
result.success(null);
} else {
result.notImplemented();
}
}
);
}
- override
onCreate()
顯示原生 activity - 提供
openNativePage()
給 MethodChannel 供 Flutter 呼叫
Manifest
android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="native_integration"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<activity android:name=".NativePageActivity" android:theme="@style/Theme.AppCompat.Light.DarkActionBar"/>
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
- 描述 Android app
Line 33
<activity android:name=".NativePageActivity" android:theme="@style/Theme.AppCompat.Light.DarkActionBar"/>
- 新增
NativePageActivity
Gradle
android/app/build.gradle
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
android {
namespace = "com.example.native_integration"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.native_integration"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug
}
}
}
flutter {
source = "../.."
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1' // 添加这个依赖项
implementation 'com.google.android.material:material:1.12.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
- 定義 Gradle script
Line 46
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1' // 添加这个依赖项
implementation 'com.google.android.material:material:1.12.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
- 新增 dependency
必須使用
androidx.appcompat:appcompat:1.6.1
,使用 1.7 會有問題
Flutter Dart
lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Native Integration',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
static const platform = MethodChannel('com.example/native_route');
Future<void> _openNativePage() async {
try {
await platform.invokeMethod('openNativePage');
} on PlatformException catch (e) {
print("Failed to open native page: '${e.message}'.");
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Home Page'),
),
body: Center(
child: ElevatedButton(
onPressed: _openNativePage,
child: Text('Open Android Native Page'),
),
),
);
}
}
- Flutter 呼叫 Java activity
Line 24
Future<void> _openNativePage() async {
try {
await platform.invokeMethod('openNativePage');
} on PlatformException catch (e) {
print("Failed to open native page: '${e.message}'.");
}
}
- 使用 MethodChannrel 透過
openNativePage()
呼叫 Java Activity
Conclusion
- 若要將原本 Java activity 整合進 Flutter,有以下 SOP
- 新增 Java 的 activity wrapper class
- 修改 Java 的 manifest
- 修改 Java 的 Gradle build script
- Dart 呼叫 Java activity