flutter java混编_android原生混编Flutter

本文详细介绍了如何将Flutter模块集成到Android原生项目中,包括新建Flutter Module、Android项目集成Flutter步骤,以及Flutter与Java间的交互方法,如Activity和Fragment形式的跳转,同时讲解了Flutter页面与Android原生页面之间的数据传递方法。
摘要由CSDN通过智能技术生成

花了一天时间初步进行接入,有些坑还没有踩全。包括第一次加载flutter界面的时候显示很慢等。

以下是代码集成方式,后续探索产物集成方式。

17abdf8e17ce

image

接入步骤

第一步、新建android原生项目

第二步、新建Flutter Module

通过命令行创建。切换到android项目的同级目录下(这里建议直接使用Terminal)。执行如下命令:

flutter create -t module my_flutter

其中my_flutter为改module名字。

直接使用AS创建。File --> New --> New Flutter Project,然后选择Flutter Module。然后填写module的名称、路径。最后填写module的包名,点击Finish就创建好了一个Flutter Module。

第三步在android项目中引入 Flutter Module

在app下的build.gradle文件中添加以下配置

compileOptions {

sourceCompatibility 1.8

targetCompatibility 1.8

}

可以解决版本兼容性问题。如果不配置可能会报错Invoke-customs are only supported starting with Android O (--min-api 26)。

在项目的根目录下的setting.gradle文件中配置

include ':app'

// 加入下面配置

setBinding(new Binding([gradle: this]))

evaluate(new File(

settingsDir.parentFile,

'FlutterDemo/my_flutter/.android/include_flutter.groovy'

))

需要修改为自己的module名字。

编译成功后在app的build.gradle文件下添加依赖。

implementation project(':flutter')

android 与 Flutter交互

Flutter在1.12版本后舍弃了部分类,导致交互这里有较大变动。

android原生跳转到Flutter界面

一、Activity形式

Activity形式。新建一个Android Activity。进行跳转。代码如下:

public class FlutterPageActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_flutter_page);

initViews();

}

private void initViews() {

FlutterView flutterView = new FlutterView(this);

FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

FrameLayout flContainer = findViewById(R.id.fl_container);

flContainer.addView(flutterView, lp);

FlutterEngine flutterEngine = new FlutterEngine(this);

flutterEngine.getNavigationChannel().setInitialRoute("route1");

flutterEngine.getDartExecutor().executeDartEntrypoint(

DartExecutor.DartEntrypoint.createDefault()

);

flutterView.attachToFlutterEngine(flutterEngine);

}

}

因为io.flutter.facade,此处采用FlutterView(继承自FrameLayout)替代了原来的Flutter.createView();

**attachToFlutterEngine(FlutterEngine flutterEngine) ** 方法的作用就是flutter的ui显示到FlutterView中。

FlutterEngine 负责在android端执行Dart代码的引擎。

flutterEngine.getNavigationChannel().setInitialRoute("route1"); 设置界面路由。如果不设置默认是“/”界面。

传参可以采用类似get拼接的形式,例如:

"route1?{\"name\":\"LiLei\"}"

将路由和参数采用?进行隔开,后续可以添加上json字符串。在Flutter 端解析的时候采用window.defaultRouteName 获取路由名称和参数。

String url = window.defaultRouteName;

// route名称

String route =

url.indexOf('?') == -1 ? url : url.substring(0, url.indexOf('?'));

// 参数Json字符串

String paramsJson =

url.indexOf('?') == -1 ? '{}' : url.substring(url.indexOf('?') + 1);

// 解析参数

Map params = json.decode(paramsJson);

在flutter中路由的简单写法。

void main() => runApp(_widgetForRoute(window.defaultRouteName));

Widget _widgetForRoute(String route) {

switch (route) {

case 'route1':

return MyApp();

default:

return Center(

child: Text('Unknown route: $route', textDirection: TextDirection.ltr),

);

}

}

创建好Activity后原生界面A 就可以采用Intent的方式进行跳转。

Intent intent = new Intent(MainActivity.this, FlutterPageActivity.class);

startActivity(intent);

二、Fragment形式

新建一个Fragment 继承自Fragment。

在fragment的onCreate方法中创建FlutterView。具体方法和Activity中相同。

@Nullable

@Override

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

FlutterView flutterView = new FlutterView(getContext());

FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

mFlutterEngine = new FlutterEngine(getContext());

mFlutterEngine.getNavigationChannel().setInitialRoute("route1");

mFlutterEngine.getDartExecutor().executeDartEntrypoint(

DartExecutor.DartEntrypoint.createDefault()

);

flutterView.attachToFlutterEngine(mFlutterEngine);

return flutterView;

}

这里将FlutterEngine方法设置为成员变量为了后续界面间传值。

在原生Activity中添加加载方法。

public class FlutterFragmentActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_flutter_fragment);

initViews();

}

private void initViews() {

//写法1

getSupportFragmentManager().beginTransaction().replace(R.id.fl_container, new FlutterPageFragment()).commit();

//写法2

FlutterFragment fragment = FlutterFragment.withNewEngine().initialRoute("route1").build();

getSupportFragmentManager().beginTransaction().replace(R.id.fl_container, fragment).commit();

//写法3

//通过FlutterFragment引入Flutter编写的页面

FlutterFragment flutterFragment = FlutterFragment.withNewEngine()

.initialRoute("route2")

.build();

getSupportFragmentManager()

.beginTransaction()

.replace(R.id.fl_container, flutterFragment)

.commit();

}

}

写法3中 在androidx环境中 flutterFragment需要继承自androidx的fragment。

Flutter界面跳转到Android原生界面

在布局中添加一个按钮。

static const nativeChannel = const MethodChannel('com.example.flutter/native');

首先要定义一个channel,全局唯一,需要和android端约定好。

RaisedButton(

child: Text('跳转到原生界面'),

onPressed:() {

// 返回给上一页的数据

Map result = {'name': '我从Flutter页面过来了'};

nativeChannel.invokeMethod('jumpToNative', result);

}),

dart采用map形式发送。定义好key value

通过nativeChannel.invokeMethod('jumpToNative', result); 方法传递出去。其中第一个参数是和android端预定好的方法名。

在fragment中进行接收

private static final String CHANNEL_NATIVE = "com.example.flutter/native";

@Override

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

MethodChannel nativeChannel = new MethodChannel(mFlutterEngine.getDartExecutor(), CHANNEL_NATIVE);

nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {

@Override

public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {

switch (methodCall.method) {

case "jumpToNative":

// 跳转原生页面

Intent jumpToNativeIntent = new Intent(getActivity(), NativeActivity.class);

jumpToNativeIntent.putExtra("name", (String) methodCall.argument("name"));

//因为写的demo所以直接采用了魔法数字 方便文章中看的直观

startActivityForResult(jumpToNativeIntent, 1001);

break;

default:

result.notImplemented();

break;

}

}

});

}

在实现Flutter页面跳转Android原生页面之前首先介绍一下Platform Channel,它是Flutter和原生通信的工具,有三种类型:

BasicMessageChannel:用于传递字符串和半结构化的信息,Flutter和平台端进行消息数据交换时候可以使用。

MethodChannel:用于传递方法调用(method invocation),Flutter和平台端进行直接方法调用时候可以使用。

EventChannel:用于数据流(event streams)的通信,Flutter和平台端进行事件监听、取消等可以使用。

Flutter 跳转到原生界面主要通过MethodChannel来实现。

在创建MethodChannel的时候需要传入一个常量。需要保证唯一性。和dart端约定好采用一样的常量。就是上文中提到的nativeChannel 。

第一个参数是BinaryMessenger类型。需要通过mFlutterEngine.getDartExecutor()方法获取到。

这里有两个前提:

a. 需要界面加载完成后。所以我们写在onViewCreated中;

b. 需要从flutterEngine中获取,所以我们将该变量改成成员变量。

通过setMethodCallHandler回调方式判断返回的方法名。在进行相应处理。

获取到想要的方法名之后,使用intent将获取到的数据发送出去。

这里采用startActivityForResult 方法是因为在原生界面中做了数据回调。

从android原生界面返回到Flutter界面数据传递

接上面的跳转原生界面成功后,在原生界面中添加按钮进行返回并传值。

tv_demo.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

Intent intent = new Intent();

intent.putExtra("message", "我从原生页面回来了");

setResult(RESULT_OK, intent);

finish();

}

});

在上诉的fragment的onActivityResult方法中进行接收。

@Override

public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if(resultCode == Activity.RESULT_OK){

Log.e(TAG,"接收到回调结果");

// NativePageActivity返回的数据

String message = data.getStringExtra("message");

Map result = new HashMap<>();

result.put("message", message);

// 创建MethodChannel,这里的flutterView即Flutter.createView所返回的View

MethodChannel flutterChannel = new MethodChannel(mFlutterEngine.getDartExecutor(), CHANNEL_FLUTTER);

// 调用Flutter端定义的方法

flutterChannel.invokeMethod("onActivityResult", result);

}

}

调用了flutter中的方法将值传入到flutter中并显示在界面上。

定义一个全局唯一常量,和flutter中约定好。

private static final String CHANNEL_FLUTTER = "com.example.flutter/flutter";

static const flutterChannel = const MethodChannel('com.example.flutter/flutter');

在initState中进行接收

String _backResult = "初步设置";

@override

void initState() {

super.initState();

Future handler(MethodCall call) async {

switch (call.method) {

case 'onActivityResult':

// 获取原生页面传递的参数

print(call.arguments['message']);

setState(() {

_backResult = call.arguments['message'];

});

break;

}

}

flutterChannel.setMethodCallHandler(handler);

}

用变量来记录

新建一个text来显示这label

Text(

'$_backResult'

),

Flutter界面返回到android原生界面数据传递

新建一个返回按钮

RaisedButton(

child: Text('返回上一页'),

onPressed: () {

// 返回给上一页的数据

Map result = {'message': '我从Flutter页面回来了'};

nativeChannel.invokeMethod('goBackWithResult', result);

}),

并执行返回的方法。方法名和key提前约定好。

原生fragmen中先接收相应的参数,然后使用intent进行传递。

@Override

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

MethodChannel nativeChannel = new MethodChannel(mFlutterEngine.getDartExecutor(), CHANNEL_NATIVE);

nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {

@Override

public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {

switch (methodCall.method) {

case "goBackWithResult":

// 返回上一页,携带数据

Intent backIntent = new Intent();

backIntent.putExtra("message", (String) methodCall.argument("message"));

getActivity().setResult(Activity.RESULT_OK, backIntent);

getActivity().finish();

break;

default:

result.notImplemented();

break;

}

}

});

}

在上一个原生界面的activity中进行接收信息。

@Override

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RESULT_OK) {

tv_result.setVisibility(View.VISIBLE);

String result = data.getStringExtra("message");

tv_result.setText("result" + result);

}

}

demo

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值