ios Using CocoaPods to Modularize a Big iOS App->使用CocoaPods来进行模块化开发
Selecting the right architecture for your mobile app is a pretty big deal. It will shape your daily workflow, frame the problems you face, and can be a huge asset or huge liability.
HubSpot's app is fully-featured. It's an analytics app, a social media app, an email app and a contacts management app (with more to come) all coexisting under one roof. As we set out to build this fairly complex app last summer, we knew we had to have an architecture that'd scale with it.
We actually build each sub-app as a fully complete standalone app, then use CocoaPods to integrate them into the main app.
In the screenshots below, you can see how each sub-app - Sources, Dashboard, Social Media, is actually both a standalone iPhone app as well as an app that can be brought into the menu of the main app.
This gives us a few huge advantages:
- Most critically, we're very easily able to ensure that the master branch of each sub-app is ready to ship, and can pull in specific versions of sub-apps in a snap.
- We spend a lot more time building and a lot less time merging. Each individual app's sandbox makes it very easy to iterate within the sub-apps and spend minimal time integrating with other apps. If you've worked on an iOS team of more than one, you've undoubtedly had gross .xcodeproj merges. While they are resolvable, they're a pain -- this lets us sidestep them almost completely.
- We are able to individually deploy each app if necessary -- this is amazing for doing usability testing on an individual app level. We could ship the app to our testers earlier before “glue” features like navigation were complete so we could get high quality, targeted feedback.
- Because user flows between sub-apps are only done with URL-based routes (more about this later), it means that routes are built-in and documented -- instead of searching through a pile of UIViewControllers for the right way to instantiate a particular view, there’s a well-defined route. This is useful when building meta-functionality like walkthrough tutorials or new push notifications.
This architecture has been a huge timesaver for us in building multifaceted iOS apps with a team of more than two people. Sound like your jam? Read on.
Learning from the Web
The inspiration for splitting up our mobile app into sub-apps came from the successes we've seen with HubSpot's web architecture.
HubSpot's web app architecture is built for development-speed and scalability. As my colleagues have written, we use a variety of tools and techniques to let us collectively deploy about 300 times a day. This is critical, as HubSpot's product suite consists of several loosely coupled but very different applications -- analytics, social media, email, blogging, and reporting tools.
On the web, we can build, test, and deploy small sections of the HubSpot app independently -- including backend APIs and jobs written in Java, front end CoffeeScript projects, and Python projects. Why not do the same for mobile?
CocoaPods: Use It.
CocoaPods, the excellent dependency management solution for iOS, is key in bringing everything together.
A multi-app architecture may be overkill for your use case, but CocoaPods certainly is not -- even if you're just bringing in a handful of 3rd party libraries for usage tracking, view components, or networking -- investing the few minutes to set it up is fully worth your time. The ruby gem-like syntax makes integrating open source components into an app nearly seamless.
Core libraries and shared resources like login, styling classes, and API/credential persistence and access are built as independent projects with Kiwi tests and a podspec file. We publish them to ourprivate CocoaPods repository and include them in our actual fully-built applications. However, we take it a step further by building each sub-app -- all of Social Media, Email, or Sources, for example -- as a separate project with a podspec, then build them all into a single app using CocoaPods.
This means we can ship test versions of a single feature internally, and can move quickly with breaking changes in a single app without worrying about breaking the big build for other developers working in other unrelated sub-apps.
The Podfile for our aggregate app, therefore, looks like:
platform :ios, '6.0' # networking, slider navigation, routing
pod 'AFNetworking', '~> 1.2.1'
pod 'ViewDeck', '~> 2.2.11'
pod 'JLRoutes', '~> 1.2' # sub-apps, pulling from the head of each repo for development. alternately, we can pin it to a release version like we do the other pods
pod 'HSAPIClient', :head
pod 'HSCommonResources', :head
pod 'HSMarketingGraderApp', :head
pod 'HSContactsApp', :head
pod 'HSDashboardApp', :head
pod 'HSLoginApp', :head
pod 'HSSocialApp', :head
pod 'HSSourcesApp', :head
pod 'HSSettingsApp', :head
pod 'HSSocialReach', :head
pod 'HSEmailApp', :head
Gluing it all Together
Astute readers will notice we've used a couple of open source tools in our main application that are key in gluing the sub-apps together,IIViewDeck and JLRoutes.
To make it so that we don't have to provide information in the base app about the different menu items and routes each sub-app can handle, each sub-app provides a single class that implements an HSBaseApp protocol with a few methods:
@protocol HSBaseApp <NSObject>
+ (UINavigationController *)baseNavigationController;
+ (NSArray *)menuItems;
+ (NSArray *)routesToRegister;
@end
An example implementation is:
+ (UINavigationController *)baseNavigationController {
return [[HSNavigationController alloc] initWithRootViewController:[[HSSocialViewController alloc] initWithNibName:@"HSSocialViewController" bundle:nil]];
} + (NSArray *)menuItems {
HSMenuItem *calendarMenuItem = [[HSMenuItem alloc] initWithTitle:@"Publishing" icon:@"\\" launchHubSpotApp:[HSSocial class]];
calendarMenuItem.sectionTitle = @"Social"; return @[calendarMenuItem];
} + (NSArray *)routesToRegister {
HSRoute *newItemRoute = [HSRoute routeWithUrl:@"social/new" andAction:^BOOL(id<HSRoutingDelegate> routingDelegate, NSString *url, NSDictionary *parameters) {
// handle route, usually by suppying a UIViewController to the routingDelegate
}]; NSArray *routes = @[newItemRoute]; // could be more routes here too return routes;
}
We use routes to handle incoming push notifications, and we use the same scheme to link across sub-apps within the main app -- as is the case when we link to Contacts from Sources or Social Media, for example.
HSRoutingDelegate has a little bit of magic in it for passing around the currently active UINavigationController so we can push on top or create a modal in a route based on context, but otherwise it's a simple wrapper for JLRoutes' excellent block-based syntax.
ios Using CocoaPods to Modularize a Big iOS App->使用CocoaPods来进行模块化开发的更多相关文章
- 李洪强iOS之集成极光推送三iOS集成指南
李洪强iOS之集成极光推送三iOS集成指南 SDK说明 适用版本 本文匹配的 SDK版本:r2.1.5 以后.查看最近更新了解最新的SDK更新情况.使用Xcode 6及以上版本可以使用新版Push S ...
- iOS 从0到1搭建高可用App框架
iOS 从0到1搭建高可用App框架 最近在搭建新项目的iOS框架,一直在思考如何才能搭建出高可用App框架,能否避免后期因为代码质量问题的重构.以前接手过许多“烂代码”,架构松散,底层混乱,缺少规范 ...
- iOS关于模块化开发解决方案(纯干货)
关于iOS模块化开发解决方案网上也有一些介绍,但真正落实在在具体的实例却很少看到,计划编写系统文章来介绍关于我对模块化解决方案的理解,里面会有包含到一些关于解耦.路由.封装.私有Pod管理等内容:并编 ...
- 根据iOS 10 的新特性,创建iMessage App,可用于自定义表情
第一. 介绍(原文作者 澳大利亚19岁少年--Davis Allie ----原文地址) 随着iOS10的发布,苹果对开发者开放了Messages应用程序,开发人员现在可以创建他们自己的各种类型 并且 ...
- iOS应用内抓包、NSURLProtocol 拦截 APP 内的网络请求
前言 开发中遇到需要获取SDK中的数据,由于无法看到代码,所以只能通过监听所有的网络请求数据,截取相应的返回数据,可以通过NSURLProtocol实现,还可用于与H5的交互 一.NSURLProto ...
- 李洪强iOS之集成极光推送二iOS 证书 设置指南
李洪强iOS之集成极光推送二iOS 证书 设置指南 创建应用程序ID 登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 在 iOS Provisioning ...
- 李洪强iOS之集成极光推送一iOS SDK概述
李洪强iOS之集成极光推送一iOS SDK概述 JPush iOS 从上图可以看出,JPush iOS Push 包括 2 个部分,APNs 推送(代理),与 JPush 应用内消息. 红色部分是 A ...
- iOS 9音频应用播放音频之iOS 9音频播放进度
iOS 9音频应用播放音频之iOS 9音频播放进度 iOS 9音频应用开发播放进度 音频文件在播放后经过了多久以及还有多久才可以播放完毕,想必是用户所关注的问题.为了解决这一问题,在很多的音乐播放器中 ...
- IOS学习笔记48--一些常见的IOS知识点+面试题
IOS学习笔记48--一些常见的IOS知识点+面试题 1.堆和栈什么区别? 答:管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制:对于堆来说,释放工作由程序员控制,容易产生memor ...
随机推荐
- CentOS6.x安装配置nginx [转]
博文来源:http://leyewen.blog.163.com/ nginx安装 nginx的官网:http://nginx.org/ 相应下载页面:http://nginx.org/en/ ...
- VS2013 单元测试(使用VS2013自带的单元测试)
本文是官方文档的学习笔记,官方文档在这里. 1.打开VS3013,随便建一个解决方案,比如叫:LearnUnitTest,建一个类库项目LearnUnitTest_Bank,该项目中添加一个BankA ...
- ftp两种传输方式区别
转自:http://linux.chinaitlab.com/server/806269.html FTP可用多种格式传输文件,通常由系统决定,大多数系统(包括UNIX系统)只有两种模式:文本模 式和 ...
- node系列1
NodeJS基础 JS是脚本语言,脚本语言都需要一个解析器才能运行,NodeJS就是一个解析器.nodejs.org 打开终端,键入node进入命令交互模式,可以输入一条代码语句后立即执行并显示结果 ...
- Weka 入门2
现在我们介绍使用Weka来对数据进行分类.对数据进行分类,我们必须先指定那一列作为预测类别.因为数据文件格式的问题,类别一般都是最后一列属性.我们可以使用setClassIndex来设置类别.然后我们 ...
- HDU-4415 Assassin’s Creed 贪心
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4415 用贪心来解,开始分为两个集合的方法错了,没有考虑之间的相互影响,正确的姿势应该是这样的,分两种情 ...
- 创建二叉树,C语言实现
一.前序遍历创建二叉树,使用递归,头文件 BiTree.h /*槽点一:创建树时用scanf输入不成功*/ #ifndef BITREE_H #define BITREE_H #include< ...
- redis的hash, list, set类型相关命令
hash相关命令: 1. hset HSET key field value 将哈希表key中的域field的值设为value.如果key不存在,一个新的哈希表被创建并进行hset操作.如果域fiel ...
- EGOImageView的使用方法及注意事项
1.下载EGOImageView及其相关的类库 EGOImageLoading 将EGOCache.EGOImageButton.EGOImageView.EGOImageLoader全部添加到工程下 ...
- [一]初识SpringMVC
是什么? web开发框架 为什么用? 功能强大 怎么做? 1.导入jar包 2.配置web.xml <?xml version="1.0" encoding="UT ...