iOS应用构建与部署小结
注:本文首发于我的个人博客:https://evilpan.com/2019/04/06/ios-basics/
上篇文章介绍了Objective-C的基本概念,本文就来接着看如何创建我们的第一个简单iOS应用,
本着简单可复现的方式,我们会以尽可能小的成本来构建并在真机运行iOS应用。 也就是说,
不用越狱, 也无需开发者账号。当然,一台iPhone手机还是需要的,为了方便编译最好还有macOS环境。
Xcode
iOS的应用必须要用Xcode来创建,步骤很简单:
- 下载并打开Xcode
- 选择ios -> Single View Application
- 填写项目名、开发组、包名(Identifier)
项目创建成功后,目录结构如下:
$ tree HelloWorld/
HelloWorld/
├── HelloWorld
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
└── HelloWorld.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ └── pan.xcuserdatad
│ └── UserInterfaceState.xcuserstate
└── xcuserdata
└── pan.xcuserdatad
├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
└── xcschemes
└── xcschememanagement.plist
可以看到项目下有两个文夹,分别是源代码文件HelloWorld
,以及工程文件HelloWorld.xcodeproj
。
作为示例,我们可以修改ViewController.m
文件,如下:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 创建控件
UILabel* label = [[UILabel alloc]init];
label.text = @"Hello World";
// 自适应大小
[label sizeToFit];
// 居中
label.center = self.view.center;
// 添加控件
[self.view addSubview :label];
}
@end
这样,一个Hello World小程序就完成了,左上角运行按钮,即可编译并在模拟器中运行,如下:
![imgSim.jpg][imgSim]
在源代码框下方Products
区域也能看到编译出的HelloWorld.app
。
是不是很简单?好我们今天的文章就这样结束了,... 才怪!
命令行编译
为了更好地了解编译过程,我们可以脱离Xcode IDE,在命令行编译该项目:
首先,在项目目录中查看Schemes:
$ xcodebuild -list -project HelloWorld.xcodeproj
Information about project "HelloWorld":
Targets:
HelloWorld
Build Configurations:
Debug
Release
If no build configuration is specified and -scheme is not passed then "Release" is used.
Schemes:
HelloWorld
然后,选择一个scheme进行编译,这里是HelloWorld:
$ xcodebuild -scheme HelloWorld build
note: Using new build system
note: Planning build
note: Using build description from disk
Build system information
error: Signing for "HelloWorld" requires a development team. Select a development team in the project editor. (in target 'HelloWorld')
** BUILD FAILED **
凹,编译失败了,签名出错,因为万恶的资本主义坏苹果要求必须要每年99$或者299$去购买
Apple Developer Program 会员资格才能对应用进行合法签名,从而发布并运行我们创建的app。
但是这里写的这个简单APP只需要在我自己的手机上运行,所以并不需要这一步,禁用签名进行编译即可:
$ xcodebuild -scheme HelloWorld build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
Build settings from command line:
CODE_SIGN_IDENTITY =
CODE_SIGNING_REQUIRED = NO
note: Using new build system
note: Planning build
note: Constructing build description
Build system information
warning: HelloWorld isn't code signed but requires entitlements. It is not possible to add entitlements to a binary without signing it. (in target 'HelloWorld')
...
Validate /Users/pan/Library/Developer/Xcode/DerivedData/HelloWorld-dnyjqrgxcjjobvfzytzhtzpmjlmx/Build/Products/Debug-iphoneos/HelloWorld.app (in target: HelloWorld)
...
Touch /Users/pan/Library/Developer/Xcode/DerivedData/HelloWorld-dnyjqrgxcjjobvfzytzhtzpmjlmx/Build/Products/Debug-iphoneos/HelloWorld.app (in target: HelloWorld)
...
** BUILD SUCCEEDED **
编译成功了!中间省略了很多输出信息,这里就不贴了。值得一提的是,生成的app并不是在当前项目目录下,
而是在$HOME/Library/Developer/Xcode/DerivedData/$PROJECT-xxxx/{...}/HelloWorld.app
中,
xxxx看起来是一段随机数。HelloWorld.app就是一个传统的苹果应用,其目录结构如下:
$ tree HelloWorld.app
HelloWorld.app
├── Base.lproj
│ ├── LaunchScreen.storyboardc
│ │ ├── 01J-lp-oVM-view-Ze5-6b-2t3.nib
│ │ ├── Info.plist
│ │ └── UIViewController-01J-lp-oVM.nib
│ └── Main.storyboardc
│ ├── BYZ-38-t0r-view-8bC-Xf-vdC.nib
│ ├── Info.plist
│ └── UIViewController-BYZ-38-t0r.nib
├── HelloWorld
├── Info.plist
└── PkgInfo
其中HelloWorld就是ARM64的Mach-O文件:
$ file HelloWorld.app/HelloWorld
HelloWorld.app/HelloWorld: Mach-O 64-bit executable arm64
模拟器
iOS模拟器除了可以在Xcode启动,也可以通过命令行进行管理,如:
xcrun simctl help
查看具体帮助:
$ xcrun simctl help install
Install an app on a device.
Usage: simctl install <device> <path>
例如,我们要想在模拟器中启动上节编译好的HelloWorld.app,可以用以下命令:
# 查看当前设备列表,选择一个设备UDID
xcrun simctl list devices
# 打开并启动设备
open -a Simulator --args -CurrentDeviceUDID $UDID
# 在启动的设备中安装我们的应用,注意需要app支持x86架构
xcrun simctl install booted /path/to/HelloWorld.app
关于simctl的更多使用示例可以参考这篇文章。
签名与ipa
上节说到我们可以不签名来编译APP,但对于真机而言,要想运行应用,签名是必须的。
在Xcode7以后,开发者可以只用自己的Apple ID来在自己的设备上运行iOS应用,设置如下:
![imgSign.jpg][imgSign]
这样就可以通过USB在物理机上运行iOS应用了,不过要注意的是第一次启动时会提示不可信的开发者,
需要到设置-通用
中进行信任。
什么是ipa
iOS应用与Android应用类似的一点是,最后安装到系统中的都是一个zip压缩包,对于Android而言后缀是apk,
而对于iOS而言则是ipa(iPhone Application Archive)。通常ipa会通过苹果加密(使用FairPlay DRM技术)。
所以一般我们想从手机上已经安装的应用还原出ipa需要先解密,也通常称为砸壳。
常见的解密方法有如下几种:
- Clutch- Fast iOS executable dumper
- dumpdecrypted - Dumps decrypted mach-o files from encrypted iPhone applications from memory to disk
- frida-ios-dump
当然这些都是需要越狱的,在非越狱的机器上可以通过iMazing提取,热门应用可以直接在第三方应用商店下载,
比如AppCake。
ipa打包
对于有源码的应用,我们可以使用Xcode进行打包,打包流程可以参考stackoverflow中的一个回答。
不过这需要有开发者账号。由于我们是自己使用,因此要找一种无需开发者账号的方法。
无需开发者账号的打包方式有很多,比如:
- How to create ipa in xcode 6 without Apple Developer account?
- Export an IPA From Xcode Without an Apple Developer Account
这里使用命令行方式进行打包(archive&export):
# archive
xcodebuild archive -project HelloWorld/HelloWorld.xcodeproj -scheme HelloWorld -configuration Debug -archivePath ./build/HelloWorld
# export
xcodebuild -exportArchive -archivePath ./build/HelloWorld.xcarchive -exportOptionsPlist exportOptions.plist -exportPath ./build
这样就在./build
目录下生成HelloWorld.ipa
包了。其中exportOptions.plist
如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>development</string>
</dict>
</plist>
详细exportOptions的key/value值可以通过xcodebuild -help
查看。
ipa安装
无需AppStore的ipa的安装方法有下面几种(欢迎补充):
- 使用Apple Configurator 2 工具(只支持MacOS)
- 使用Xcode安装
- 使用OTA部署方式安装
- 其他
使用Apple Configurator 2
Apple Configurator 2是苹果公司提供的一个部署和配置工具,可以直接从AppStore下载。
USB连接苹果手机后打开工具,图形界面操作,依次选择:
Add -> Apps -> Choose from my Mac
然后点击生成的ipa文件即可。不是很推荐这个工具,如果一定要用图形界面,还不如用下面的Xcode。
使用Xcode
同样是图形界面操作,USB连接手机后依次选择:
Window -> Devices and Simulators -> Devices
选择自己的手机后,点击+
添加或者直接把ipa文件拖拽进来即可。
OTA部署
OTA部署支持使用HTTPS的方式部署和分发你的ipa包,一个示例OTA链接地址如下:
itms-services://?action=download-manifest&url=https://example.com/ota.plist
itms-services
是苹果上的自定义协议,会根据action下载并处理目标plist文件,
ota.plist
内容如下:
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>
https://example.com/app.ipa
</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>com.evilpan.helloworld</string>
<key>bundle-version</key>
<string>1</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>一个有趣的APP</string>
</dict>
</dict>
</array>
</dict>
</plist>
解析后会从https://example.com/app.ipa
下载应用,用户点击确定即可安装。
这里注意不论是ota.plist还是app.ipa的地址都是强制要求为HTTPS的,
因此若想以这种形式安装,还必须要去注册一个合法的SSL证书,也可以用免费的。
由于AppStore审核很严格,很多私人用的或者不合规的iOS软件都是通过OTA部署的形式分发的,
并且在会在安装说明中指引用户去设置->通用->描述文件与设备管理
中手动点击信任该个人/企业开发者。
其他
除了上述方式,还有一些开源脚本可以帮助我们安装部署自己的应用,如ios-deploy,
只要连接USB输入以下命令即可安装:
$ ios-deploy -b HelloWorld.ipa
[....] Waiting for iOS device to be connected
------ Install phase ------
...
[ 65%] InstallingEmbeddedProfile
[ 70%] VerifyingApplication
[ 75%] CreatingContainer
[ 80%] InstallingApplication
[ 85%] PostflightingApplication
[ 90%] SandboxingApplication
[ 95%] GeneratingApplicationMap
[100%] Installed package HelloWorld.ipa
有点类似于Android的adb install
,相当方便。个人建议直接使用源码编译而不是npm安装。
后记
本文从开发者的角度,介绍了iOS应用创建、编译、打包、测试、部署等方面,
从零开始构建并运行我们的第一个iOS程序。 既介绍了模拟器的安装测试方式,
也介绍了物理机上的打包和部署过程。其中很多地方尽可能的使用命令行去运行,
这有利于后续自动化的操作,也有利于我们理解各个选项所使用到的参数作用。
为了降低工作量,我们特地在没有越狱以及没有开发者账号的情况下完成上述操作。
下一篇,我们将尝试从攻击者的角度,实际“破解”一个iOS应用,Stay Tuned!
参考链接
- iOS builds / ipa creation from the command line
- Setting up Frida Without Jailbreak on devices running iOS 12.1.4
- AppCake - Third party ipa download
- dumpdecrypted - Dumps decrypted mach-o files from encrypted iPhone applications from memory to disk
- Clutch- Fast iOS executable dumper
- frida-ios-dump
- insert_dylib
- Non-market App Distribution - Monaca Docs
imgSim: https://img2020.cnblogs.com/blog/676200/202003/676200-20200307215659162-1061114665.png
imgSign: https://img2020.cnblogs.com/blog/676200/202003/676200-20200307215715098-769151084.png
iOS应用构建与部署小结的更多相关文章
- Jenkins的Windows Slave分布式构建和部署
1.新建的Slave:系统管理-->管理节点-->新建节点 远程工作目录 即是 节点服务器 站点文件存放目录 在配置节点时 启动方法 配置的选项中的 Launch agent via Ja ...
- 用Ant实现Java项目的自动构建和部署
原文地址:http://tech.it168.com/j/2007-11-09/200711091344781.shtml 本文请勿转载! Ant是一个Apache基金会下的跨平台的构 ...
- 用Ant实现Java项目的自动构建和部署(转)
Ant是一个Apache基金会下的跨平台的构件工具,它可以实现项目的自动构建和部署等功能.在本文中,主要让读者熟悉怎样将Ant应用到Java项目中,让它简化构建和部署操作. 一. ...
- Ant构建和部署项目(转)
原文地址: http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html Ant是一个Apache基金会下的跨平台的构件工具,它可以实 ...
- 用Ant实现Java项目的自动构建和部署(转)
Ant是一个Apache基金会下的跨平台的构件工具,它可以实现项目的自动构建和部署等功能.在本文中,主要让读者熟悉怎样将Ant应用到Java项目中,让它简化构建和部署操作. 一. ...
- Ant构建与部署Java项目---入门
原文地址:http://tech.it168.com/j/2007-11-09/200711091344781.shtml Ant是一个Apache基金会下的跨平台的构件工具,它可以实现项目的自动构建 ...
- 用持续集成工具Travis进行构建和部署
用持续集成工具Travis进行构建和部署 用持续集成工具Travis进行构建和部署 摘要:本文简单说明了如何使用持续集成工具Travis进行构建和部署的过程. 1. 概述 持续集成(Continuou ...
- 边缘化搭建 DotNet Core 2.1 自动化构建和部署环境(上)
写在前面 写这篇文章的缘由是由于笔者的对新兴技术方向有所追求,但个人资产有限,只能容许购买一台阿里云低配1核2G服务器.服务器上搭建了 Centos7 & Docker & Jenki ...
- GitHub + circleCI 自动构建/自动部署 应用
GitHub + circleCI 自动构建/自动部署, 这里略过了单元测试,以部署 laravel 应用为例子 比起 gitlab + ansible + genkins 操作起来节省了很多硬件资源 ...
随机推荐
- Normal Probability Plots|outlier
6.4 Assessing Normality; Normal Probability Plots The normal probability plot is a graphical techniq ...
- python语法基础-基础-赋值与深浅拷贝
##################################### 预备知识一——python的变量及其存储 在详细的了解python中赋值.copy和deepcopy之前,我们还是要花一点时 ...
- Word Flow:创造吉尼斯世界纪录的触屏文本输入的全新体验——微软Windows Phone 8.1系统倾情巨献
Flow:创造吉尼斯世界纪录的触屏文本输入的全新体验--微软Windows Phone 8.1系统倾情巨献" title="Word Flow:创造吉尼斯世界纪录的触屏文本输入的全 ...
- HDU1166 敌兵布阵 [线段树模板]
题意:在序列中修改单点和查询区间和 #include<iostream> #include<cstdio> #include<cstring> #define ls ...
- JavaScript学习总结(一)基础部分
转自:http://segmentfault.com/a/1190000000652749 基本概念 javascript是一门解释型的语言,浏览器充当解释器. js执行引擎并不是一行一行的执行,而是 ...
- vyos的Xvlan配置方式
set interfaces bridge br0 address '172.12.12.10/24' //开启一个桥借口,用于xvlan的通信 set interfaces vxlan vxlan0 ...
- IDEA 中tomcat上面有个x 而且找不到配置tomcat的选项
在使用idea时候,准备启动服务器,tomcat突然上面有个xx 解决方式 在 File-settings-plugins 搜索tomcat 如果插件后面有 就重新取消之后再勾选,然后点应用就可以解决 ...
- 转:zabbix 2.0.6监控cisco交换机 2950 2960s 3560G
转自: http://blog.chinaunix.net/uid-24250828-id-3806551.html 想在zabbix 上监控交换机端口的流量,找了两天的模板,包括官方的和网友写的.在 ...
- spring参数拼装
-- 知道轮子是怎么造的 -- 自己试着造一造轮子 ,这样才可以更好地利用轮子,轮子的缺陷和优点才能明确. spring参数拼装,需要用到set函数,参考文档: http://coderec.cn/2 ...
- bzoj1432_[ZJOI2009]Function
题目描述 有n 个连续函数fi (x),其中1 ≤ i ≤ n.对于任何两个函数fi (x) 和fj (x),(i != j),恰好存在一个x 使得fi (x) = fj (x),并且存在无穷多的x ...