0%

有的时候我们需要针对特定的机型或者系统版本做一些特殊的处理,使得我们的程序能够正常的运行,这时就要去判断设备型号、系统版本了,获取这些信息本身并没有什么技术含量,只是比较零碎,因此为了查阅方便,整理了一份代码出来,用的时候直接copy即可。

设备信息

使用 uname 方法可以获取设备的硬件信息,其中就包括型号,我们可以根据型号具体的判断一个设备,比如 iPhone5s 的型号是 ‘iPhone6,2’;

使用的时候需要导入头文件: #import <sys/utsname.h>

1
2
3
4
5
struct utsname systemInfo;

uname(&systemInfo);

NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSASCIIStringEncoding];

这样获取的型号,不是我们平时叫的设备名称,所以一般都需要一个对应关系,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
- (NSString *)deviceType {

struct utsname systemInfo;

uname(&systemInfo);

NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSASCIIStringEncoding];

if ([platform isEqualToString:@"iPhone1,1"]) return @"iPhone 2G";

if ([platform isEqualToString:@"iPhone1,2"]) return @"iPhone 3G";

if ([platform isEqualToString:@"iPhone2,1"]) return @"iPhone 3GS";

if ([platform isEqualToString:@"iPhone3,1"]) return @"iPhone 4";

if ([platform isEqualToString:@"iPhone3,2"]) return @"iPhone 4";

if ([platform isEqualToString:@"iPhone3,3"]) return @"iPhone 4";

if ([platform isEqualToString:@"iPhone4,1"]) return @"iPhone 4S";

if ([platform isEqualToString:@"iPhone5,1"]) return @"iPhone 5";

if ([platform isEqualToString:@"iPhone5,2"]) return @"iPhone 5";

if ([platform isEqualToString:@"iPhone5,3"]) return @"iPhone 5c";

if ([platform isEqualToString:@"iPhone5,4"]) return @"iPhone 5c";

if ([platform isEqualToString:@"iPhone6,1"]) return @"iPhone 5s";

if ([platform isEqualToString:@"iPhone6,2"]) return @"iPhone 5s";

if ([platform isEqualToString:@"iPhone7,1"]) return @"iPhone 6 Plus";

if ([platform isEqualToString:@"iPhone7,2"]) return @"iPhone 6";

if ([platform isEqualToString:@"iPhone8,1"]) return @"iPhone 6s";

if ([platform isEqualToString:@"iPhone8,2"]) return @"iPhone 6s Plus";

if ([platform isEqualToString:@"iPhone8,4"]) return @"iPhone SE";

if ([platform isEqualToString:@"iPhone9,1"]) return @"iPhone 7";

if ([platform isEqualToString:@"iPhone9,2"]) return @"iPhone 7 Plus";

if ([platform isEqualToString:@"iPhone9,3"]) return @"iPhone 7";

if ([platform isEqualToString:@"iPhone9,4"]) return @"iPhone 7 Plus";

if ([platform isEqualToString:@"iPhone10,1"]) return @"iPhone 8";

if ([platform isEqualToString:@"iPhone10,2"]) return @"iPhone 8 Plus";

if ([platform isEqualToString:@"iPhone10,3"]) return @"iPhone X";

if ([platform isEqualToString:@"iPhone10,4"]) return @"iPhone 8";

if ([platform isEqualToString:@"iPhone10,5"]) return @"iPhone 8 Plus";

if ([platform isEqualToString:@"iPhone10,6"]) return @"iPhone X";

if ([platform isEqualToString:@"iPod1,1"]) return @"iPod Touch 1G";

if ([platform isEqualToString:@"iPod2,1"]) return @"iPod Touch 2G";

if ([platform isEqualToString:@"iPod3,1"]) return @"iPod Touch 3G";

if ([platform isEqualToString:@"iPod4,1"]) return @"iPod Touch 4G";

if ([platform isEqualToString:@"iPod5,1"]) return @"iPod Touch 5G";

if ([platform isEqualToString:@"iPad1,1"]) return @"iPad 1G";

if ([platform isEqualToString:@"iPad2,1"]) return @"iPad 2";

if ([platform isEqualToString:@"iPad2,2"]) return @"iPad 2";

if ([platform isEqualToString:@"iPad2,3"]) return @"iPad 2";

if ([platform isEqualToString:@"iPad2,4"]) return @"iPad 2";

if ([platform isEqualToString:@"iPad2,5"]) return @"iPad Mini 1G";

if ([platform isEqualToString:@"iPad2,6"]) return @"iPad Mini 1G";

if ([platform isEqualToString:@"iPad2,7"]) return @"iPad Mini 1G";

if ([platform isEqualToString:@"iPad3,1"]) return @"iPad 3";

if ([platform isEqualToString:@"iPad3,2"]) return @"iPad 3";

if ([platform isEqualToString:@"iPad3,3"]) return @"iPad 3";

if ([platform isEqualToString:@"iPad3,4"]) return @"iPad 4";

if ([platform isEqualToString:@"iPad3,5"]) return @"iPad 4";

if ([platform isEqualToString:@"iPad3,6"]) return @"iPad 4";

if ([platform isEqualToString:@"iPad4,1"]) return @"iPad Air";

if ([platform isEqualToString:@"iPad4,2"]) return @"iPad Air";

if ([platform isEqualToString:@"iPad4,3"]) return @"iPad Air";

if ([platform isEqualToString:@"iPad4,4"]) return @"iPad Mini 2G";

if ([platform isEqualToString:@"iPad4,5"]) return @"iPad Mini 2G";

if ([platform isEqualToString:@"iPad4,6"]) return @"iPad Mini 2G";

if ([platform isEqualToString:@"iPad4,7"]) return @"iPad Mini 3";

if ([platform isEqualToString:@"iPad4,8"]) return @"iPad Mini 3";

if ([platform isEqualToString:@"iPad4,9"]) return @"iPad Mini 3";

if ([platform isEqualToString:@"iPad5,1"]) return @"iPad Mini 4 (WiFi)";

if ([platform isEqualToString:@"iPad5,2"]) return @"iPad Mini 4 (LTE)";

if ([platform isEqualToString:@"iPad5,3"]) return @"iPad Air 2";

if ([platform isEqualToString:@"iPad5,4"]) return @"iPad Air 2";

if ([platform isEqualToString:@"iPad6,3"]) return @"iPad Pro 9.7";

if ([platform isEqualToString:@"iPad6,4"]) return @"iPad Pro 9.7";

if ([platform isEqualToString:@"iPad6,7"]) return @"iPad Pro 12.9";

if ([platform isEqualToString:@"iPad6,8"]) return @"iPad Pro 12.9";

if ([platform isEqualToString:@"iPad6,11"]) return @"iPad 5 (WiFi)";

if ([platform isEqualToString:@"iPad6,12"]) return @"iPad 5 (Cellular)";

if ([platform isEqualToString:@"iPad7,1"]) return @"iPad Pro 12.9 inch 2nd gen (WiFi)";

if ([platform isEqualToString:@"iPad7,2"]) return @"iPad Pro 12.9 inch 2nd gen (Cellular)";

if ([platform isEqualToString:@"iPad7,3"]) return @"iPad Pro 10.5 inch (WiFi)";

if ([platform isEqualToString:@"iPad7,4"]) return @"iPad Pro 10.5 inch (Cellular)";

if ([platform isEqualToString:@"AppleTV2,1"]) return @"Apple TV 2";

if ([platform isEqualToString:@"AppleTV3,1"]) return @"Apple TV 3";

if ([platform isEqualToString:@"AppleTV3,2"]) return @"Apple TV 3";

if ([platform isEqualToString:@"AppleTV5,3"]) return @"Apple TV 4";

if ([platform isEqualToString:@"i386"]) return @"iPhone Simulator";

if ([platform isEqualToString:@"x86_64"]) return @"iPhone Simulator";

return @"unKnown";
}

UIDevice 获取设备相关信息

  • 系统版本号
1
2
// 10.3.2
[[UIDevice currentDevice]systemVersion]
  • 系统名称
1
2
// iOS
[[UIDevice currentDevice] systemName]
  • 电池电量
1
2
//模拟器得到的是 -1
[[UIDevicecurrentDevice]batteryLevel]
  • 厂商唯一串号
1
2
3
//226072EA-5C4C-43F9-9E66-6E8ACE31DE49

[[[UIDevice currentDevice] identifierForVendor]UUIDString]
  • 用户名
1
2
///Matt Reach's iPhone
[[UIDevice currentDevice] name]

infoDictionary

App 的版本,应用名称等都记录在 info.plist 里,可以这样获取:

1
2
3
4
5
6
7
8
9
10
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];

// 应用装到设备上之后,显示的名称
[infoDictionary objectForKey:@"CFBundleDisplayName"]

// 应用的版本号 比如:6.8.3
[infoDictionary objectForKey:@"CFBundleShortVersionString"];

// 应用的build号 比如:2778
NSString *appCurVersionNum = [infoDictionary objectForKey:kCFBundleVersionKey];

其实这个里面信息蛮多的,其他的不再一一列举了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
{
BuildMachineOSBuild = 16A323;
CFBundleDevelopmentRegion = "zh_CN";
CFBundleDisplayName = "\U5343\U5e06-SDK";
CFBundleExecutable = SohuLiveDemo;
CFBundleIcons = {
CFBundlePrimaryIcon = {
CFBundleIconFiles = (
AppIcon29x29,
AppIcon40x40,
AppIcon57x57,
AppIcon60x60
);
};
};
CFBundleIdentifier = "com.sohu.live.demo";
CFBundleInfoDictionaryVersion = "6.0";
CFBundleName = SohuLiveDemo;
CFBundleNumericVersion = 0;
CFBundlePackageType = APPL;
CFBundleShortVersionString = "6.8.3";
CFBundleSignature = "????";
CFBundleSupportedPlatforms = (
iPhoneSimulator
);
CFBundleVersion = 1598;
DTCompiler = "com.apple.compilers.llvm.clang.1_0";
DTPlatformBuild = "";
DTPlatformName = iphonesimulator;
DTPlatformVersion = "10.2";
DTSDKBuild = 14C89;
DTSDKName = "iphonesimulator10.2";
DTXcode = 0821;
DTXcodeBuild = 8C1002;
LSApplicationCategoryType = "";
LSApplicationQueriesSchemes = (
wechat,
weixin,
alipay,
qianfan56,
qfA31D406E33689950,
mqq
);
LSRequiresIPhoneOS = 1;
MinimumOSVersion = "7.0";
NSAppTransportSecurity = {
NSAllowsArbitraryLoads = 1;
};
NSCameraUsageDescription = "\U7231\U4e0a\U76f4\U64ad";
NSMicrophoneUsageDescription = "\U8bf7\U5141\U8bb8\U6211\U4f7f\U7528\U9ea6\U514b\U98ce";
NSPhotoLibraryUsageDescription = "\U5343\U5e06SDK\U60f3\U4f7f\U7528\U60a8\U7684\U76f8\U518c";
UIAppFonts = (
"MFLiHei-Regular.ttf"
);
UIDeviceFamily = (
1
);
UILaunchImages = (
{
UILaunchImageMinimumOSVersion = "8.0";
UILaunchImageName = "Brand Assets-800-Portrait-736h";
UILaunchImageOrientation = Portrait;
UILaunchImageSize = "{414, 736}";
},
{
UILaunchImageMinimumOSVersion = "8.0";
UILaunchImageName = "Brand Assets-800-667h";
UILaunchImageOrientation = Portrait;
UILaunchImageSize = "{375, 667}";
},
{
UILaunchImageMinimumOSVersion = "7.0";
UILaunchImageName = "Brand Assets-700";
UILaunchImageOrientation = Portrait;
UILaunchImageSize = "{320, 480}";
},
{
UILaunchImageMinimumOSVersion = "7.0";
UILaunchImageName = "Brand Assets-700-568h";
UILaunchImageOrientation = Portrait;
UILaunchImageSize = "{320, 568}";
}
);
UILaunchStoryboardName = "Launch Screen";
UIRequiredDeviceCapabilities = (
armv7
);
UIStatusBarStyle = UIStatusBarStyleDefault;
UISupportedInterfaceOrientations = (
UIInterfaceOrientationPortrait,
UIInterfaceOrientationLandscapeLeft,
UIInterfaceOrientationLandscapeRight
);
UIViewControllerBasedStatusBarAppearance = 0;
}

时光荏苒,来搜狐已经 2 年整了,最近挺忙的,以至于今天来公司加班,查看邮件后才发现今天是入职两周年的纪念日。

2 年 2 个城市 2 个团队。。。

不忘初心,勇往直前!

Bye, 2017 MacBook Pro

先看下 2017 新款 MacBook Pro 长啥样吧:

两个月前,我司第二季度申请的电脑到了,我组有几台 2017 款的 MacBook Pro,带 Multi-Touch Bar 的,跟现在使用的 2015 款比起来纤薄了许多,也更加轻盈,性能不用说,更加强大。于是心里痒痒,忍不住换了下。

拿到手之后,感觉挺别扭的,因为我无法连接手机调试,充电;只好先买了一个 type-c 转 USB 的转接头;

我习惯了使用双显示器工作,所以又买了一个 type-c 转 HDMI 的转接头,这玩意可不便宜,花了¥99块大洋。

“键盘采用第二代蝶式结构,按键稳定性是传统剪刀式结构的 4 倍,并且手感更舒适,响应更灵敏。”

这段话来自于官网,不过我并没有感觉到更舒适,反而觉得键盘太难受了!!!键程太短了,按下没一点感觉,回弹也很无力,总结起来就是毫无手感。。。
为了找到手感就买了一个机械键盘+鼠标,其实我之前一直没有鼠标的,感觉鼠标会拖慢我的效率,触控板挺好用的,因为用了外接键盘,手够不着触控板了,只好用迁就使用鼠标了。

“宽大的 Force Touch 触控板,让你的手指有充分的空间施展触控手势和进行点按操作。”

新的 MBP 配备了更加大的触控板,但由于我使用了外接键盘,导致这么大一块板子给白白浪费了!并没有派上用场。

“它更配备了 Multi-Touch Bar,一个内置于键盘的玻璃面多点触控条,让你能在需要时快速取用各种工具。”

至于这个 Bar 的话,几乎没碰过,就是刚到手的时候,尝尝鲜玩玩而已,后来配了外接键盘后,离我就更加远了,我连触控板都几乎不去碰了,就更别说这个Bar了,当初想尝试这个新款,当然也有这个 Bar 的原因,因为这个 Bar 是可编程的,想着可以没事了搞个程序玩下。

跟工作性质也有关系,几乎每天都要开会,开会时一般会拿上电脑,这时如果想继续调试就还有带上转接头,或者手机没电了,要充电也是如此,这样就感觉很不方便。

直到前两天,公司更新了PC,我的老DELL机器也一起更新了,并且我还选择了配备显示器(之前用的是同事的),领取新的机器和显示器后就把同事的显示器归还了,没想到的是这个显示器也是个奇葩,可以插传统的 VGA,还可以插一个我之前没见过的 DELL DP,尼玛啊,我哪有这个接口啊,公司配备的转接头是 HDMI 转 VGA 的,所以我就只能看,不能用了,网上查了下 Type C 转 DELL DP 的转接头需要 ¥210 个大洋。我只想说真尼玛折腾啊,各大公司的接口不统一,才会有这么多的转接头出现。

我觉得苹果就是为了追求新一代 MBP 的纤薄,才狠下心去掉了自家的 DP 接口和 USB 接口,选择拥抱了 type-c,并且阉割了一半键程的键盘!

至于更加惊人的性能,更好的显示效果,更快的存储速度,续航能力等,这些都没有那么的明显,因为目前 2015 款的配置已经完全够用了!就我们编程而言,你体会不到这些变化。

新亏组里还有台 2015 款的 MBP,经过周转,我又换了回去;兜兜转转,一阵新鲜感过后,还是我去年申请的 MBP 用着最顺手!新款的 MBP,至于没有给我带来更多的欢乐,反而是更多的不便利,因此我觉得一味的最求轻薄,牺牲实际使用体验,反而不好,至少用在写代码的体验很是糟糕。

Hello, My loved 2015 MacBook Pro

正常情况下,我们的文档只能存储到沙盒里,在写业务逻辑时经常需要判断沙盒里某个文件是否存在,或者文件夹不存在创建文件夹等操作,因此写篇文章记录下如何获取沙盒路径,如何使用文件管理类创建目录等常用操作。

沙盒路径

什么是沙盒?为了保证App的正常运行,不受到其他App的干扰,或者病毒的侵害,苹果为每个App设定了自己独立的目录,对于开发者而言,你只能访问这个目录下的文件或者子目录,这个目录是你App的根目录,这就是沙盒机制,大大减少了流氓软件和病毒。

关于沙盒设计可看官方介绍 App Sandbox Design Guide

沙盒内重要目录

获取沙盒根目录,直接使用这个 C 方法就OK了:

NSHomeDirectory()

沙盒里面有几个文件夹还记得吗?有 3 个,分别是:

  • Documents : 一般重要的文件会放这里,不过默认情况下,备份App时会备份这里面的数据;这个目录也可以设置共享,就可以在itunes里向App导入数据了

NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)

注意:NSSearchPathForDirectoriesInDomains 函数返回的是个数组,取一个就行了。

  • Library/Caches : 一般会将图片这种没那么重要的资源缓存到这里

NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)

  • tmp : 就是个临时目录,中间临时文件,存这里面,系统可能会删这里的文件,最好我们自己清理临时文件,减少沙盒的体积

NSTemporaryDirectory()

这三个都在App沙盒根目录里,因此也可以通过 NSHomeDirectory() 拼接出来。

管理文件和目录

iOS 里使用 NSFileManager 类管理文件(夹),这是一个单利类,但你仍旧可以创建新的实例,自己使用。下面总结下 NSFileManager 的常用方法:

  • 创建文件
1
2
3
4
5
6
7
8
NSFileManager *fileManager = [NSFileManager defaultManager];
///文件路径,文件内容,相关属性
BOOL succ = [fileManager createFileAtPath:path contents:nil attributes:nil];
if (succ) {
NSLog(@"创建成功");
} else {
NSLog(@"创建失败");
}
  • 直接写入文件

NSString,NSData,NSArray,NSDictionary等常用类均提供了直接写入文件的方法;这里以 NSString 举例说明;由于这个方法的存在,所以上面的创建文件方法用的不是很多;

1
2
3
4
5
6
7
8
NSString *iOSPath = [documentsPath stringByAppendingPathComponent:@"iOS.txt"];
NSString *text = @"测试直接写入";
BOOL succ = [text writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
if (succ) {
NSLog(@"写入成功");
} else {
succ(@"写入失败");
}
  • 从文件读取
1
2
3
4
- (void)readFileContent{
NSString *text = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSLog(@"text: %@", text);
}
  • 创建文件夹
1
2
3
4
5
6
7
8
NSFileManager *fileManager = [NSFileManager defaultManager];
///第二个参数,一般传YES,意思是创建中间目录;
BOOL succ = [fileManager createDirectoryAtPath:@"/a/b/c" withIntermediateDirectories:YES attributes:nil error:nil];
if (succ) {
NSLog(@"创建成功");
} else {
NSLog(@"创建失败");
}
  • 删除文件,文件夹

最好在异步线程里删除文件

1
2
3
4
5
6
7
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL succ = [fileManager removeItemAtPath:path error:nil];
if (succ) {
NSLog(@"删除成功");
}else{
NSLog(@"删除失败");
}
  • 文件是否存在
1
2
3
4
5
6
BOOL succ = [[NSFileManager defaultManager]fileExistsAtPath:savePath];
if (succ) {
NSLog(@"文件存在");
}else{
NSLog(@"文件不存在");
}
  • 文件夹是否存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
NSString *basePath = [cachePath stringByAppendingPathComponent:@"telittleVideo"];

BOOL directory = NO;
///注意,文件夹存在时,这个方法返回的也是YES哦,所以要继续判断 directory !
if ([[NSFileManager defaultManager]fileExistsAtPath:basePath isDirectory:&directory] && !directory) {
///如果不是文件夹,那么说明存在了同名文件了,删掉吧
[[NSFileManager defaultManager]removeItemAtPath:basePath error:nil];
}

///文件夹不存在,要创建
if(!directory){
NSError *err = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:&err];
NSLog(@"%@",err);
}

通过前几篇博客的介绍,已经知道了如何去创建自己的 pods 库,前提是公开源码的,但有时候你可能不想或者不能把源码提供出去,那还能继续使用 cocoapods 管理库和依赖吗?答案是肯定的,接下来就来介绍下 cocoapods 如何管理 frameworks !

无论是源码还是库的形式,对于 pod 而言,区别就是 podspec 文件,比如我做了几个管理源码的 pod 库,现在我只需要修改下就可以了,以 SCNetworkKit 举例说明:

1
2
s.source       = { :git => "https://github.com/debugly/SCNetworkKit.git", :tag => "#{s.version}" }
s.source_files = "SCNetworkKit/Classes/**/*.{h,m}"

修改为

1
2
s.source       = { :http => "http://10.7.36.192/Pods_Static/1.0.55/SCNetworkKit.framework.zip" }
s.vendored_frameworks = "SCNetworkKit.framework"

source 支持四种类型:

  • :git => :tag, :branch, :commit, :submodules
  • :svn => :folder, :tag, :revision
  • :hg => :revision
  • :http => :flatten, :type, :sha256, :sha1, :headers

这里使用 http 是因为实际项目中更为方便,我们会把库文件放到服务器上,通过不通的文件夹去管理版本,下载也比较快速。

剩下的验证和发布步骤就和创建管理源码的 pods 库一样了,如果你没有创建过 pods 库的话,出门右转: 使用 pod lib 创建 CocoaPods 库

vendored_frameworks 说明

1、从名字上就可以知道,这个配置支持多个 framework,配置时只需要使用逗号分隔即可;

2、可以支持路径,比如 s.vendored_frameworks = “Release/SCNetworkKit.framework” 那么 SCNetworkKit.framework 必须位于相对于 spec 文件的 Release 目录下,发布到服务器上的压缩文件,解压后也必须能够解压出 Release 文件夹,否则会验证失败!

vendored_libraries 说明

cocoapods 不仅可以管理 frameworks ,还可以管理 .a 静态库,只需要把 vendored_frameworks 换成 vendored_libraries 即可!

resources 说明

前面的博客里没提到 resources 管理,这里顺便提下,假设我的 SohuGameSDK.framework 里包含的有 SohuGame.xcassets 文件夹,podspec 配置如下:

1
s.resources = "SohuGameSDK.framework/SohuGame.xcassets"

我觉得很赞的是,不用将资源手动添加到主工程里去,pods会自动通过脚本帮你完成这件事,这个是新版 pods 才有的功能,最初是不支持的,大概是从 1.0 开始支持的!!

我在做 SDK 开发工作期间,并没有通过 cocoapods 管理,也没有提供 pods 库,原因大概是:

我需要去配合集成 SDK 的 App,有的 App 对于 cocoapods 依赖性很大,也经常更新,对于这个 App 来讲,其实可以支持下 pods库,但是有个 App 虽然使用了 cocoapods,但是好久都没更新过了,工程较复杂,他们不愿意使用这种方式集成,避免更新我的库时,搞乱了他们的工程依赖关系!所以都是手动替换的。

其实使用 cocoapods 实现这一过程也是可以的,举例说明(SDK 发布到内网 CDN服务器):

SDK 要更新包了,我需要:

  1. 将 SDK(也就是相关的 frameworks)上传到服务器
  2. 升级 podspec 版本号
  3. 将 podspec 推送到私有 cocospods

这些工作完全可以通过脚本完成,然后通过 jenkins 调用即可;大致的脚本流程如下:

1
2
3
4
5
6
build_sdk : 编译SDK工程
zip_frameworks : 压缩生成的 frameworks
scp_frameworks : 将 zip 包推到 cdn 服务器
generate_spec : 通过模板,生成目标 spec 文件,这里推荐使用 json 格式的spec,便于模板替换
push_spec : 将 spec 文件推送到私聊 pod 仓库
send_mail : 发送邮件给开发者

集成者的工作是:

  1. 升级 Podfile 里 SDK 的版本号
  2. 使用 pod update xx 把指定库更新下来
  3. 提交 pods 变动

本文更新时,我已经不再做 SDK 开发了,现在做 App 了,但是也不等于这套流程没用了,因为我可以把这套流程修改成 组件二进制化 流程。