Flutter 混合开发(下)

简介: 某些应用程序可能需要使用移动设备进行拍照或者选择相册中的照片,Flutter官方提供了插件:image_picker

二. 嵌入原有项目


首先,我们先明确一点:Flutter设计初衷并不是为了和其它平台进行混合开发,它的目的是为了打造一个完整的跨平台应用程序。

但是,实际开发中,原有项目完全使用Flutter进行重构并不现实,对于原有项目我们更多可能采用混合开发的方式。


2.1. 创建Flutter模块


对于需要进行混合开发的原有项目,Flutter可以作为一个库或者模块,继承进现有项目中。

  • 模块引入到你的Android或iOS应用中,以使用Flutter渲染一部分的UI,或者共享的Dart代码。
  • 在Flutter v1.12中,添加到现有应用的基本场景已经被支持,每个应用在同一时间可以集成一个全屏幕的Flutter实例。

但是,目前一些场景依然是有限制的:

  • 运行多个Flutter实例,或在屏幕局部上运行Flutter可能会导致不可以预测的行为;
  • 在后台模式使用Flutter的能力还在开发中(目前不支持);
  • 将Flutter库打包到另一个可共享的库或将多个Flutter库打包到同一个应用中,都不支持;
  • 添加到应用在Android平台的实现基于 FlutterPlugin 的 API,一些不支持 FlutterPlugin 的插件可能会有不可预知的行为。

创建Flutter Module

flutter create --template module my_flutter

创建完成后,该模块和普通的Flutter项目一直,可以通过Android Studio或VSCode打开、开发、运行;

目录结构如下:

  • 和之前项目不同的iOS和Android项目是一个隐藏文件,并且我们通常不会单独打开它们再来运行;
  • 它们的作用是将Flutter Module进行编译,之后继承到现有的项目中;
my_flutter/
├── .ios/
├── .android/
├── lib/
│   └── main.dart
├── test/
└── pubspec.yaml


2.2. 嵌入iOS项目


嵌入到现有iOS项目有多种方式:

  • 可以使用 CocoaPods 依赖管理和已安装的 Flutter SDK ;
  • 也可以通过手动编译 Flutter engine 、你的 dart 代码和所有 Flutter plugin 成 framework ,用 Xcode 手动集成到你的应用中,并更新编译设置;

目前iOS项目几乎都已经使用Cocoapods进行管理,所以推荐使用第一种CocoaPods方式;

我们按照如下的方式,搭建一个需要继承的iOS项目:

1.为了进行测试,我们这里创建一个默认的iOS项目:使用Xcode创建即可

image.png                                                   创建一个iOS项目

2.将项目加入CocoaPods进行管理

  • 电脑上需要已经安装了CocoaPods

初始化CocoaPods:

pod init

安装CocoaPods的依赖:

pod install

编译Podfile文件:

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
# 添加模块所在路径
flutter_application_path = '../my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'ios_my_test' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  # 安装Flutter模块
  install_all_flutter_pods(flutter_application_path)
  # Pods for ios_my_test
end

重新执行安装CocoaPods的依赖:

pod install


2.2.1. Swift代码


为了在既有的iOS应用中展示Flutter页面,需要启动 Flutter EngineFlutterViewController

通常建议为我们的应用预热一个 长时间存活 的FlutterEngine:

  • 我们将在应用启动的 app delegate 中创建一个 FlutterEngine,并作为属性暴露给外界。
import UIKit
import FlutterPluginRegistrant
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
   // 1.创建一个FlutterEngine对象
    lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       // 2.启动flutterEngine
        flutterEngine.run()
        return true
    }
}

在启动的ViewController中,创建一个UIButton,并且点击这个Button时,弹出FlutterViewController

import UIKit
import Flutter
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
       // 1.创建一个按钮
        let button = UIButton(type: UIButton.ButtonType.custom)
        button.addTarget(self, action: #selector(showFlutter), for: .touchUpInside)
        button.setTitle("Show Flutter", for: .normal)
        button.frame = CGRect(x: 80, y: 210, width: 160, height: 40)
        button.backgroundColor = UIColor.blue
        self.view.addSubview(button)
    }
    @objc func showFlutter() {
        // 2.创建FlutterViewController对象(需要先获取flutterEngine)
        let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine;
        let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil);
        navigationController?.pushViewController(flutterViewController, animated: true);
    }
}

image.png                                                      代码效果

我们也可以省略预先创建的 FlutterEngine

  • 不推荐这样来做,因为在第一针图像渲染完成之前,可能会出现明显的延迟。
func showFlutter() {
  let flutterViewController = FlutterViewController(project: nil, nibName: nil, bundle: nil)
  present(flutterViewController, animated: true, completion: nil)
}


2.2.2. Objective-C代码


如果上面的代码希望使用Objective-C也是可以实现的:

  • 代码的逻辑是完成一直的

AppDelegate.h代码:

@import UIKit;
@import Flutter;
@interface AppDelegate : FlutterAppDelegate 
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end

AppDelegate.m代码:

#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> // Used to connect plugins.
#import "AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {
  self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
  [self.flutterEngine run];
  [GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

ViewController.m代码:

@import Flutter;
#import "AppDelegate.h"
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Make a button to call the showFlutter function when pressed.
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:self
               action:@selector(showFlutter)
     forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Show Flutter!" forState:UIControlStateNormal];
    button.backgroundColor = UIColor.blueColor;
    button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
    [self.view addSubview:button];
}
- (void)showFlutter {
    FlutterEngine *flutterEngine =
        ((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
    FlutterViewController *flutterViewController =
        [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
    [self presentViewController:flutterViewController animated:YES completion:nil];
}
@end


2.3.嵌入Android项目


嵌入到现有Android项目有多种方式:

  • 编译为AAR文件(Android Archive)
  • 通过Flutter编译为aar,添加相关的依赖
  • 依赖模块的源码方式,在gradle进行配置

这里我们采用第二种方式

1.创建一个Android的测试项目

  • 使用Android Studio创建

image.png                                              创建Android项目

2.添加相关的依赖

修改Android项目中的settings.gradle文件:

// Include the host app project.
include ':app'                                     // assumed existing content
setBinding(new Binding([gradle: this]))                                 // new
evaluate(new File(                                                      // new
  settingsDir.parentFile,                                               // new
  'my_flutter/.android/include_flutter.groovy'                          // new
))

另外,我们需要在Android项目工程的build.gradle中添加依赖:

dependencies {
  implementation project(':flutter')
}

编译代码,可能会出现如下错误:

  • 这是因为从Java8开始才支持接口方法
  • Flutter Android引擎使用了该Java8的新特性

image.png

解决办法:通过设置Android项目工程的build.gradle配置使用Java8编译:

compileOptions {
    sourceCompatibility 1.8
    targetCompatibility 1.8
  }

接下来,我们这里尝试添加一个Flutter的screen到Android应用程序中

Flutter提供了一个FlutterActivity来展示Flutter界面在Android应用程序中,我们需要先对FlutterActivity进行注册:

  • 在AndroidManifest.xml中进行注册
<activity
  android:name="io.flutter.embedding.android.FlutterActivity"
  android:theme="@style/AppTheme"
  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  android:hardwareAccelerated="true"
  android:windowSoftInputMode="adjustResize"
  />


2.3.1. Java代码


package com.coderwhy.testandroid;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        startActivity(
            FlutterActivity.createDefaultIntent(this)
        );
    }
}

也可以在创建时,传入默认的路由:

package com.coderwhy.testandroid;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        startActivity(
          FlutterActivity
          .withNewEngine()
          .initialRoute("/my_route")
          .build(currentActivity)
        );
    }
}

image.png                                        将Flutter页面嵌入到Android项目


2.3.2. Kotlin代码


package com.coderwhy.test_demo_a_k
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_main)
        startActivity(
            FlutterActivity.createDefaultIntent(this)
        )
    }
}

也可以在创建时指定路由:

package com.coderwhy.test_demo_a_k
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_main)
        startActivity(
            FlutterActivity
                .withNewEngine()
                .initialRoute("/my_route")
                .build(this)
        );
    }
}


三. Flutter模块调试


一旦将Flutter模块继承到你的项目中,并且使用Flutter平台的API运行Flutter引擎或UI,那么就可以先普通的Android或者iOS一样来构建自己的Android或者iOS项目了

但是Flutter的有一个非常大的优势是其快速开发,也就是hot reload。

那么对应Flutter模块,我们如何使用hot reload加速我们的调试速度呢?

  • 可以使用flutter attach
# --app-id是指定哪一个应用程序
# -d是指定连接哪一个设备
flutter attach --app-id com.coderwhy.ios-my-test -d 3D7A877C-B0DD-4871-8D6E-0C5263B986CD

image.png                                                   attach调试模式

相关文章
|
2月前
|
缓存 监控 前端开发
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
【4月更文挑战第30天】本文探讨了Flutter应用启动优化策略,包括理解启动过程、资源加载优化、减少初始化工作、界面布局简化、异步初始化、预加载关键数据、性能监控分析以及案例和未来优化方向。通过这些方法,可以缩短启动时间,提升用户体验。使用Flutter DevTools等工具可助于识别和解决性能瓶颈,实现持续优化。
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
|
27天前
|
开发框架 前端开发 测试技术
Flutter开发常见问题解答
Flutter开发常见问题解答
|
2月前
|
前端开发 C++ 容器
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
|
16天前
|
开发框架 移动开发 Android开发
构建高效移动应用:探索Flutter开发框架
【6月更文挑战第28天】随着移动设备的普及,用户对移动应用的需求日益增长。开发者面临着在众多平台间提供无缝体验的挑战。本文深入探讨了Flutter框架如何通过其跨平台特性、热重载功能以及丰富的组件库简化移动应用的开发流程,同时确保高性能和优雅的用户界面设计。
26 2
|
2月前
|
Dart 安全
简化代码、提高效率:Dart和Flutter开发小技巧
在日常开发中,我们常常会使用一些常用的技巧或语法糖,以简化代码、提高开发效率。本文将分享一些在Dart和Flutter中常用的小贴士,帮助你更轻松地编写优雅高效的代码。
简化代码、提高效率:Dart和Flutter开发小技巧
|
1月前
|
Dart 监控 测试技术
在Flutter开发中,注重代码质量与重构实践显得尤为重要
【6月更文挑战第11天】随着Flutter在跨平台开发的普及,保持高质量代码成为开发者关注的重点。良好的代码质量关乎应用性能、稳定性和开发效率。为提升Flutter代码质量,开发者应遵循最佳实践,编写可读性高的代码,实施代码审查和自动化测试。重构实践在应对代码复杂性时也至关重要,包括识别重构时机、制定计划、逐步操作及利用重构工具。注重代码质量和重构是Flutter开发成功的关键。
39 3
|
12天前
|
Dart Android开发 iOS开发
flutter插件开发
flutter插件开发
|
26天前
|
移动开发 小程序 安全
基础入门-APP架构&小程序&H5+Vue语言&Web封装&原生开发&Flutter
基础入门-APP架构&小程序&H5+Vue语言&Web封装&原生开发&Flutter
|
2月前
|
Dart 前端开发 安全
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
【4月更文挑战第30天】本文探讨了Flutter中线程管理和并发编程的关键性,强调其对应用性能和用户体验的影响。Dart语言提供了`async`、`await`、`Stream`和`Future`等原生异步支持。Flutter采用事件驱动的单线程模型,通过`Isolate`实现线程隔离。实践中,可利用`async/await`、`StreamBuilder`和`Isolate`处理异步任务,同时注意线程安全和性能调优。参考文献包括Dart异步编程、Flutter线程模型和DevTools文档。
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
|
1月前
|
Dart 前端开发 JavaScript
Flutter for Web:跨平台移动与Web开发的新篇章
Flutter for Web是Google的开源UI工具包Flutter的延伸,用于构建高性能、高保真的跨平台应用,包括Web。它基于Dart语言和Flutter的核心框架,利用Skia渲染引擎通过WebAssembly在Web上运行。开发流程包括安装SDK、创建项目、编写Dart代码和部署。性能优化涉及减少渲染开销、代码压缩等。与传统Web框架相比,Flutter for Web在开发效率和性能上有优势,但兼容性和生态系统尚待完善。
25 0