在Android和iOS中集成flutter

2018 年 12 月 6 日 CocoaChina

本公众号内容均为本号转发,已尽可能注明出处。因未能核实来源或转发内容图片有权利瑕疵的,请及时联系本号,本号会第一时间进行修改或删除。 QQ : 3442093904 

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' doplatform:ios,'8.0'
 flutter_application_path = '../my_flutter/'eval(File.read(File.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_tools/bin/xcode_backend.sh" embed

到text area,如下图:

配置完成之后,⌘B来build工程。如果没有报错,那么部署成功。下面开始写代码:

在AppDelegate.h中:

#import <UIKit/UIKit.h>#import <Flutter/Flutter.h>@interface AppDelegate : 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 application:application didFinishLaunchingWithOptions:launchOptions];
}@end

ViewController.m:

#import <Flutter/Flutter.h>#import "ViewController.h"@implementation 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。

作者:似水流年0_0

链接:https://my.oschina.net/gef/blog/2963186


--END--


登录查看更多
0

相关内容

Android(安卓)是一种以 Linux 为基础开发的开放源代码的操作系统,主要应用于便携设备。2005 年,Android 公司被 Google 收购,随后 Google 联合制造商组成开放手机联盟。Android 已从智能手机领域逐渐扩展到平板电脑、智能电视(及机顶盒)、游戏机、物联网、智能手表、车载系统、VR以及PC等领域。
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
117+阅读 · 2020年5月10日
TensorFlow Lite指南实战《TensorFlow Lite A primer》,附48页PPT
专知会员服务
69+阅读 · 2020年1月17日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
87+阅读 · 2019年11月25日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
22+阅读 · 2019年11月7日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
美团:基于跨平台框架Flutter的动态化平台建设
前端之巅
14+阅读 · 2019年6月17日
支持多标签页的Windows终端:Fluent 终端
Python程序员
7+阅读 · 2019年4月15日
已删除
创业邦杂志
5+阅读 · 2019年3月27日
从webview到flutter:详解iOS中的Web开发
前端之巅
5+阅读 · 2019年3月24日
Android P正式发布,你需要尽快做适配了
前端之巅
3+阅读 · 2018年8月7日
Python | Jupyter导出PDF,自定义脚本告别G安装包
程序人生
7+阅读 · 2018年7月17日
Arxiv
92+阅读 · 2020年2月28日
Arxiv
110+阅读 · 2020年2月5日
Arxiv
35+阅读 · 2019年11月7日
Semantics of Data Mining Services in Cloud Computing
Arxiv
4+阅读 · 2018年10月5日
A Survey on Deep Transfer Learning
Arxiv
11+阅读 · 2018年8月6日
VIP会员
相关资讯
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
美团:基于跨平台框架Flutter的动态化平台建设
前端之巅
14+阅读 · 2019年6月17日
支持多标签页的Windows终端:Fluent 终端
Python程序员
7+阅读 · 2019年4月15日
已删除
创业邦杂志
5+阅读 · 2019年3月27日
从webview到flutter:详解iOS中的Web开发
前端之巅
5+阅读 · 2019年3月24日
Android P正式发布,你需要尽快做适配了
前端之巅
3+阅读 · 2018年8月7日
Python | Jupyter导出PDF,自定义脚本告别G安装包
程序人生
7+阅读 · 2018年7月17日
相关论文
Top
微信扫码咨询专知VIP会员