<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Ios on chai2010 的博客</title>
    <link>https://chai2010.cn/tags/ios/</link>
    <description>Recent content in Ios on chai2010 的博客</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-CN</language>
    <lastBuildDate>Wed, 25 May 2016 00:00:00 +0000</lastBuildDate>
    
        <atom:link href="https://chai2010.cn/tags/ios/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>使用Go语言开发iOS应用(Swift版)</title>
      <link>https://chai2010.cn/post/golang/go-ios-app/</link>
      <pubDate>Wed, 25 May 2016 00:00:00 +0000</pubDate>
      
      <guid>https://chai2010.cn/post/golang/go-ios-app/</guid>
      
        <description>

&lt;h1 id=&#34;使用go语言开发ios应用-swift版&#34;&gt;使用Go语言开发iOS应用(Swift版)&lt;/h1&gt;

&lt;p&gt;本文加上读者对Go语言和Swift语言都有一定了解, 但是对二者混合使用不了解的同学.&lt;/p&gt;

&lt;p&gt;本教程是基于一个真实上架的iOS应用做的简单的总结。&lt;/p&gt;

&lt;p&gt;我们先看看运行效果：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://chai2010.cn/images/go-ios-yjyy-01.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;

&lt;p&gt;Go语言是Google公司于2010年开源的一个面向网络服务和多并发环境的编程语言，特点是简单。
但是因为简单，也就只能实现90%的性能，这是Go语言的最大优点，因为 少即是多 的道理不是每个人都能领悟的。&lt;/p&gt;

&lt;p&gt;Swift是Apple公司于2014年发布的用来替代ObjectiveC的语言，主要面向iOS和OS X上的界面程序开发。
当然用swift来开发服务器也是大家关注的一个领域，作者看好在不远的将来Swift将逐步替代C++和Rust语言。&lt;/p&gt;

&lt;p&gt;Go语言和Swift语言本来是风马牛不相及的两个语言，为何非一定要整到一起呢？
原因很简单，因为作者是一个Go粉，同时也算是半个Swift粉；想试水iOS开发，但是实在是受不了ObjectiveC的裹脚布语法。&lt;/p&gt;

&lt;p&gt;补充下：本人虽然不喜欢ObjectiveC的语法，但是觉得ObjectiveC的runtime还是很强悍的。
理论上，基于ObjectiveC的runtime，可以用任何流行的编程语言来开发iOS应用，RubyMotion就是一个例子。&lt;/p&gt;

&lt;p&gt;其实，现在流行的绝大部分语言都有一个交集，就是c语言兼容的二进制接口。
所以说，C++流行并不是C++多厉害，而是它选择几本无缝兼容了C语言的规范。&lt;/p&gt;

&lt;p&gt;但是，完全兼容C语言的规范也有缺点，就是语言本身无法自由地发展，因为很多地方会受到C语言编程模型的限制。
C++和ObjectiveC是两个比较有代表的例子。&lt;/p&gt;

&lt;p&gt;所以说，Swift一出世就兼容C语言的二进制接口规范，同时抱紧了ObjectiveC的runtime大腿，而去自己确实有很大优秀的特性。&lt;/p&gt;

&lt;p&gt;但是，我们这里暂时不关心Swift和ObjectiveC的混合编程，我们只关注作为ObjectiveC子集的C语言如何与Swift混合编程。&lt;/p&gt;

&lt;h2 id=&#34;swift调用c函数&#34;&gt;Swift调用C函数&lt;/h2&gt;

&lt;p&gt;Swift调用C函数的方法有多种：通过ObjectiveC桥接调用和直接调用。其实两者的原理是一样的，我个人跟喜欢选择最直接也最暴力的直接调用C函数的方式。&lt;/p&gt;

&lt;p&gt;比如有一个C函数:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

void getInput(int *output) {
    scanf(&amp;quot;%i&amp;quot;, output);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;生成一个桥接的头文件&lt;code&gt;xxx-Bridging-Header.h&lt;/code&gt;，里面包含c函数规格说明：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;void getInput(int *output);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;swift就可以直接使用了:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import Foundation

var output: CInt = 0
getInput(&amp;amp;output)

println(output)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果不用桥接文件，可以在swift中声明一个Swift函数，对应C函数:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@_silgen_name(&amp;quot;getInput&amp;quot;) func getInput_swift(query:UnsafePointer&amp;lt;CInt&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;为了明确区分C函数和swift函数，我们将&lt;code&gt;getInput&lt;/code&gt;重新声明为&lt;code&gt;getInput_swift&lt;/code&gt;，使用方法和前面一样：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import Foundation

var output: CInt = 0
getInput_swift(&amp;amp;output)

println(output)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;swift中如何管理c返回的内存&#34;&gt;Swift中如何管理c返回的内存&lt;/h2&gt;

&lt;p&gt;Swift语言本身是自带ARC的，用户很少直接关注内存问题。但是C函数如果返回内存到Swift空间，
Swift的ARC是无效的，需要手工释放C内存。&lt;/p&gt;

&lt;p&gt;假设我们自己用C语言实现了一个字符串克隆的函数:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;char* MyStrDup(char* s) {
    return strdup(s);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在swift中可以这样使用：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@_silgen_name(&amp;quot;MyStrDup&amp;quot;)
func MyStrDup_swift(query:UnsafePointer&amp;lt;CChar&amp;gt;) -&amp;gt; UnsafeMutablePointer&amp;lt;CChar&amp;gt;

let p = MyStrDup_swift(&amp;quot;hello swift-c!&amp;quot;)
let s = String.fromCString(p)!
p.dealloc(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;使用&lt;code&gt;String.fromCString(p)!&lt;/code&gt;从C字符串构建一个swift字符串，然后手工调用&lt;code&gt;p.dealloc(1)&lt;/code&gt;释放c字符串内存空间。&lt;/p&gt;

&lt;p&gt;函数调用和内存管理是跨语言编程中最重要的两个基础问题，目前已久初步可以工作了。&lt;/p&gt;

&lt;h2 id=&#34;go语言导出c静态库&#34;&gt;Go语言导出C静态库&lt;/h2&gt;

&lt;p&gt;Go语言提供了一个cgo的工具，用于Go语言和C语言交互。这是Go语言使用C语言的一个例子:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;package main

//#include &amp;lt;stdio.h&amp;gt;
import &amp;quot;C&amp;quot;

func main() {
    C.puts(C.CString(&amp;quot;abc&amp;quot;))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;既然要交互，自然会涉及到C语言回调Go语言函数的情形。为此，cgo提供了一个&lt;code&gt;export&lt;/code&gt;注释命令，
用于生成Go语言函数对应的C语言函数:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;//export MyStrDup
func MyStrDup(s *C.char) *C.char {
    return C.strdup(s)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;MyStrDup&lt;/code&gt;指定的名字必须和Go函数名字一致，函数的参数最后是C语言支持的类型。&lt;/p&gt;

&lt;p&gt;现在，我们就得到了用Go语言实现的&lt;code&gt;MyStrDup&lt;/code&gt;函数，使用方法和前面的C语言实现的&lt;code&gt;MyStrDup&lt;/code&gt;是一样的。&lt;/p&gt;

&lt;p&gt;和引用C语言函数库遇到的问题一样，我们如何在工程中引用这些C代码或Go代码实现的函数呢？&lt;/p&gt;

&lt;p&gt;答案还是来自C语言：将代码构建为C静态库或者C动态库，然后将静态库或动态库导入Swift工程。&lt;/p&gt;

&lt;p&gt;但是，对于iOS来说，构建C静态库或者C动态库的过程要麻烦（使用xcode也只是隐藏了构建的具体步骤）。&lt;/p&gt;

&lt;p&gt;因为，iOS涉及到多种CPU架构：模拟器的x86、4s的32位arm、5s以后的64位arm，64位arm中还有不同当版本&amp;hellip;&lt;/p&gt;

&lt;p&gt;这是C静态库或者C动态库构建始终都要面对的问题。&lt;/p&gt;

&lt;h2 id=&#34;交叉构建的参数&#34;&gt;交叉构建的参数&lt;/h2&gt;

&lt;p&gt;Go1.6之后增加了构建C静态库的支持，交叉编译也非常简单，只需要设置好&lt;code&gt;GOARCH&lt;/code&gt;和&lt;code&gt;GOOS&lt;/code&gt;就行。&lt;/p&gt;

&lt;p&gt;因为，iOS的&lt;code&gt;GOOS&lt;/code&gt;只有&lt;code&gt;Darwin&lt;/code&gt;一种类型，我们只需要设置&lt;code&gt;GOARCH&lt;/code&gt;就可以了。&lt;/p&gt;

&lt;p&gt;要构建C静态库，我们需要将上面的&lt;code&gt;MyStrDup&lt;/code&gt;实现放到一个&lt;code&gt;main&lt;/code&gt;包中:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;package main

//#include &amp;lt;string.h&amp;gt;
import &amp;quot;C&amp;quot;

func main() {
    //
}

//export MyStrDup
func MyStrDup(s *C.char) *C.char {
    return C.strdup(s)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;main&lt;/code&gt;包中的&lt;code&gt;main&lt;/code&gt;函数不会被执行，但是&lt;code&gt;init&lt;/code&gt;函数依然有效。&lt;/p&gt;

&lt;p&gt;使用下面的命令就可以构建当前系统的c静态库：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;go build -buildmode=c-archive
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;要交叉编译iOS可用的c静态库，我们需要先设置&lt;code&gt;GOARCH&lt;/code&gt;，同时打开cgo特性（交叉编译时，cgo默认是关闭的）。&lt;/p&gt;

&lt;p&gt;下面是构建针对模拟器的x86/amd64类型的C静态库：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;export CGO_ENABLED=1
export GOARCH=amd64

go build -buildmode=c-archive -o libmystrdup_amd64.a
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;我们使用&lt;code&gt;-o&lt;/code&gt;参数指定了输出的静态库文件名。构建命令同时还会生成一个头文件（可能叫&lt;code&gt;libmystrdup_386.h&lt;/code&gt;），
我们没有用到这个头文件，直接删除掉就可以。&lt;/p&gt;

&lt;p&gt;下面是构建针对模拟器的x86/386类型的C静态库：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;export CGO_ENABLED=1
export GOARCH=386

go build -buildmode=c-archive -o libmystrdup_386.a
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在构建x86/386类型的C静态库时可能会有一些link错误，我们暂时先用以下方法回避。&lt;/p&gt;

&lt;p&gt;创建一个&lt;code&gt;patch_386.go&lt;/code&gt;文件：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Copyright 2016 &amp;lt;chaishushan{AT}gmail.com&amp;gt;. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// 针对iOS模拟器link时缺少的函数
// 属于临时解决方案

package main

/*
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;time.h&amp;gt;

size_t fwrite$UNIX2003(const void* a, size_t b, size_t c, FILE* d) {
    return fwrite(a, b, c, d);
}

char* strerror$UNIX2003(int errnum) {
    return strerror(errnum);
}

time_t mktime$UNIX2003(struct tm * a) {
    return mktime(a);
}
double strtod$UNIX2003(const char * a, char ** b) {
    return strtod(a, b);
}

int setenv$UNIX2003(const char* envname, const char* envval, int overwrite) {
    return setenv(envname, envval, overwrite);
}
int unsetenv$UNIX2003(const char* name) {
    return unsetenv(name);
}

*/
import &amp;quot;C&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;当然，还是会有一些警告出现，暂时忽略它们。&lt;/p&gt;

&lt;h2 id=&#34;构建多cpu类型的静态库&#34;&gt;构建多cpu类型的静态库&lt;/h2&gt;

&lt;p&gt;然后，将C静态库加入到ios的xcode工程文件就可以了。&lt;/p&gt;

&lt;p&gt;x86构建是比较简单的，因为我们可以默认使用本地的构建命令。
但是，如果要构建arm的静态库，则需要先配置好构建环境。&lt;/p&gt;

&lt;p&gt;我从Go代码中扣出了一个&lt;code&gt;clangwrap.sh&lt;/code&gt;脚本（好像是在&lt;code&gt;$GOROOT/misci/ios&lt;/code&gt;目录）:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh
# This uses the latest available iOS SDK, which is recommended.
# To select a specific SDK, run &#39;xcodebuild -showsdks&#39;
# to see the available SDKs and replace iphoneos with one of them.
SDK=iphoneos
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
export IPHONEOS_DEPLOYMENT_TARGET=7.0
# cmd/cgo doesn&#39;t support llvm-gcc-4.2, so we have to use clang.
CLANG=`xcrun --sdk $SDK --find clang`

if [ &amp;quot;$GOARCH&amp;quot; == &amp;quot;arm&amp;quot; ]; then
    CLANGARCH=&amp;quot;armv7&amp;quot;
elif [ &amp;quot;$GOARCH&amp;quot; == &amp;quot;arm64&amp;quot; ]; then
    CLANGARCH=&amp;quot;arm64&amp;quot;
else
    echo &amp;quot;unknown GOARCH=$GOARCH&amp;quot; &amp;gt;&amp;amp;2
    exit 1
fi

exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH &amp;quot;$@&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;里面比较重要的是&lt;code&gt;IPHONEOS_DEPLOYMENT_TARGET&lt;/code&gt;环境变量，这里意思是目标最低支持ios7.0系统。&lt;/p&gt;

&lt;p&gt;构建arm64环境的静态库：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;export CGO_ENABLED=1
export GOARCH=arm64
export CC=$PWD/clangwrap.sh
export CXX=$PWD/clangwrap.sh

go build -buildmode=c-archive -o libmystrdup_arm64.a
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;构建armv7环境的静态库：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;export CGO_ENABLED=1
export GOARCH=arm
export GOARM=7
export CC=$PWD/clangwrap.sh
export CXX=$PWD/clangwrap.sh

go build -buildmode=c-archive -o libmystrdup_armv7.a
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后我们用&lt;code&gt;lipo&lt;/code&gt;命令将以上这些不同的静态库打包到一个静态库中：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;lipo libmystrdup_386.a libmystrdup_adm64.a libmystrdup_arm64.a libmystrdup_armv7.a -create -output libmystrdup.a
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这样的话，只要引入一个静态库就可以支持不同cpu类型的目标了。&lt;/p&gt;

&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;

&lt;p&gt;毛主席教导我们：要在战争中学习战争。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://appsto.re/cn/QH8ocb.i&#34;&gt;野鸡医院&lt;/a&gt;&lt;/strong&gt; 这个app是作者第一个iOS应用，这篇教程也是在iOS开发过程逐步学习总结的结果。&lt;/p&gt;

&lt;p&gt;完整的例子：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppStore安装: &lt;a href=&#34;https://appsto.re/cn/QH8ocb.i&#34;&gt;https://appsto.re/cn/QH8ocb.i&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Swift工程: &lt;a href=&#34;https://github.com/chai2010/ptyy/tree/master/ios-app/yjyy-swift&#34;&gt;https://github.com/chai2010/ptyy/tree/master/ios-app/yjyy-swift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Go静态库工程: &lt;a href=&#34;https://github.com/chai2010/ptyy/tree/master/cmd/yjyy&#34;&gt;https://github.com/chai2010/ptyy/tree/master/cmd/yjyy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;静态库构建脚本: &lt;a href=&#34;https://github.com/chai2010/ptyy/tree/master/ios-app/yjyy-swift/vendor/gopkg&#34;&gt;https://github.com/chai2010/ptyy/tree/master/ios-app/yjyy-swift/vendor/gopkg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;所有的代码均可以免费获取(BSD协议): &lt;a href=&#34;https://github.com/chai2010/ptyy&#34;&gt;https://github.com/chai2010/ptyy&lt;/a&gt;&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title>Bazel教程：构建iOS应用[翻译]</title>
      <link>https://chai2010.cn/post/bazel/bazel-ios-app/</link>
      <pubDate>Thu, 19 May 2016 00:00:00 +0000</pubDate>
      
      <guid>https://chai2010.cn/post/bazel/bazel-ios-app/</guid>
      
        <description>&lt;h1 id=&#34;bazel教程-构建ios应用&#34;&gt;Bazel教程：构建iOS应用&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;原文：&lt;a href=&#34;http://bazel.io/docs/tutorial/ios-app.html&#34;&gt;http://bazel.io/docs/tutorial/ios-app.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;译者：&lt;a href=&#34;http://github.com/chai2010&#34;&gt;chai2010&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;本教程包含以下步骤（Bazel新用户请先参考: &lt;a href=&#34;http://my.oschina.net/chai2010/blog/674110&#34;&gt;Bazel入门教程&lt;/a&gt;）：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;代码预览&lt;/li&gt;
&lt;li&gt;创建BUILD构建文件&lt;/li&gt;
&lt;li&gt;针对模拟器构建应用&lt;/li&gt;
&lt;li&gt;查看构建输出&lt;/li&gt;
&lt;li&gt;在模拟器环境运行／调试应用&lt;/li&gt;
&lt;li&gt;针对设备构建应用&lt;/li&gt;
&lt;li&gt;安装应用到设备&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;需要在 Mac OS X 环境，&lt;code&gt;WORKSPACE&lt;/code&gt; 不用配置。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&#34;查看源文件结构&#34;&gt;查看源文件结构&lt;/h2&gt;

&lt;p&gt;iOS应用源文件在&lt;code&gt;$WORKSPACE/ios-app/UrlGet&lt;/code&gt;目录。&lt;/p&gt;

&lt;p&gt;代码在这里：&lt;a href=&#34;https://github.com/bazelbuild/examples/tree/master/tutorial/ios-app/UrlGet&#34;&gt;https://github.com/bazelbuild/examples/tree/master/tutorial/ios-app/UrlGet&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;创建build文件&#34;&gt;创建BUILD文件&lt;/h2&gt;

&lt;p&gt;在命令行用vi创建并编辑BUILD文件（其它编辑器也可以）：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ vi $WORKSPACE/ios-app/BUILD
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;添加一个-objc-library-规则&#34;&gt;添加一个&lt;code&gt;objc_library&lt;/code&gt;规则&lt;/h2&gt;

&lt;p&gt;Bazel针对构建iOS应用提供了诸多规则命令。在这里，我们首先使用
&lt;a href=&#34;http://bazel.io/docs/be/objective-c.html#objc_library&#34;&gt;&lt;code&gt;objc_library&lt;/code&gt;&lt;/a&gt;
规则从源文件和Xib文件构建 &lt;a href=&#34;https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/Introduction.html&#34;&gt;静态库&lt;/a&gt;。
（这个只是最小的规则，此外还有&lt;code&gt;ios_application&lt;/code&gt;规则可以用于构建多架构的iOS应用。）&lt;/p&gt;

&lt;p&gt;BUILD的内容如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;objc_library(
    name = &amp;quot;UrlGetClasses&amp;quot;,
    srcs = [
        &amp;quot;UrlGet/AppDelegate.m&amp;quot;,
        &amp;quot;UrlGet/UrlGetViewController.m&amp;quot;,
    ],
    hdrs = glob([&amp;quot;UrlGet/*.h&amp;quot;]),
    xibs = [&amp;quot;UrlGet/UrlGetViewController.xib&amp;quot;],
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;规则对应的目标名字是&lt;code&gt;UrlGetClasses&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&#34;添加-objc-binary-规则&#34;&gt;添加&lt;code&gt;objc_binary&lt;/code&gt;规则&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;http://bazel.io/docs/be/objective-c.html#objc_binary&#34;&gt;&lt;code&gt;objc_binary&lt;/code&gt;&lt;/a&gt; 创建一个
bundled应用中的二进制可执行程序。&lt;/p&gt;

&lt;p&gt;BUILD文件添加如下内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;objc_binary(
    name = &amp;quot;ios-app-binary&amp;quot;,
    srcs = [
        &amp;quot;UrlGet/main.m&amp;quot;,
    ],
    deps = [
        &amp;quot;:UrlGetClasses&amp;quot;,
    ],
)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中&lt;code&gt;deps&lt;/code&gt;属性引用了前面的&lt;code&gt;UrlGetClasses&lt;/code&gt;静态库。&lt;/p&gt;

&lt;h2 id=&#34;添加-ios-application-规则&#34;&gt;添加&lt;code&gt;ios_application&lt;/code&gt;规则&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://chai2010.cn/docs/be/objective-c.html#ios_application&#34;&gt;&lt;code&gt;ios_application&lt;/code&gt;&lt;/a&gt; 规则用于创建&lt;code&gt;.ipa&lt;/code&gt;打包应用，
同时生成Xcode过程文件。&lt;/p&gt;

&lt;p&gt;BUILD文件添加如下内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;ios_application(
    name = &amp;quot;ios-app&amp;quot;,
    binary = &amp;quot;:ios-app-binary&amp;quot;,
    infoplist = &amp;quot;UrlGet/UrlGet-Info.plist&amp;quot;,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;完整的BUILD文件在这里：&lt;a href=&#34;https://github.com/bazelbuild/examples/blob/master/tutorial/ios-app/BUILD&#34;&gt;https://github.com/bazelbuild/examples/blob/master/tutorial/ios-app/BUILD&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;构建模拟器环境的应用&#34;&gt;构建模拟器环境的应用&lt;/h2&gt;

&lt;p&gt;命令行环境，确保当前目录对应Bazel的workspace：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ cd $WORKSPACE
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;输入以下命令构建应用：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ bazel build //ios-app:ios-app
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Bazel将启动构建工作。当构建完成时，输出类似下面的信息：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;INFO: Found 1 target...
Target //ios-app:ios-app up-to-date:
  bazel-bin/ios-app/ios-app.ipa
  bazel-bin/ios-app/ios-app.xcodeproj/project.pbxproj
INFO: Elapsed time: 3.765s, Critical Path: 3.44s
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;查找构建的输出&#34;&gt;查找构建的输出&lt;/h2&gt;

&lt;p&gt;输出的&lt;code&gt;.ipa&lt;/code&gt;和其它文件在&lt;code&gt;$WORKSPACE/bazel-bin/ios-app&lt;/code&gt;目录。&lt;/p&gt;

&lt;h2 id=&#34;模拟器环境运行-调试应用&#34;&gt;模拟器环境运行／调试应用&lt;/h2&gt;

&lt;p&gt;现在可以从Xcode环境的模拟器来运行应用。先打开&lt;code&gt;$WORKSPACE/bazel-bin/ios-app/ios-app.xcodeproj&lt;/code&gt;工程文件，
然后选择相应版本的iOS模拟器，然后点击 &lt;strong&gt;Run&lt;/strong&gt; 按钮运行。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; 如果要Xcode工程中的任何信息发生变化（比如删除文件或添加／改变依赖），必须使用Bazel重新生成Xcode工程文件。&lt;/p&gt;

&lt;h2 id=&#34;针对设备构建应用&#34;&gt;针对设备构建应用&lt;/h2&gt;

&lt;p&gt;针对设备构建应用，需要设置bazel以找到目标对应设备的provisioning profile配置文件。
根据以下步骤设置：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;打开网页 &lt;a href=&#34;https://developer.apple.com/account/ios/profile/profileList.action&#34;&gt;Apple Profiles&lt;/a&gt;
  下载设备对应的provisioning profile配置文件。
  如果又疑问，请参考 &lt;a href=&#34;https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingProfiles/MaintainingProfiles.html&#34;&gt;Apple&amp;rsquo;s documentation&lt;/a&gt;。&lt;/li&gt;
&lt;li&gt;将profile配置文件放到&lt;code&gt;$WORKSPACE/tools/objc&lt;/code&gt;目录。&lt;/li&gt;
&lt;li&gt;可选操作 － 可以在&lt;code&gt;.gitignore&lt;/code&gt;中忽略配置文件。&lt;/li&gt;

&lt;li&gt;&lt;p&gt;编辑 &lt;code&gt;$WORKSPACE/tools/objc/BUILD&lt;/code&gt; 文件，添加：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;  filegroup(
      name = &amp;quot;default_provisioning_profile&amp;quot;,
      srcs = [&amp;quot;&amp;lt;NAME OF YOUR PROFILE&amp;gt;.mobileprovision&amp;quot;],
  )
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;现在可以构建针对设备的应用了：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ bazel build //ios-app:ios-app --ios_multi_cpus=armv7,arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;上面的命令将构建针对多个类型的设备应用。如果只需要构建真的特定类型的应用，
可以指定一个特定的设备架构体系结构。&lt;/p&gt;

&lt;p&gt;如果需要选择一个特定版本的Xcode或特定版本的SDK，可以通过&lt;code&gt;--xcode_version=7.2 --ios_sdk_version=9.2&lt;/code&gt;指定。
要确保选定版本的SDK对应的Xcode已经安装到本机。&lt;/p&gt;

&lt;p&gt;如果需要指定一个能够运行的最小iOS版本，可以通过&lt;code&gt;--ios_minimum_os=7.0&lt;/code&gt;指定。&lt;/p&gt;

&lt;h2 id=&#34;安装应用到设备上&#34;&gt;安装应用到设备上&lt;/h2&gt;

&lt;p&gt;安装应用到设备最简单的方法是打开Xcode，然后点击&lt;code&gt;Windows &amp;gt; Devices&lt;/code&gt;菜单。
从左边列表选择相应的设备，点击 &amp;ldquo;+&amp;rdquo; 按钮并选择生成的 &lt;code&gt;.ipa&lt;/code&gt; 文件。&lt;/p&gt;

&lt;p&gt;如果程序没有运行，请检查设备和provisioning profile配置是否匹配。
点击&lt;code&gt;Devices&lt;/code&gt;下面的&lt;code&gt;View Device Logs&lt;/code&gt;按钮，可以查看到相关的错误信息。&lt;/p&gt;</description>
      
    </item>
    
  </channel>
</rss>