Flutter 支持作为 android Moudle 出现在项目中.这样就可以在 已有的项目中 使用.
虽然现在Flutter 比较受关注,但是和weex 一样 ,大部分都只是在观望 不是真正的进行使用.所以 如果用还是混合开发 原生+Flutter 方式比较合适(自我感觉).
写一个demo 进行Android及Flutter 交互.(IOS 方法基本一致).
Flutter 调用 android 硬件的插件还比较匮乏 比如 各种传感器, 自定义相机 所以就会用到 Flutter 调用android 及android 原生调用 Flutter的方法.

#####本例子中会实现.

  • 原有的android 应用程序嵌入 FlutterView
  • Flutter 代码调用Android 原生方法进行页面跳转及传值
  • Android原生 调用 Flutter 方法 进行传值

#####android引入flutter moudle
在当前project下 运行命令
flutter create -t module my_flutter(my_flutter为生成的flutter module名称)

  1. 在工程的settings.gradle增加以下配置
    1
    2
    3
    4
    5
    6
    include ':app'
    setBinding(new Binding([gradle: this])) // new
    evaluate(new File( // new
    settingsDir.parentFile, // new
    'ToyamaFinance/my_flutter/.android/include_flutter.groovy' //ToyamaFinance项目名称 my_flutter FlutterMoudle名称
    ))
    2.在app (假如你的Android应用名称为app)的build.gradle文件下dependencies增加如下依赖
    implementation project(':flutter')
    其中flutter工程为创建Flutter module过程自动生成的,注意就是flutter
    注意 其中 minSdkVersion 需要至少为16,否则会报错

######生成的工程结构如下:

#####android端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.guoshikeji.toyamafinance.flutter_activitys;

import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Window;
import android.widget.RelativeLayout;

import com.guoshikeji.toyamafinance.R;
import com.guoshikeji.toyamafinance.activity.launch.LoginActivity;
import com.guoshikeji.toyamafinance.activity.user.ShareDialogActivity;
import com.guoshikeji.toyamafinance.application.MyApplication;
import com.guoshikeji.toyamafinance.control.utils.SerializeUtils;
import com.guoshikeji.toyamafinance.mode.bean.UserBean;
import com.guoshikeji.toyamafinance.mode.constants.Constants;
import com.qmuiteam.qmui.util.QMUIStatusBarHelper;
import io.flutter.facade.Flutter;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.view.FlutterView;
public class FlutterProjectsDetails extends AppCompatActivity {
//发送与接收的key,需保证唯一,不一定是包名,并且android和flutter的key需一致 不然会报错
public static final String FlutterToAndroidCHANNEL = "com.guoshikeji.toandroid/project_details";
public static final String AndroidToFlutterCHANNEL= "com.guoshikeji.toflutter/project_details";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//requestWindowFeature(Window.FEATURE_NO_TITLE);
//MyApplication.getInstance().addActivity(this);
//QMUIStatusBarHelper.translucent(this, Color.WHITE);
//MyApplication.getInstance().addActivity(this);
setContentView(R.layout.activity_flutter_default);
RelativeLayout rl_flutter_defalut = findViewById(R.id.rl_flutter_defalut);
Intent intent = getIntent();
int project_id = intent.getIntExtra("project_id", 0);
Log.e("tyl","project_id1="+project_id);
//加载flutter界面 getLifecycle方法需要activity继承至AppCompatActivity
FlutterView flutterView = Flutter.createView(this, getLifecycle(), "route1");
//将view添加到原生界面中
rl_flutter_defalut.addView(flutterView);
//android向flutter发送消息
new EventChannel(flutterView, AndroidToFlutterCHANNEL)
.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
String androidParmas = project_id+"";
eventSink.success(androidParmas);
}
@Override
public void onCancel(Object o) {

}
});
//接收flutter发送过来的消息
new MethodChannel(flutterView, FlutterToAndroidCHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
Log.e("tyl","flutter_back="+methodCall.method);
//接收来自flutter的指令oneAct
if (methodCall.method.equals("finish")) {
MyApplication.getInstance().removeActivity(FlutterProjectsDetails.this);
result.success("success");
}
else if (methodCall.method.equals("share")) {
Object object = SerializeUtils.readServiceListFromFile(Constants.USER_INFO);
if (object != null) {
Intent intent = new Intent(FlutterProjectsDetails.this, ShareDialogActivity.class);
intent.putExtra(ShareDialogActivity.MODE_ORIENTATION, 1);
startActivity(intent);
} else {
startActivity(new Intent(FlutterProjectsDetails.this, LoginActivity.class));
}
result.success("success");
} else {
result.notImplemented();
}
}
});
}
}

#####Flutter端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';

void main() => runApp(new MyApp());

Widget _widgetForRoute(String route) {
switch (route) {
case 'route1':
return MyHomePage(title: 'Flutter Demo Home Page1');
case 'route2':
return MyHomePage(title: 'Flutter Demo Home Page2');
default:
return MyHomePage(title: 'Flutter Demo Home Page2');
}
}

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: _widgetForRoute(window.defaultRouteName),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
//获取到插件与原生的交互通道 需要和android的key一致
static const toAndroidPlugin = const MethodChannel('com.guoshikeji.toandroid/project_details');
static const fromAndroiPlugin = const EventChannel('com.guoshikeji.toflutter/project_details');
StreamSubscription _fromAndroiSub;
var _nativeParams;
@override
void initState() {
// TODO: implement initState
super.initState();
_startfromAndroiPlugin();//在initState中初始化
}
//注册从android获取消息的监听
void _startfromAndroiPlugin(){
if(_fromAndroiSub == null){
_fromAndroiSub = fromAndroiPlugin.receiveBroadcastStream()
.listen(_onfromAndroiEvent,onError: _onfromAndroiError);
}
}
//获取成功的方法
void _onfromAndroiEvent(Object event) {
setState(() {
_nativeParams = event;
});
}
//获取失败的方法
void _onfromAndroiError(Object error) {
setState(() {
_nativeParams = "error";
print(error);
});
}
//发送消息
Future<Null> _jumpToNative() async {
String result = await toAndroidPlugin.invokeMethod('withoutParams');

print(result);
}
//发送带参数的消息
Future<Null> _jumpToNativeWithParams() async {
Map<String, String> map = { "flutter": "这是一条来自flutter的参数" };
String result = await toAndroidPlugin.invokeMethod('withParams', map);
print(result);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
child: new ListView(
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: new RaisedButton(
textColor: Colors.black,
child: new Text('跳转到原生界面'),
onPressed: () {
_jumpToNative();
}),
),
new Padding(
padding: const EdgeInsets.only(
left: 10.0, top: 10.0, right: 10.0),
child: new RaisedButton(
textColor: Colors.black,
child: new Text('跳转到原生界面(带参数)'),
onPressed: () {
_jumpToNativeWithParams();
}),
),

new Padding(
padding: const EdgeInsets.only(
left: 10.0, top: 10.0, right: 10.0),
child: new Text('这是一个从原生获取的参数:$_nativeParams'),
)
, new Padding(
padding: const EdgeInsets.only(
left: 10.0, top: 10.0, right: 10.0),
child: new Text('Flutter floatingActionButton 点击次数$_counter'),
)

],
)
),
);
}
}