Android工程内嵌Flutter

本文记录一下Android主工程中嵌入部分Fluttter页面的实现方法。

创建一个Android工程模拟你的现有工程

为了让Android工程和Flutter工程互不干扰,这里不再以Android工程为工程的跟目录,而是让Android工程和平级的Flutter工程的公共目录作为根目录。 最终的目录结构应该是下面这样的

你的项目根目录(随便什么你喜欢的地方)
  ├── 原生安卓工程(FlutterInAndroid)
  └── Flutter工程 (my_flutter)

所以首先在你的项目根目录下用AS创建一个新的Android原生项目,可以勾选上kotlin支持,这样更舒服。 创建完成后你会得到一个这样的结构

你的项目根目录(随便什么你喜欢的地方)
  └── FlutterInAndroid

FlutterInAndroid目录内是一个完整的Android工程

module模式创建Flutter工程

接下来使用Flutter命令来创建module工程,在你的项目根目录下执行:

flutter create -t module my_flutter
 

创建完成后你会得到一个这样的结构

你的项目根目录(随便什么你喜欢的地方)
  ├── FlutterInAndroid
  └── my_flutter

my_flutter是一个Flutter的module工程,用来供Android项目引入

在Android工程中引入依赖

在FlutterInAndroid这个Android工程的setting.gradle文件中追加flutter工程的引入

你的项目跟目录/FlutterInAndroid/setting.gradle

include ‘:app‘
//加入下面配置
setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir.parentFile,
        ‘my_flutter/.android/include_flutter.groovy‘
))

在app的build.gradle文件中加入工程依赖

你的项目跟目录/FlutterInAndroid/app/build.gradle

...
dependencies {
    ...
    // 加入下面配置
    implementation project(‘:flutter‘)
}

使用AS打开FlutterInAndroid工程,重新构建项目,即可成功的将Flutter加入Android工程。

在Android工程中创建Flutter的View

Flutter提供了两种方式让Android工程来引用组件,一种是View,一种是Fragment,这里选用View来进行讲解,Fragment同理。 这里我们用两种方式来引入FLutter,本质是还是是作为一个view引入布局还是将FlutterView作为Activity的根View。

以单个view引入布局

val flutterView = Flutter.createView(this,lifecycle,"route1")

通过上面很简单的一个方法,我们就能通过Flutter创建出一个view,这个方法提供三个参数,第一个是Activity,第二个参数是一个Lifecycle对象,我们之间取Activity的lifecycle即可,第三个参数是告诉Flutter我们要创建一个什么样的view,这个字符串参数可以在Flutter工程中获取得到。

创建出这个FlutterView之后就可以按常规的操作来将它加入到任何你想要的布局中去了。

以根view作为Activity

创建一个空的Activity,用Flutter创建一个View作为页面的根View:

class FlutterActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_flutter)
        val flutterView = Flutter.createView(this@FlutterActivity,lifecycle,"route1")
        val layout = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
        addContentView(flutterView, layout)
    }
}

这里我们并没有使用setContentView而是是用了addContentView这个方法,原因是这样的:

虽然FLutter的加载速度非常快,但是这个过程依然存在,在创建FLutterView之前我们先给ContentView设置了一个R.layout.activity_flutter布局,这个布局可以作为FlutterView加载完成之前展示给用户的界面,当然大部分情况下用户根本感知不到这个界面Flutter已经加载完成了,但我们仍需要它,因为debug模式下造成Flutter的加载速度并不是非常快,这个界面可以给开发人员看,还有就是如果没有这个界面的话在Activity的加载过程会出现一个黑色的闪屏,而这个情况对用户来说并不友好。

在Flutter工程中根据不同的route创建不同的组件

用AndroidStudio在你的项目跟目录/my_flutter打开Flutter工程,这时候AndroidStudio插件会识别到Flutter工程并以Flutter工程进行加载。

忽略掉.android和.ios文件夹之后你会发现,这个FLutter工程和完整的Flutter工程并没有任何不同,你依然能够以完整Flutter工程的流程来进行Flutter开发并启动调试,这是一个非常人性化的设计。

上面我们在原生Android工程中以View的形式调用了Flutter,而Flutter本质上是只有一个入口的,也就是main.dart文件中的main函数:

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

我们的目的是根据原生工程的调用让Flutter生成不同的组件作为View来供原生工程使用,那么我们就可以从这个main函数来入手。

通过文档我们可以通过window的全局变量中获取到当前的routeName,这个值正是上面通过原生工程传给Flutter的标识,有了这个标识就可以简单的做判断来进行不同的组件创建了:

import ‘dart:ui‘;
import ‘package:flutter/material.dart‘;

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

//根据不同的标识创建不同的组件给原生工程调用
Widget _widgetForRoute(String route) {
  switch (route) {
    case ‘route1‘:
      return SomeWidget(...);
    case ‘route2‘:
      return SomeOtherWidget(...);
    default:
      return Center(
        child: Text(‘Unknown route: $route‘, textDirection: TextDirection.ltr),
      );
  }
}

让Flutter模块支持热加载

首先在Flutter目录下启动监听服务,在你的项目根目录/my_flutter下执行

flutter attach

执行后,监听服务会等待并监听debug应用中flutter的状态

然后在打开FlutterInAndroid项目的AS中以正常方式调试运行,在真机或模拟器中运行app后并不会立即出发flutter的监听服务,当flutter的view或Fragment激活时才会触发。

当flutter的监听服务和app建立连接后,终端会出现如下输出:

$ flutter attach -d W8
Waiting for a connection from Flutter on PLK UL00...
Done.
Syncing files to device PLK UL00...                          8.7s

??  To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on PLK UL00 is available at: http://127.0.0.1:54218/
For a more detailed help message, press "h". To quit, press "q".

这时我们修改flutter工程中的dart代码文件,保存后在终端中点击r键即可进行热加载,R键进行热重启。

签名打包

引入flutter工程后,对Android原生工程的构建基本上没有影响,打包按常规操作即可。

Flutter创建的module工程中的Android工程与纯Flutter工程的中Android工程的比较

区别 Flutter的module工程中的Android工程 纯Flutter工程中的Android工程
文件夹名称 .android android
包含的module app和Flutter app
说明1 app只提供了入口Activity,Flutter包含了插件扩展及原生工程调用的接口 app包含入口Activity及插件扩展
说明2 app供Flutter自身开发调试,Flutter作为module供Android原生调用 app作为Android工程运行及打包

为了方便描述我们称前者为module工程,后者为完整工程。

由此可见,虽然module工程中提供了名为Flutter的module供原生工程调用,但仍然保留了app工程,这样非常大程度的方便了flutter工程师来单独开发flutter项目,无需依赖任何原生的调用,自身即可启动调试。

原文地址:https://www.cnblogs.com/fuyaozhishang/p/9617234.html

时间: 2024-11-03 22:45:21

Android工程内嵌Flutter的相关文章

【Android】内嵌数据库IDE(可视化操作类)

Android开发的朋友应该对数据库内容的管理深有体会,想看一下放入数据库的内容都不是很方便,要么用root的设备导出来看或用第三方的手机版的ide.但是都要求root之后.最近一直在想android方便快捷的方法,今天刚好弄到了数据库这块.就写了一个Activity专门用来看数据库的,功能就是看对应数据库的表及表中的数据库. 效果图 刚写还没来得及美化,后面在使用过程中再时行完善. DBIDEActivity.java import java.util.ArrayList; import ja

关于android h5内嵌网页报TypeError: Object.entries is not a function

android内嵌网页有个tab点击居然没反应,晕了.不过还好只是手里的魅族手机有问题,华为的可以,基本可以确定是兼容性问题 用devtools查看webview网页看到报错信息如下图 很明显了es6的generators的entries函数不支持,然后查看手机的chrome内核版本是51,查了下android chrome内核兼容性如下图,android chrome的兼容性更新如此之慢. 解决吧,本来以为是babel编译转es5的问题,搞了半天不行..最后查看大神的回答才发现:babel只能

Android Lint——内嵌于Android Studio的代码优化工具

Android Lint工具是Android Studio 自带的静态代码工模具,Android Lint是专门针对Android 定制的检查规则,因此可以检查出很多Android特有的代码缺陷.建议在开发过程中,经常性地检查编写的代码是否存在问题,在每次测试功能模块前运行Lint是一个不错的时机. Android Studio自身集成了Android Lint,用鼠标右键单击工程中的任一一个文件夹,在弹出菜单中选择Analyze →Inspect Code...即可执行Lint检查. 检查结果

Android学习之——如何将GridView内嵌在ScrollView中

最近在做一个项目,有一个需求是在ScrollView中内嵌一个GridView. 刚开始,我是以为能直接内嵌在里面: 1 <ScrollView 2 android:layout_width="match_parent" 3 android:layout_height="0dp" 4 android:layout_weight="5.5"> 5 <GridView 6 android:id="@+id/gridView

cocos2d-x调用android内嵌浏览器打开网页

cocos2d-x调用android内嵌浏览器打开网页,可以从入口传入网址,C++调用android 的api即可实现.方法也很简单 1. 修改"cocos2dx\platform\win32"下的CCApplication.h和CCApplication.cpp,添加函数 头文件声明 void openURL(const char* pszUrl); cpp文件实现: void CCApplication::openURL(const char* pszUrl) { ShellExe

android之在view中内嵌浏览器的方法

我要做的一个东西是在一个页面的中间嵌入浏览器,一开始不知道从哪里开始,因为以前用的都是Textveiw或者editVeiw之类的控件,而它们并不能用来显示网页的内容,怎么办呢? 首先想到的是:是不是有一个用来显示网页的View呢,于是我就在eclipse里xml编辑器里输入<web,哈哈,果然下面有个提示是webVeiw,那么能不能用它呢?于是到网上搜一下它的资料,果然可以的,下面就开始吧. 先在xml里把webview建好,在代码里用findViewById()将其取出来.我的代码是: Web

关于Unity程序在IOS和Android上显示内嵌网页的方式

近期因为有须要在Unity程序执行在ios或android手机上显示内嵌网页.所以遍从网上搜集了一下相关的资料.整理例如以下: UnityWebCore 从搜索中先看到了这个.下载下来了以后发现这个的原理好像是通过调用浏览器内核.然后将网页渲染到mesh的方式完毕的. 但遗憾的是仅仅支持windows桌面版本号.但还是发出来大家假设有须要能够下载  下载地址: http://pan.baidu.com/s/1nt3FVkd unity-webview 这个是在github上找到的. 是一个kei

Android内嵌网页webview点击其中的链接跳转到我们应用内的Activity

在一个大的Android项目中,由于客户端来不及更新和实现,经常会内嵌一些网页(在一些大型的互联网公司,PC的产品总是跑在客户端的前面),比如活动页面,通常可以内嵌用html5实现的页面,可以适配手机.但是这些网页中有好多链接,但是这些链接有些内容有是我们客户端已经实现的,比如有一个注册链接,其实客户端也实现了注册功能,我们不想再继续跳转到网页注册,而是打开客户端某个注册Activity,可以通过以下方式来实现: xml 文件,如下: java代码如下: ? 1 2 3 4 5 6 7 8 9

Android官方ORM数据库Room技术解决方案:@Embedded内嵌对象(二)

Android官方ORM数据库Room技术解决方案:@Embedded内嵌对象(二) (一)附录1简介了Android Room的基本使用.在附录1例子中,User对象元素均为普通的Java基本数据类型,但是实际的开发中,通常建立的持久化存储对象复杂,且通常是结构化的Java对象,互相之间存在引用或者内嵌关系. Android Room支持数据库表Java对象通过注解符@Embedded内嵌一个Java对象.这样就像过去的ORM数据库一样,比如构造一个名为Info的Java对象,作为一个成员变量