Flutter与原生混合开发实现过程

本篇博客不讲原理,只讲实现方法,从0到1实现 Flutter 和原生的混合开发。将会新建一个 Android 原生项目,取名叫 AndroidDemo,然后新建一个 FlutterModule 项目,取名为 flutter_module,两个项目都放在 flutter_boost 目录下,最后实现两个项目的混合。实现的功能包括:

  • 安卓原生打开 Flutter 页面
  • Flutter 打开安卓原生页面

实现步骤如下:

1 . 新建安卓原生项目 AndroidDemo
2 .打开原生项目,在 AndroidStudio 控制台中输入如下命令,用于新建 FlutterModule 项目

cd..	//由于新建的 FlutterModule 项目和 AndroidDemo 项目并列在同级目录下,退出到主目录下
flutter create -t module flutter_module	//创建 flutter_module 

控制台的截图如下:
在这里插入图片描述
最后 flutter_module 创建成功后,在目录中可以看到如下并列的文件结构:
在这里插入图片描述
3 .打开 flutter_module 项目,在控制台中执行如下指令

cd .android
./gradlew assembleDebug

4 .原生项目 AndroidDemo 的配置

在 app 目录下的 build.gradle 中添加如下代码:

compileOptions {
	sourceCompatibility 1.8
	targetCompatibility 1.8
}

并添加 Flutter 依赖:

implementation project(':flutter')

结构图如下:
在这里插入图片描述
最后在 setting.gradle 中添加如下代码,根据你的项目名称和路径自行调整:

setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir.parentFile,
        '/flutter_module/.android/include_flutter.groovy'
))

原生项目的配置环节到这里就完成了。

5 .在 AndroidDemo 项目中新建活动,取名为 FlutterActivity,并添加 MainActivity 代码和 FlutterActivity 代码

MainActivity 代码如下:

package com.example.shinelon.androiddemo;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this,FlutterActivity.class);
                Bundle bundle = new Bundle();
                bundle.putString("routeName", "first");
                intent.putExtras(bundle);
                startActivity(intent);
            }
        });
    }
}

FlutterActivity 代码如下:

package com.example.shinelon.androiddemo;

import android.app.NativeActivity;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.FrameLayout;

import io.flutter.facade.Flutter;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.view.FlutterView;

public class FlutterActivity extends AppCompatActivity {

    public static final String CHANNEL_NAME = "com.flutterbus/demo";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 获取由上一个页面传过来的routeName
        String routeName = "";
        Intent intent = getIntent();
        if (intent != null && intent.getExtras() != null) {
            routeName = intent.getExtras().getString("routeName");
        }

        // 根据指定routeName创建FlutterView用来展示对应dart中的Widget
        FlutterView flutterView = Flutter.createView(this, this.getLifecycle(), routeName);

        // 创建Platform Channel用来和Flutter层进行交互
        new MethodChannel(flutterView, CHANNEL_NAME).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
                methodCall(methodCall, result);
            }
        });
        setContentView(flutterView);
    }

    /**
     * 处理dart层传来的方法调用
     */
    private void methodCall(MethodCall call, MethodChannel.Result result) {
        if (call.method.equals("gotoNativePage")) {
            startActivity(new Intent(this, SecondActivity.class));
            result.success(true);
        } else {
            result.notImplemented();
        }
    }

}

FlutterActivity 对应的布局是一个 FrameLayout ,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FlutterActivity">

    <FrameLayout
        android:id="@+id/flutter_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </FrameLayout>

</android.support.constraint.ConstraintLayout>

6 . flutter_module 项目中 main.dart 代码入下

import 'package:flutter/material.dart';
import 'dart:ui';
import 'dart:async';
import 'package:flutter/services.dart';

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

Widget _widgetForRoute(String route) {
  switch (route) {
    case 'first':
      return MyApp();
    case 'second':
      return MyApp();
    default:
      return Center(
        child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
      );
  }
}

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: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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;

  static const platform = const MethodChannel("com.flutterbus/demo");

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  //调用原生方法
  Future<Null> gotoNativePage() async {
    bool result;
    try {
      //参数为方法名称
      result = await platform.invokeMethod("gotoNativePage");
    } on PlatformException catch (e) {
      print(e.message);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            //从flutter进入原生界面
            RaisedButton(
              onPressed: gotoNativePage,
              child: Text("打开原生界面"),
            ),
            //进入flutter界面
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), 
    );
  }
}

dart 代码实现了 flutter 打开原生页面的功能,对应于原生的 SecondActivity,自己新建一个活动就可以了。

到这里就已经实现了 Flutter 和原生的混合了,下面是实现页面跳转的方法。

安卓原生打开 Flutter 页面的方法:

Intent intent = new Intent();
intent.setClass(MainActivity.this,FlutterActivity.class);
Bundle bundle = new Bundle();
bundle.putString("routeName", "first");
intent.putExtras(bundle);
startActivity(intent);

Flutter 打开原生页面的方法,也就是调用原生的方法,然后在原生的方法中打开活动:

dart 代码调用原生方法

static const platform = const MethodChannel("com.flutterbus/demo");
//函数
Future<Null> gotoNativePage() async {
  bool result;
   try {
     //参数为方法名称
     result = await platform.invokeMethod("gotoNativePage");
   } on PlatformException catch (e) {
     print(e.message);
   }
 }

原生方法实现页面转跳:

/**
* 处理dart层传来的方法调用
*/
private void methodCall(MethodCall call, MethodChannel.Result result) {
   if (call.method.equals("gotoNativePage")) {
   	   //进入 SecondActivity
       startActivity(new Intent(this, SecondActivity.class));
       result.success(true);
   } else {
       result.notImplemented();
   }
}

最后编译安装 AndroidDemo 项目,看一下实现结果:

打开 App 的第一个界面:
在这里插入图片描述
点击 进入FLUTTER界面 按钮后进入如下界面,也就是 Flutter 界面:
在这里插入图片描述
点击 打开原生界面 后进入如下界面,也就是我们的 SecondActivity:
在这里插入图片描述
这种方法实现混合开发效果不是很好,在原生打开 Flutter 页面时会出现白屏现象,需要等待一段时间,体验不是很好。如有问题可以留言。

发布了38 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43851639/article/details/100801601
今日推荐