1. 程式人生 > >在Android和iOS中整合flutter

在Android和iOS中整合flutter

  flutter可能是未來跨平臺開發的又一技術框架,那麼對於一個app,我們不可能完全用flutter來開發,那麼就意味著我們需要在已有的Android和iOS程式碼中去整合flutter。目前這一技術還處於預覽狀態,並且還要切換flutter的channel為mater分支。如下,官方原話:
  
  那麼我們在整合之前需要檢視現在flutter處於什麼渠道:
  
  我的是處於master分支,如果你以前沒改過的話,應該是beta分支,那麼可以執行:
  
  flutter channel master
  
  進行切換。
  
  下面正式開始整合Android和iOS。
  
  Android
  
  首先用Android studio建立一個Android工程,步驟不做介紹了。然後在Android工程的根目錄執行一下命令:
  
  flutter create -t module my_flutter
  
  來建立一個flutter的module,成功之後,目錄結構如下:
  
  接著我們來修改一下Android功能裡的gradle檔案:
  
  首先是app的setting.gradle檔案,新增如下:
  
  include ':app'
  
  setBinding(new Binding([gradle: this]))
  
  evaluate(new File(
  
  settingsDir.parentFile,
  
  'my_flutter/.android/include_flutter.groovy'
  
  ))
  
  目的就是去載入指定目錄的include_flutter.groovy檔案,那麼我們檢視一下這個檔案:
  
  // Generated file. Do not edit.
  
  def scriptFile = getClass().protectionDomain.codeSource.location.path
  
  def flutterProjectRoot = new File(scriptFile).parentFile.parentFile
  
  gradle.include ':flutter'
  
  gradle.project(':flutter').projectDir = new File(flutterProjectRoot, '.android/Flutter')
  
  def plugins = new Properties()
  
  def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins')
  
  if (pluginsFile.exists()) {
  
  pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
  
  }
  
  plugins.each { name, path ->
  
  def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
  
  gradle.include ":$name"
  
  gradle.project(":$name").projectDir = pluginDirectory
  
  }
  
  gradle.getGradle().projectsLoaded { g ->
  
  g.rootProject.afterEvaluate { p ->
  
  p.subprojects { sp ->
  
  if (sp.name != 'flutter') {
  
  sp.evaluationDependsOn(':flutter')
  
  }
  
  }
  
  }
  
  }
  
  其中最重要的一段程式碼,就是include ':flutter',意思就是flutter這個module要參與編譯。
  
  接著在app層級(不是project層)的build.gradle檔案中新增依賴:
  
  dependencies {
  
  implementation project(':flutter')
  
  :
  
  }
  
  OK配置階段結束,我們開始先寫Android程式碼,在activity中新增一個button,當我們點選它時,將載入flutter佈局,程式碼如下:
  
  public class MainActivity extends AppCompatActivity {
  
  private TextView button;
  
  @Override
  
  protected void onCreate(Bundle savedInstanceState) {
  
  super.onCreate(savedInstanceState);
  
  setContentView(R.layout.activity_main);
  
  button = findViewById(R.id.button);
  
  button.setOnClickListener(new View.OnClickListener() {
  
  @Override
  
  public void onClick(View view) {
  
  FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
  
  tx.replace(R.id.container, Flutter.createFragment("route1"));
  
  tx.commit();
  
  // View flutterView = Flutter.createView(MainActivity.this,getLifecycle(),"route1");
  
  // FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(100,100);
  
  // params.leftMargin = 100;
  
  // params.topMargin = 200;
  
  // addContentView(flutterView,params);
  
  }
  
  });
  
  }
  
  }
  
  這裡有兩種實現方式,一種是使用fragment,一種是使用FlutterView。程式碼中的route1字串則是flutter程式碼中定義的,接下來就開始寫flutter程式碼:
  
  import 'dart:ui';
  
  import 'package:flutter/material.dart';
  
  void main() => runApp(_widgetForRoute(window.defaultRouteName));
  
  Widget _widgetForRoute(String route) {
  
  switch (route) {
  
  case 'route1':
  
  return SomeWidget();
  
  case 'route2':
  
  return SomeWidget();
  
  default:
  
  return Center(
  
  child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
  
  );
  
  }
  
  }
  
  class SomeWidget extends StatelessWidget{
  
  @override
  
  Widget build(BuildContext context) {
  
  // TODO: implement build
  
  return Container(
  
  width: 100,
  
  height: 100,
  
  color: Color(0xFF00FF00),
  
  child: Center(
  
  child: Text("hello",textDirection: TextDirection.ltr,),
  
  ),
  
  );
  
  }
  
  }
  
  這裡可以看到對rout1的定義。
  
  寫到這裡程式碼部分就完成了,然後執行android專案,就可以看到效果了。
  
  ios
  
  首先也是執行:
  
  flutter create -t module my_flutter
  
  生成一個flutter工程,由於在Android整合中已經做了這一步,故跳過。然後用Xcode建立一個iOS工程,建立完成之後,目錄如下:
  
  下面為工程新增flutter的依賴,這裡要使用cocoapods,若以前沒有安裝過,則執行命令:
  
  sudo gem install cocoapods
  
  然後在iOS工程的根目錄建立Podfile檔案,命令為:
  
  touch Podfile
  
  然後修改podfile檔案,如下:
  
  target 'ios4Flutter' do
  
  platform:ios,'8.0'
  
  flutter_application_path =www.feifanyule.cn '../my_flutter/'
  
  eval(File.read(File.www.dfgjpt.com/ join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
  
  end
  
  其中ios4Flutter為我的iOS工程名,flutter_application_path為flutter工程的根目錄。
  
  最後執行:
  
  pod install
  
  完成專案的依賴,效果如下:
  
  之後點選.xcworkSpace檔案開啟iOS工程,找到Build Phases目錄,新建一個Script Phase,貼上下面的命令:
  
  "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
  
  "$FLUTTER_ROOT/packages/flutter_www.haom178.com tools/bin/xcode_backend.sh" embed
  
  到text area,如下圖:
  
  配置完成之後,⌘B來build工程。如果沒有報錯,那麼部署成功。下面開始寫程式碼:
  
  在AppDelegate.h中:
  
  #import <UIKit/UIKit.h>
  
  #import <Flutter/Flutter.h>
  
  @interface AppDelegate :www.gcyl152.com FlutterAppDelegate
  
  @end
  
  AppDelegate.m:
  
  #import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> // Only if you have Flutter Plugins
  
  #include "AppDelegate.h"
  
  @implementation AppDelegate
  
  // This override can be omitted if you do not have any Flutter Plugins.
  
  - (BOOL)application:(UIApplication *)application
  
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  
  [GeneratedPluginRegistrant registerWithRegistry:self];
  
  return [super www.gcyL157.com application:application didFinishLaunchingWithOptions:launchOptions];
  
  }
  
  @end
  
  ViewController.m:
  
  #import <Flutter/Flutter.h>
  
  #import "ViewController.h"
  
  @implementation www.michenggw.com ViewController
  
  - (void)viewDidLoad {
  
  [super viewDidLoad];
  
  UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
  
  [button addTarget:self
  
  action:@selector(handleButtonAction)
  
  forControlEvents:UIControlEventTouchUpInside];
  
  [button setTitle:@"Press me" forState:UIControlStateNormal];
  
  [button setBackgroundColor:[UIColor blueColor]];
  
  button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
  
  [self.view addSubview:button];
  
  }
  
  - (void)handleButtonAction {
  
  FlutterViewController* flutterViewController = [[FlutterViewController alloc] init];
  
  [flutterViewController setInitialRoute:@"route1"];
  
  [self presentViewController:flutterViewController animated:false completion:nil];
  
  }
  
  @end
  
  OK,oc程式碼編寫完成,執行app,呈現效果。
  
  Hot restart/reload and debugging Dart code
  
  我們可以運用dart語言的特性實現 hot reload,首先在flutter的根目錄執行:
  
  flutter attach
  
  如下:
  
  當執行完app,點選按鈕進入flutter的view時,終端狀態如下:
  
  當我們再次修改dart程式碼,儲存之後,在命令中輸入r即可hot reload。