由本章节开始,咱们将从支付宝客户端的架构设计方案入手,细分拆解客户端在“容器化框架设计”、“网络优化”、“性能启动优化”、“自动化日志收集”、“RPC 组件设计”、“移动应用监控、诊断、定位”等具体实现,带领你们进一步了解支付宝在客户端架构上的迭代与优化历程。数组
本节将介绍支付宝 iOS 容器化框架设计的基本思路。bash
在 mPaaS 开篇介绍中已经和你们分享过《模块化与解耦式开发在蚂蚁金服 mPaaS 中的实践》:经过容器化开发框架将业务隔离成相对独立的模块,并着力追求模块与模块之间高内聚、低耦合,所以咱们实现了灵活的插件式开发,并得以将业务划分为上千个独立工程。网络
mPaaS iOS 框架源自于支付宝客户端,为了实现这种上千个工程之间的低耦合和相关依赖调用,mPaaS 框架直接接管了 App 的生命周期,负责整个 App 启动托管、App 生命周期管理、处理与分发 UIApplication
的代理事件。 mPaaS 框架提供了容器化环境,业务开发人员在这个容器化环境中使用 微应用
和 服务
进行具体的业务需求开发。架构
微应用
和 服务
是 mPaaS 框架内定义的概念,主要是用来进行业务模块间的划分。按照是否有 UI 界面做为标准,mPaaS 框架将不一样的业务模块划分为 微应用
和 服务
。微应用
是 APP 运行期间带有用户界面的业务模块;服务
是 App 运行期由业务提供的轻量级抽象服务。在 mPaaS 框架中,经过 框架上下文Context
进行 微应用
与 服务
的生命周期管理。app
经过修改 main.m 函数的实现,mPaaS 框架使用本身的 ClientDelegate
类接管了 UIApplicationDelegate
中各类 App 生命周期。mPaaS 框架接入以后,ClientDelegate
彻底替代了通常工程中的 AppDelegate
的角色,从而实现了整个应用的生命周期都是由框架进行管理。框架
int main(int argc, char * argv[]) {
@autoreleasepool {
// Now use mPaaS framework
return UIApplicationMain(argc, argv, @"Application", @"ClientDelegate");
}
}
复制代码
为了方便用户获取 App 生命周期来开发自定义功能,mPaaS 框架提供了 DTFrameworkInterface
类里面实现了 UIApplicationDelegate
中全部代理方法的等价接入方式,只须要在 DTFrameworkInterface
的 Category 中覆盖对应的方法便可。模块化
例以下面常见的 UIApplicationDelegate
代理方法:函数
@protocol UIApplicationDelegate<NSObject>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)applicationWillResignActive:(UIApplication *)application;
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation;
@end
复制代码
在 DTFrameworkInterface
中都提供了对应的方法:post
typedef NS_ENUM(NSInteger, DTFrameworkCallbackResult)
{
DTFrameworkCallbackResultContinue = 0, // 继续执行
DTFrameworkCallbackResultReturn = 1, // 中断执行
DTFrameworkCallbackResultReturnYES = 2, // 中断以后的逻辑,并返回 YES
DTFrameworkCallbackResultReturnNO = 3, // 中断以后的逻辑,并返回 NO
};
@interface DTFrameworkInterface : NSObject
#pragma mark - 应用配置,微应用配置、服务配置、Scheme 处理器配置,可用 Category 覆盖
- (void)application:(UIApplication *)application beforeDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (DTFrameworkCallbackResult)application:(UIApplication *)application handleDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (void)application:(UIApplication *)application afterDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (DTFrameworkCallbackResult)applicationDidBecomeActive:(UIApplication *)application;
- (DTFrameworkCallbackResult)applicationWillResignActive:(UIApplication *)application;
- (DTFrameworkCallbackResult)application:(UIApplication *)application
openURL:(NSURL *)url
newURL:(NSURL **)newURL
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation;
@end
复制代码
因为 mPaaS 框架有一些本身的初始化逻辑须要实现,在 DTFrameworkInterface
中额外提供了 beforeDidFinishLaunchingWithOptions
和 afterDidFinishLaunchingWithOptions
方法,方便用户在 App 启动时肯定的时间执行本身的初始化代码。性能
DTFrameworkInterface
在 afterDidFinishLaunchingWithOptions
以前会启动 BootLoader
,执行 mPaaS 框架的初始化逻辑。在嵌入式操做系统中,BootLoader
的做用是初始化硬件设备,以便为最终调用操做系统内核准备好正确的环境。相似的在 mPaaS 框架中,BootLoader
用来初始化整个 mPaaS 框架环境,默认实现为依次执行下面的流程:
这样就完成了 mPaaS 框架的初始化和首页的显示。
后面将详细介绍其中关键的3个概念:微应用
、服务
、框架上下文 Context
。
微应用就是带 UI 界面的独立业务模块,其中最特殊的一个微应用是 Launcher
微应用,Launcher
做为 App 启动以后第一个打开的微应用,通常用来建立 App 首页。在 mPaaS 框架中,各个微应用之间是高度独立、不相互依赖的。
微应用
经过 plist
文件配置来进行注册。配置微应用时须要指定 delegate
对应的类名、微应用的描述 description
以及打开微应用时使用的 name
。这样 框架上下文 Context
经过微应用的 name
就能够打开指定的微应用。
为了方便业务开发,每一个 微应用
也存在生命周期。微应用的生命周期,是模仿 iOS App 的生命周期来作的。每一个微应用须要实现本身的 DTMicroApplicationDelegate
代理,这个相似于 iOS App 中实现的 Appdelege
类。
对于具体业务开发而言 微应用
的开发和一个完整的 App 同样,每一个 微应用
负责控制本身应用内的页面堆栈,并根据 微应用
的生命周期执行相应的操做。在 mPaaS 框架中,全部的 微应用
都是运行在 mPaaS 框架提供的容器中,其不须要关注 App 的生命周期。对于一些特殊的业务场景,mPaaS 支持建立微应用的多个实例。
服务
与 微应用
不一样地方在于其没有 UI 界面,是在后台执行。一旦服务启动后,其在整个客户端的生命周期中一直存在,所以服务通常用于给微应用提供通用服务,好比执行某个功能或者获取数据等。
一个常见的服务是用户登录状态服务,每一个微应用能够经过这个服务来获取到用户的登陆状态和用户信息。
服务
也是经过 plist
文件配置来进行注册。服务注册时须要提供服务的惟一标识 name
和对应的实现类 class
类名。框架在建立 服务
时会利用 Objective-C
语言的运行时机制建立 服务
实现类的实例。lazyLoading
用来控制是否延迟加载该类。若是是延迟加载,在框架启动时该 服务
并不会实例化,只有在用到该 服务
时才会实例化并启动。若是是非延迟加载,则在框架启动时会启动该服务。
因为服务的特殊性,在 mPaaS 中同时提供了 ServicesMap
来批量注册类,ServicesMap
中的 [AUTOSTART]
用来讲明哪些组的服务
须要在 App 启动的时候最早启动。
这种分级启动服务的特色能够有效控制 App 的启动时间,提供很好的用户体验。
每一个服务都须要实现 服务
接口:
@required
/**
* 启动一个服务。
* 注意:
* 框架在完成初始化操做后,会调用该方法。
* 若是一个服务要启动一个应用,必须在该方法被调用以后,才能启动其它的应用。
*/
- (void)start;
@optional
/**
* 建立服务完成。
*/
- (void)didCreate;
/**
* 服务将要销毁。
*/
- (void)willDestroy;
复制代码
在增长了 服务
以后,整个 App 的结构以下图所示。后台的服务成为各个 微应用
之间沟通的桥梁。
经过前面的介绍,你们已经对 微应用
和 服务
有了深刻的了解。在 mPaaS 框架中,框架上下文Context
承担了一个调度员的角色,负责各个 微应用
和 服务
的调度、通讯管理,这样就实现了每一个 微应用
的打开、页面推栈以及关闭不会影响 App 其余 微应用
模块。
经过 mPaaS 框架提供的 DTContext * DTContextGet()
函数能够获取到框架上下文Context
对象。一个简化的 Context
类实现以下:
@interface Context : NSObject
@property(nonatomic, strong) UIWindow *window;
@property(nonatomic, strong) UINavigationController *navigationController;
// 根据指定的名称启动一个微应用
- (BOOL)startApplication:(NSString *)name params:(NSDictionary *)params animated:(BOOL)animated;
// 逆向遍历微应用栈,返回最新的微应用对象。
- (DTMicroApplication *)findApplicationByName:(NSString *)name;
// 根据指定的名称查到一个服务
- (id)findServiceByName:(NSString *)name;
// 注册一个服务
- (BOOL)registerService:(id)service forName:(NSString *)name;
// 反注册一个已存在的服务
- (void)unregisterServiceForName:(NSString *)name;
@end
复制代码
对于业务开发人员,能够经过 框架上下文 Context
获取到主 window、启动指定的 微应用
、获取一个 服务
、动态注册与反注册 服务
,从而实现业务之间的链接。
经过本节内容,咱们初步了解了 mPaaS 在 iOS 端容器化框架的设计思路,经过 微应用
和 服务
的方式完成业务模块之间的解耦和调用。框架上下文 Context
做为一个迷你的容器操做系统,为 微应用
和 服务
的运行提供了所需的容器化环境,保证了独立的业务开发流程和流畅的用户体验。
欢迎你们体验 mPaaS 容器化开发框架,期待你们的反馈与交流。
往期阅读
《开篇 | 模块化与解耦式开发在蚂蚁金服 mPaaS 深度实践探讨》