朱宽武 發表於 2020-10-27 21:57:00

【Flutter 混合开发】添加 Flutter 到 Android Activity

<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215713180-299329130.png"></p>
<blockquote>
<p>Flutter 混合开发系列 包含如下:</p>
<ul>
<li>嵌入原生View-Android</li>
<li>嵌入原生View-iOS</li>
<li>与原生通信-MethodChannel</li>
<li>与原生通信-BasicMessageChannel</li>
<li>与原生通信-EventChannel</li>
<li><strong>添加 Flutter 到 Android Activity</strong></li>
<li>添加 Flutter 到 Android Fragment</li>
<li>添加 Flutter 到 iOS</li>
</ul>
<p>每个工作日分享一篇,欢迎关注、点赞及转发。</p>
</blockquote>
<h3 id="创建-flutter-module">创建 Flutter Module</h3>
<p>Flutter可以以源代码或AAR的方法嵌入到Android原生项目,集成流程可以使用 Android Studio 完成,也可以手动完成。强烈建议使用Android Studio。</p>
<p>首先创建一个 Android 项目,创建一个空的 Activity:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215713769-3263478.png"></p>
<p>Android 项目创建成功后,使用Android Studio 添加Flutter模块,在Android原生项目中点击“File &gt; New &gt; New Module...”,创建 <strong>Flutter Module</strong>:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215714591-2146123315.png"></p>
<blockquote>
<p><strong>注意</strong>:Android Studio 的版本3.5及以上,Flutter IntelliJ plugin版本42及以上。</p>
</blockquote>
<p>在弹出的选择Module类型的对话框中选中Flutter Module,然后点击Next,</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215715130-1392609478.png"></p>
<p>设置Flutter module的Project name、Flutter SDK等,点击Next:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215715658-1536183139.png"></p>
<p>设置Flutter module的包名,点击Finish:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215715972-1572526729.png"></p>
<p>编译完成后将在当前App目录下生成Flutter模块的代码,目录结构如下:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215716267-489261289.png"></p>
<h3 id="启动页加载-flutter">启动页加载 Flutter</h3>
<p>将 Flutter 页面加载到 MainActivity(默认启动页)中,修改 MainActivity :</p>
<pre><code class="language-kotlin">package com.flutter.androidflutter

import io.flutter.embedding.android.FlutterActivity

class MainActivity : FlutterActivity()
</code></pre>
<p>你没有看错,只需让MainActivity 继承 <strong>FlutterActivity</strong> 即可。</p>
<blockquote>
<p><strong>注意</strong>:FlutterActivity的包名是io.flutter.embedding.android.FlutterActivity</p>
</blockquote>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215716856-1471829589.jpg"></p>
<h3 id="跳转到-flutter-页面">跳转到 Flutter 页面</h3>
<p>MainActivity(默认启动页)添加一个按钮,点击后跳转到新的页面,此页面加载 Flutter ,MainActivity代码如下:</p>
<pre><code class="language-kotlin">package com.flutter.androidflutter

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      button.setOnClickListener {
            startActivity(Intent(this,SecondFlutterActivity::class.java))
      }
    }
}
</code></pre>
<p>SecondFlutterActivity 代码如下:</p>
<pre><code class="language-kotlin">package com.flutter.androidflutter

import io.flutter.embedding.android.FlutterActivity

class SecondFlutterActivity:FlutterActivity()
</code></pre>
<p>在 <strong>AndroidManifest.xml</strong> 中注册此 Activity:</p>
<pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.flutter.androidflutter"&gt;

    &lt;application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:supportsRtl="true"
      android:theme="@style/AppTheme"&gt;
      ...
      &lt;activity android:name=".SecondFlutterActivity"/&gt;
    &lt;/application&gt;

&lt;/manifest&gt;
</code></pre>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215717156-1899099228.gif"></p>
<p><strong>SecondFlutterActivity</strong> 只是继承了 <strong>FlutterActivity</strong>,这种情况下,也可以直接使用 <strong>FlutterActivity</strong>:</p>
<pre><code class="language-kotlin">startActivity(Intent(this, FlutterActivity::class.java))
</code></pre>
<p>或者:</p>
<pre><code class="language-kotlin">startActivity(FlutterActivity.createDefaultIntent(this))
</code></pre>
<p>在 <strong>AndroidManifest.xml</strong> 中注册 FlutterActivity:</p>
<pre><code>&lt;activity android:name="io.flutter.embedding.android.FlutterActivity"/&gt;
</code></pre>
<p>效果与上面是一样的。</p>
<p>FlutterActivity 会加载 Flutter Module 中 lib/main.dart 中 main 方法,如果有多个Flutter页面,如何指定跳转,比如现在有 OnePageFlutter 页面,OnePage 代码如下:</p>
<pre><code class="language-dart">class OnePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
      child: Text('这是 One 页面'),
      ),
    );
}
}
</code></pre>
<p>FlutterActivity 指定加载页面需要使用<strong>命名路由</strong>,MyApp 修改如下:</p>
<pre><code class="language-dart">class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(

      primarySwatch: Colors.blue,
      ),
      routes: {
      'one_page':(context){
          return OnePage();
      },
      'two_page':(context){
          return TwoPage();
      }
      },
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
}
}
</code></pre>
<p>MainActivity 页面点击到 Flutter 页面,加载 OnePage 页面:</p>
<pre><code class="language-kotlin">class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      button.setOnClickListener {
            startActivity(
                FlutterActivity
                  .withNewEngine()
                  .initialRoute("one_page")
                  .build(this)
            )
      }
    }
}
</code></pre>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215717680-371953703.gif"></p>
<h3 id="引擎缓存">引擎缓存</h3>
<p>加载 FlutterActivity 页面时明显看到一段时间的黑屏,这段时间主要是启动 Flutter 引擎(FlutterEngine),Flutter 引擎启动的时间在不同手机上不同,性能越好的手机越短。同时每一个 FlutterActivity 页面都会启动一个引擎,所以强烈建议不要在一个项目中创建多个 FlutterActivity(或者启动多个 FlutterActivity 实例),否则内存会越来越大,下面是每隔3秒创建一个 FlutterActivity 实例内存变化图:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215719465-1146424109.gif"></p>
<p>为了减少 FlutterActivity 页面的延迟时间和多个 FlutterActivity 实例内存一直增长问题,我们可以使用 Flutter 引擎(FlutterEngine)缓存,在启动 FlutterActivity 前先启动 Flutter 引擎,然后使用缓存的引擎加载页面,通常将其放在 <strong>Application</strong> 中:</p>
<pre><code class="language-kotlin">class MyApplication : Application() {
    lateinit var flutterEngine: FlutterEngine

    override fun onCreate() {
      super.onCreate()
      flutterEngine = FlutterEngine(this)
      flutterEngine.dartExecutor.executeDartEntrypoint(
            DartExecutor.DartEntrypoint.createDefault()
      )
      FlutterEngineCache
            .getInstance()
            .put("engine_id", flutterEngine)
    }

}
</code></pre>
<p>使用缓存的引擎:</p>
<pre><code class="language-kotlin">startActivity(
    FlutterActivity
      .withCachedEngine("engine_id")
      .build(this)
)
</code></pre>
<p>在同一台手机上效果非常明显,黑屏时间大大减少,不过还是有一个短暂的黑屏。</p>
<p>这里要注意,使用缓存引擎时,其生命周期不在是 FlutterActivity(或者 FlutterFragment)的生命周期,而是整个 App 的生命周期(在Application 中的创建和销毁)。当然也可以提前销毁:</p>
<pre><code class="language-kotlin">flutterEngine.destroy()
</code></pre>
<p>另外项目的 debug 和 release 版本对性能的影响非常大,如果要<strong>测试其性能一定在要 release 下测试</strong>。</p>
<p>上面使用新的引擎可以指定 FlutterActivity(或者 FlutterFragment)配置初始路由,但使用缓存引擎时无法在 FlutterActivity(或者 FlutterFragment)配置初始路由,因为缓存引擎已经启动并运行,不过可以在启动缓存引擎时指定其初始路由:</p>
<pre><code class="language-kotlin">flutterEngine = FlutterEngine(this)

flutterEngine.navigationChannel.setInitialRoute("one_page")

flutterEngine.dartExecutor.executeDartEntrypoint(
    DartExecutor.DartEntrypoint.createDefault()
)
FlutterEngineCache
    .getInstance()
    .put("engine_id", flutterEngine)
</code></pre>
<p>如果使用缓存引擎在FlutterActivity(或 FlutterFragment)指定不同路由,如何处理?这时需要创建一个 <strong>method channel</strong>,flutter 接收具体消息从而切换不同的路由。</p>
<h2 id="交流">交流</h2>
<p>老孟Flutter博客(330个控件用法+实战入门系列文章):http://laomengit.com</p>
<p>欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:</p>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215721786-1174248521.png"></td>
<td><img src="https://img2020.cnblogs.com/other/467322/202010/467322-20201027215722286-1039051127.png"></td>
</tr>
</tbody>
</table><br><br>
来源:https://www.cnblogs.com/mengqd/p/13887892.html
頁: [1]
查看完整版本: 【Flutter 混合开发】添加 Flutter 到 Android Activity