Day22 - Flutter - 混合开发(下)

简介: Day22 - Flutter - 混合开发(下)
  • <2>、Java 代码
    实现思路和上面是一致的,只是使用了Java来实现:


package com.example.batterylevel2;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugin.common.MethodChannel;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
public class MainActivity extends FlutterActivity {
     private static final String CHANNEL = "com.jk/battery";
     @Override
     public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
          // 1.创建MethodChannel对象
          MethodChannel methodChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL);
          // 2.添加调用方法的回调
          methodChannel.setMethodCallHandler(
              (call, result) -> {
              // 2.1.如果调用的方法是getBatteryInfo,那么正常执行
              if (call.method.equals("getBatteryInfo")) {
                  // 2.1.1.调用另外一个自定义方法回去电量信息
                  int batteryLevel = getBatteryLevel();
                  // 2.1.2. 判断是否正常获取到
                  if (batteryLevel != -1) {
                      // 获取到返回结果
                     result.success(batteryLevel);
                  } else {
                     // 获取不到抛出异常
                    result.error("UNAVAILABLE", "Battery level not available.", null);
                  }
              } else {
                  // 2.2.如果调用的方法是getBatteryInfo,那么正常执行
                  result.notImplemented();
              }
           }
         );
     }
     private int getBatteryLevel() {
         int batteryLevel = -1;
         if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
             BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
             batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
         } else {
             Intent intent = new ContextWrapper(getApplicationContext()).
             registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
             batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
             intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
         }
         return batteryLevel;
     }
}


二、嵌入原有项目



首先,我们先明确一点: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


image.png

image.png


2.2、嵌入iOS项目


  • 嵌入到现有iOS项目有多种方式:
  • 可以使用 CocoaPods 依赖管理和已安装的 Flutter SDK ;
  • 也可以通过手动编译 Flutter engine 、你的 dart 代码和所有 Flutter plugin 成 framework ,用 Xcode 手动集成到你的应用中,并更新编译设置;
  • 目前iOS项目几乎都已经使用Cocoapods进行管理,所以推荐使用第一种CocoaPods方式;
  • 我们按照如下的方式,搭建一个需要继承的iOS项目:我们暂且起名字:testdemoios
  • 1、为了进行测试,我们这里创建一个默认的iOS项目:使用Xcode创建即可


image.png


image.png

2、将项目加入CocoaPods进行管理,电脑上需要已经安装了CocoaPods,直接百度输入 CocoaPods即可搜到很多的教程,按着教程来就好

初始化CocoaPods:

cd 进入刚才创建的 testdemoios
pod init

编译Podfile文件:

# platform :ios, '9.0'
# 添加模块所在路径,记得 `command + s` 保存
flutter_application_path = '../../my_flutter/my_flutter'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'testdemoios' do
    use_frameworks!
    # 安装Flutter模块
    install_all_flutter_pods(flutter_application_path)
end


提示: flutter_application_path = '../../my_flutter/my_flutter' 后面的路径,我们可以放一个统一的位置,方便团队开发


image.png

image.png

image.png

image.png

  • 安装CocoaPods的依赖


pod install
  • 2.2.1、Swift代码里面嵌入 上面 my_flutter 包
    为了在既有的iOS应用中展示Flutter页面,需要启动 Flutter Engine和 FlutterViewController。
    通常建议为我们的应用预热一个 长时间存活 的FlutterEngine:
    我们将在应用启动的 AppDelegate.swift 中创建一个 FlutterEngine,并作为属性暴露给外界。


import UIKit
import Flutter
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
     var window: UIWindow?
     lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
          // 开启引擎
          flutterEngine.run()
          return true
      }
}
  • 在启动的ViewController中,创建一个UIButton,并且点击这个Button时,弹出FlutterViewController


import UIKit
import Flutter
class ViewController: UIViewController {
   override func viewDidLoad() {
      super.viewDidLoad()
        view.backgroundColor = .green
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
        button .setTitle("进入 Flutter 界面", for: .normal)
        button.backgroundColor = .brown
        button.center = view.center
        button.addTarget(self, action: #selector(click), for: .touchUpInside)
        view.addSubview(button)
   }
   @objc func click() {
        let flutterVC = FlutterViewController(engine: (UIApplication.shared.delegate as! AppDelegate).flutterEngine, nibName: nibName, bundle: nil)
        self .present(flutterVC, animated: true, completion: nil)
   }
}

image.png

image.png


  • 提示:我当时运行代码报错:framework not found FlutterPluginRegistrant,我进行了一下 pod update 就好了\
  • 我们也可以省略预先创建的 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];
      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


扩展:在原生项目开启 Flutter的热更新和热加载,也就是flutter代码修改完,原生项目不用再启动,就可以直接看到flutter代码的修改内容

步骤如下:

1、关闭模拟器开启的项目,杀死模拟器的APP

2、进入module项目的根目录,终端执行下面的代码,选择对用的设备

flutter attach



image.png

image.png


3、打开app,在flutter修改完项目后,在终端输入对应的指令,app界面跟着变化

  • 2.3.嵌入Android项目嵌入到现有Android项目有多种方式:
  • 编译为AAR文件(Android Archive):通过Flutter编译为aar,添加相关的依赖
  • 依赖模块的源码方式,在gradle进行配置
  • 这里我们采用第二种方式
  • 1>、创建一个Android的测试项目,使用Android Studio创建



image.png

2>、添加相关的依赖

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


image.png


include ':app'
rootProject.name = "testdemoandroid"
setBinding(new Binding([gradle: this]))                                 // new
evaluate(new File(                                                      // new
     settingsDir.parentFile,                                               // new
      '../my_flutter/my_flutter/.android/include_flutter.groovy'                          // new
))


提示: File() 后面的路径是 my_flutter 项目的路径,我放置的和上面iOS那个图一样


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

image.png


dependencies {
   implementation project(':flutter')
}


编译代码,可能会出现如下错误: 1、这是因为从Java8开始才支持接口方法;2、Flutter Android引擎使用了该Java8的新特性


image.png

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


image.png

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.jk.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.jk.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)
        );
   }
}
  • 2.3.2、Kotlin代码


package com.jk.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


网络异常,图片无法展示
|


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