快速入门

例子介绍

本章通过一个小例子使你对bazel在iOS下的使用快速入门。现在我们有两个独立的项目HelloBazel和AFNetworking,HelloBazel是一个单视图app项目,AFNetworking是一个静态库项目,HelloWorld需要引用AFNetworking进行网络访问。将两个项目置于JingoalBuild文件夹下,结构如下:

文件结构

组织bazel构建层次

1.根目录

bazel根目录使用WORKSAPCE文件标识,构建过程从含有WORKSPACE的文件夹开始进行目录层次的查找,运行如下命令创建WORKSPACE.

 $ cd JingoalBuild
 $ touch WORKSPACE

2.含有源代码的构建目录

bazel构建目录为含有build文件的子文件夹,bazel使用buld文件中的配置来编译该目录下的所有源代码文件,bazel将含有build文件的文件夹称为一个package,package是用来进行资源定位和依赖查找的一种手段。分别进入AFNetworking和HelloBazel进行BUILD的创建,这里只演示HelloBazel的过程,AFNetworking执行相同的操作。

$ cd HelloBazel
$ touch BUILD
$ chmod +x BUILD (变成可执行文件,google例子均为这样)

3.创建完成后的目录如下:

创建build

添加构建代码

1.准备工作

  • 将iOS_Third_Party_Source/lib/AFNetworking/AFNetworking/AFNetworking 下的源代码加入AFNetworking项目

  • 在HelloBazel的ViewController.m引入网络访问代码:

#import "AFNetworking.h"

- (void)viewDidLoad {
    [super viewDidLoad];
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

    NSURL *URL = [NSURL URLWithString:@"http://httpbin.org/get"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];

    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error);
        } else {
            NSLog(@"%@ %@", response, responseObject);
        }
    }];
    [dataTask resume];

}

注意: 在IDE开发流程中直接引入头文件会出现查找错误,你需要引入依赖项目,或者导入依赖项目的库文件和头文件,在bazel构建中,IDE的依赖配置对我们的构建过程没有影响,后面我们将看到这一点。

2.添加AFNetworking的构建代码

打开AFNetworking下的BUILD文件,加入如下代码:

objc_library(
    name = "AFNetworkingLib",
    srcs = glob(["AFNetworking/*.m"]),
    hdrs = glob(["AFNetworking/*.h"]),
    sdk_frameworks = ["Foundation","CoreGraphics","SystemConfiguration","Security","MobileCoreServices","CFNetwork"],
    visibility = ["//visibility:public"]
)

objc_library : 指明当前package构建一个.a结尾的iOS库文件,为一个规则,更多关于iOS的详细规则看这里

name : 该依赖规则名称,bazel在指定依赖关系时使用

srcs : 该依赖规则使用的.m文件,glob函数会自动匹配AFNetworking文件夹下所有的.m文件,如要递归匹配所有的子文件夹可以使用glob(["*/.m"])

hdrs : 该依赖规则使用的头文件

sdk_frameworks : 该依赖规则使用的系统库

visibility : 该依赖规则的访问权限,public指明所有其他的package都可访问

3.添加HelloBazel的构建代码

打开HelloBazel下的BUILD文件添加如下代码:

ios_application( #该规则指明当前构建最终生成可在模拟器或真机运行的app
    name = "HelloBazel-app",
    binary = "HelloBazel-app-binary",#依赖的二进制
    infoplist = "HelloBazel/Info.plist" #同iOS
)

objc_binary(#二进制文件一般为main.m文件
    name = "HelloBazel-app-binary",
    srcs = [
        "HelloBazel/main.m"
    ],
    deps = [
        ":HelloBazelLib",#二进制文件依赖的库文件,":"冒号指明依赖是在当前规则中
    ],
)

objc_library(//同AFNetworking下的objc_library规则
    name = "HelloBazelLib",
    srcs = [
        "HelloBazel/AppDelegate.m",
        "HelloBazel/ViewController.m"
    ],
    deps = ["//AFNetworking:AFNetworkingLib"],
    includes = ["../AFNetworking/AFNetworking"],
    storyboards = ["HelloBazel/Base.lproj/Main.storyboard"],
)

注意 :

  • objc_library中的deps指明了一个外部依赖,"//"表示该依赖从根文件夹也就是含有WORKSPACE的文件夹开始查找(当前例子就是JingoalBuild),"//AFNetworking:AFNetworkingLib"表示依赖位于根文件夹的AFNetworking文件夹中,依赖名称为"AFNetworkingLib" 以"//"开始的依赖查找路径的最终文件夹,也就是冒号左边第一个文件夹,必须含有BUILD(本例中为AFNetworking,也是一个package),冒号右边为BUILD中的规则名称。

  • includes用来将外部库的头文件查找路径包含入当前规则,否则将出现找不到头文件,和你在xcode中添加的外部依赖或导入的头文件一样,文件的定位以当前规则所在的BUILD文件为准,只能使用相对路径不能使用绝对路径。

开始构建

进入HelloBazel文件夹,执行下列代码:

bazel build --ios_sdk_version=9.3 //HelloBazel:HelloBazel-app

将得到如下输出:

INFO: Found 1 target...
Target //HelloBazel:HelloBazel-app up-to-date:
  bazel-bin/HelloBazel/HelloBazel-app.ipa
  bazel-bin/HelloBazel/HelloBazel-app.xcodeproj/project.pbxproj
INFO: Elapsed time: 7.193s, Critical Path: 6.96s

其中ios_sdk_version根据机器安装xcode的版本进行指定 编译过的整合项目将出现在根目录的bazel-bin文件夹下,详细的路径可看上方日志。