张艳秋 發表於 2020-11-2 22:34:00

【Flutter 混合开发】添加 Flutter 到 iOS

<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223401041-870024373.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>添加 Flutter 到 Android Activity</li>
<li>添加 Flutter 到 Android Fragment</li>
<li><strong>添加 Flutter 到 iOS</strong></li>
</ul>
<p>每个工作日分享一篇,欢迎关注、点赞及转发。</p>
</blockquote>
<p>Flutter 可以作为 frameworks 添加到 iOS 项目,iOS项目引入Flutter module需要安装Xcode,另外Flutter支持iOS8及以上。</p>
<h3 id="创建-flutter-module">创建 Flutter module</h3>
<p>由于 Xcode 无法像 Android Studio 一样安装插件,因此只能通过命令创建 Flutter module,打开终端,输入如下:</p>
<pre><code>cd ios 项目根目录
flutter create --template module my_flutter
</code></pre>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223401725-524852733.png"></p>
<p>执行完毕后,Flutter module将会创建在 ios项目/my_flutter目录下,目录结构如图:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223403082-2142875322.png"></p>
<p>.ios 是隐藏目录,可以单独运行Flutter module,测试此模块的功能,iOS代码添加到现有应用程序的项目或插件中,而不是添加到模块的.ios /目录中。</p>
<p>由于.ios /目录是自动生成的,因此请勿对其进行源代码控制。在新机器上构建模块之前,请先在my_flutter目录中运行flutter pub get来重新生成.ios /目录,然后再使用Flutter模块构建iOS项目。</p>
<h3 id="将flutter模块嵌入到现有应用程序中">将Flutter模块嵌入到现有应用程序中</h3>
<p>将Flutter模块嵌入到现有iOS应用程序中有两种方式:</p>
<ul>
<li>使用CocoaPods和已安装的Flutter SDK(<strong>推荐</strong>)。</li>
<li>为Flutter引擎,已编译的Dart代码和所有Flutter插件创建 frameworks。手动嵌入 frameworks,并在Xcode中更新现有应用程序的构建设置。</li>
</ul>
<blockquote>
<p>应用程序无法在 Release 模式下的模拟器上运行,因为Flutter尚不支持为Dart代码提前输出x86 / x86_64二进制(AOT)二进制文件。在模拟器或真实设备上以调试模式运行,而在真实设备上以Release模式运行。</p>
<p>下面的两种方式是将 Release frameworks 添加到 iOS 应用程序,因此<strong>编译</strong>的时候设备不能选择模拟器,否则编译失败。</p>
</blockquote>
<p>编译成功:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223403917-1100083469.png"></p>
<p>选择模拟器编译失败:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223404680-1272598316.png"></p>
<h4 id="使用cocoapods和已安装的flutter-sdk">使用CocoaPods和已安装的Flutter SDK</h4>
<p>此方法需要所有的相关开发的人员安装 Flutter 环境。</p>
<p>假设现有应用程序和Flutter模块位于同级目录中。如果您使用其他目录结构,则可能需要调整相对路径,目录如下:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223405503-339157594.png"></p>
<p>修改iOS应用程序中 <strong>Podfile</strong> 文件,如果没有则手动创建,内容如下:</p>
<pre><code>flutter_application_path = '../my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'My App' do
install_all_flutter_pods(flutter_application_path)
end


</code></pre>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223406166-1057324905.png"></p>
<p>CocoaPods 相关请参考官网。</p>
<p>执行 <strong>pod install</strong> 命令:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223408560-1128649911.png"></p>
<blockquote>
<p>当在my_flutter / pubspec.yaml中更改Flutter插件的依赖性或者第一次运行时,请在Flutter模块目录中运行flutter pub get来刷新podhelper.rb脚本读取的插件列表。然后,从应用程序目录再次运行pod install。</p>
<p>podhelper.rb脚本将插件Flutter.framework和App.framework嵌入到项目中。</p>
</blockquote>
<p>用 <strong>Xcode 打开 My App.xcworkspace</strong>,如果已经打开则需要关闭重新打开,使用 <strong>⌘B</strong> 编译项目,编译成功。</p>
<h4 id="在xcode中嵌入-flutter-frameworks">在Xcode中嵌入 Flutter Frameworks</h4>
<p>通过命令生成必要的 Frameworks,并通过手动编辑现有的Xcode项目将它们嵌入到应用程序中。如果团队成员无法在本地安装Flutter SDK和CocoaPods,或者您不想在现有应用程序中将CocoaPods用作依赖项管理器,则可以使用此方式。每次在Flutter模块中进行代码更改时,都必须运行 <strong>flutter build ios</strong> 。</p>
<p>运行如下命令生成 Frameworks:</p>
<pre><code>flutter build ios-framework --output=./Flutter/
</code></pre>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223409402-1935068194.png"></p>
<p>执行完毕后在对应的目录下生成相关编译产物:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223409618-1849217595.png"></p>
<p>frameworks 已经生成,将 frameworks 链接到 iOS 应用程序有很多中方法,下面介绍一种, 打开 Xcode,</p>
<p>将 <strong>App.framework</strong> 和 <strong>Flutter.framework</strong> 拖入<strong>Build Settings &gt; Build Phases &gt; Link Binary With Libraries</strong>:<br>
<img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223411359-744812407.gif"></p>
<p>此时在项目的左侧增加 <strong>Frameworks</strong> 目录:</p>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223411720-1107463770.png"></p>
<p>在 <strong>Build Settings -&gt; Search Paths -&gt; Framework Search Paths</strong> 中添加 <strong>${PODS_ROOT}/../my_flutter/Flutter/Release</strong></p>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223412520-1409504800.png"></p>
<p>使用 <strong>⌘B</strong> 编译项目,编译成功。</p>
<h3 id="创建-flutterengine-和-flutterviewcontroller">创建 FlutterEngine 和 FlutterViewController</h3>
<p>将 Flutter 页面嵌入 iOS 应用程序需要创建 FlutterEngine(Flutter 引擎) 和 FlutterViewController,FlutterEngine 是Dart VM和Flutter运行时的 host,FlutterViewController 附着于 FlutterEngine,作用是通信和显示 Flutter UI。</p>
<p>创建 FlutterEngine:</p>
<pre><code class="language-swift">import UIKit
import Flutter

@UIApplicationMain
class AppDelegate: FlutterAppDelegate {
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")

override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: ?) -&gt; Bool {
   
    flutterEngine.run();
   
    return super.application(application, didFinishLaunchingWithOptions: launchOptions);
}
}
</code></pre>
<p>添加一个按钮,跳转到 Flutter 页面:</p>
<pre><code class="language-swift">import UIKit
import Flutter

class ViewController: UIViewController {

    override func viewDidLoad() {
      super.viewDidLoad()
      let button = UIButton(type:UIButton.ButtonType.custom)
      button.addTarget(self, action: #selector(showFlutter), for: .touchUpInside)
      button.setTitle("显示 Flutter", for: UIControl.State.normal)
      button.frame = CGRect(x: 80.0, y: 210.0, width: 160.0, height: 40.0)
      button.backgroundColor = UIColor.blue
      self.view.addSubview(button)
    }
   
    @objc func showFlutter() {
      let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
      let flutterViewController =
          FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
      present(flutterViewController, animated: true, completion: nil)
    }


}
</code></pre>
<p><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223413136-856282022.gif"></p>
<p>上面的代码使用了缓存 FlutterEngine,当然这也是推荐的一种方式。</p>
<p>还有一种方式是是使用隐含的FlutterEngine,使用隐含的FlutterEngine会明显增加显示Flutter UI的时间,通常不建议这样做,如果很少显示 Flutter 屏幕,没有好的方法来确定何时启动Dart VM以及何时Flutter不需要在视图控制器之间保持状态,则这可能很有用。</p>
<pre><code class="language-swift">func showFlutter() {
let flutterViewController = FlutterViewController(project: nil, nibName: nil, bundle: nil)
present(flutterViewController, animated: true, completion: nil)
}
</code></pre>
<h3 id="指定入口点">指定入口点</h3>
<p>默认情况下 FlutterEngine 加载 <strong>lib/main.dart 文件中的 main() 方法</strong>,也可以指定其他文件的方法:</p>
<pre><code>flutterEngine.run(withEntrypoint: "newEntrypoint", libraryURI: "main.dart")
</code></pre>
<h3 id="初始化路由">初始化路由</h3>
<p>从Flutter 1.22版开始,可以指定路由</p>
<pre><code>let flutterEngine = FlutterEngine()
flutterEngine.run(
withEntrypoint: FlutterDefaultDartEntrypoint, initialRoute: "/one_page")

</code></pre>
<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/202011/467322-20201102223413803-232880502.png"></td>
<td><img src="https://img2020.cnblogs.com/other/467322/202011/467322-20201102223414095-1729077621.png"></td>
</tr>
</tbody>
</table><br><br>
来源:https://www.cnblogs.com/mengqd/p/13916985.html
頁: [1]
查看完整版本: 【Flutter 混合开发】添加 Flutter 到 iOS