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月前
|
Android开发 iOS开发 容器
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
|
5月前
|
开发框架 前端开发 测试技术
Flutter开发常见问题解答
Flutter开发常见问题解答
|
1月前
|
开发者
鸿蒙Flutter实战:07-混合开发
鸿蒙Flutter混合开发支持两种模式:1) 基于har包,便于主项目开发者无需关心Flutter细节,但不支持热重载;2) 基于源码依赖,利于代码维护与热重载,需配置Flutter环境。项目结构包括AppScope、flutter_module等目录,适用于不同开发需求。
74 3
|
17天前
|
传感器 开发框架 物联网
鸿蒙next选择 Flutter 开发跨平台应用的原因
鸿蒙(HarmonyOS)是华为推出的一款旨在实现多设备无缝连接的操作系统。为了实现这一目标,鸿蒙选择了 Flutter 作为主要的跨平台应用开发框架。Flutter 的跨平台能力、高性能、丰富的生态支持和与鸿蒙系统的良好兼容性,使其成为理想的选择。通过 Flutter,开发者可以高效地构建和部署多平台应用,推动鸿蒙生态的快速发展。
129 0
|
19天前
|
Dart 安全 UED
Flutter&鸿蒙next中的表单封装:提升开发效率与用户体验
在移动应用开发中,表单是用户与应用交互的重要界面。本文介绍了如何在Flutter中封装表单,以提升开发效率和用户体验。通过代码复用、集中管理和一致性的优势,封装表单组件可以简化开发流程。文章详细讲解了Flutter表单的基础、封装方法和表单验证技巧,帮助开发者构建健壮且用户友好的应用。
60 0
|
1月前
|
开发框架 移动开发 Android开发
安卓与iOS开发中的跨平台解决方案:Flutter入门
【9月更文挑战第30天】在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各自占据半壁江山。开发者们常常面临着选择:是专注于单一平台深耕细作,还是寻找一种能够横跨两大系统的开发方案?Flutter,作为一种新兴的跨平台UI工具包,正以其现代、响应式的特点赢得开发者的青睐。本文将带你一探究竟,从Flutter的基础概念到实战应用,深入浅出地介绍这一技术的魅力所在。
77 7
|
1月前
|
编解码 Dart API
鸿蒙Flutter实战:06-使用ArkTs开发Flutter鸿蒙插件
本文介绍了如何开发一个 Flutter 鸿蒙插件,实现 Flutter 与鸿蒙的混合开发及双端消息通信。通过定义 `MethodChannel` 实现 Flutter 侧的 token 存取方法,并在鸿蒙侧编写 `EntryAbility` 和 `ForestPlugin`,使用鸿蒙的首选项 API 完成数据的读写操作。文章还提供了注意事项和参考资料,帮助开发者更好地理解和实现这一过程。
57 0
|
1月前
|
Dart Android开发
鸿蒙Flutter实战:03-鸿蒙Flutter开发中集成Webview
本文介绍了在OpenHarmony平台上集成WebView的两种方法:一是使用第三方库`flutter_inappwebview`,通过配置pubspec.lock文件实现;二是编写原生ArkTS代码,自定义PlatformView,涉及创建入口能力、注册视图工厂、处理方法调用及页面构建等步骤。
52 0
|
2月前
|
JSON Dart Java
flutter开发多端平台应用的探索
flutter开发多端平台应用的探索
50 6
|
2月前
|
JSON Dart Java
flutter开发多端平台应用的探索 下 (跨模块、跨语言通信之平台通道)
flutter开发多端平台应用的探索 下 (跨模块、跨语言通信之平台通道)