mPaas

概念

移动开发平台(Mobile PaaS,简称 mPaaS)是源于支付宝 App 的移动开发平台,为移动开发、测试、运营及运维提供云到端的一站式解决方案,能有效降低技术门槛、减少研发成本、提升开发效率,协助企业快速搭建稳定高质量的移动 App。

主要功能

  • 3 大研发框架:Native 开发框架、Kylin H5 开发框架、小程序开发框架。
  • 20 多个功能性组件,例如网关服务、埋点分析、热修复、用户反馈、消息推送、离线包、国际化、扫码等。
  • 100 多个 UI 控件,包括 AntUI 和 AntMobile。

主要应用

设备标识 :简单快捷地获取设备 ID,快速定位到特定设备
H5 容器 :在 Native 代码中快速加载 H5 页面
社交分享 :快速便捷地将信息共享到各个渠道

接入

mPaaS iOS 框架是源自支付宝客户端的开发框架。该框架直接接管应用的生命周期,负责整个应用 启动托管应用生命周期管理。同时基于 Framework 的设计思想,将业务隔离成相对独立的模块,着力于追求模块之间的高內聚、低耦合。参考 mPaaS 框架介绍 获取更多信息。

不适用一般的AppDelegate,而使用DTFrameworkInterface来控制整个生命周期。

以下为main.m中接入。

int main(int argc, char * argv[]) {
    [MPAnalysisHelper enableCrashReporterService]; // USE MPAAS CRASH REPORTER

        @autoreleasepool {
            // 开启闪退上报
            [MPAnalysisHelper enableCrashReporterService];
        
#ifdef HOTPATCHEXIST
        NSString *path;
        APSecBufferRef buf;
        int ret;
        
        path = [[NSBundle mainBundle] pathForResource:@"pubkey" ofType:@"pem"];
        APSecInitPublicKey([path UTF8String]); // 读取并初始化公钥
        
        buf = APSecGetPKS(); // 读取公钥的签名
        ret = APSecVerifyFile([path UTF8String], buf->data, buf->length); // 验证公钥文件自身是否符合签名
        free(buf);
        if (ret != 0) {
            MSCLog(@"The public key is modified.");
        }
#endif
        
        return UIApplicationMain(argc, argv, @"DFApplication", @"DFClientDelegate"); // NOW USE MPAAS FRAMEWORK
    }
}

目录结构

  • mpaas_sdk.config:当前工程添加的模块信息,包括版本、添加时间、资源文件等,由 mPaaS 插件自动维护,不得手动修改。
  • mPaaSDemo-mPaaS-Headers.h:当前工程依赖的 mPaaS 模块的头文件,由 mPaaS 插件自动维护,不得手动修改。
  • mPaaSDemo-Prefix.pch:当前工程 pch 文件的引用,会自动将 mPaaSdemo-mPaaS-Headers.h 加入 mPaaS 模块的头文件。
  • APMobileFramework:mpaas 框架的生命周期管理的 category 文件。
  • mPaas:MPaaSInterface 的 category 文件。
  • meta.config:从 mPaaS 控制台下载的云端元数据。
  • yw_1222.jpg:通过元数据中的 base64code 字段生成的无线保镖验签图片,在移动网关验签时使用。如不需要移动网关功能,可删除此图片。
  • Resources & Frameworks:mPaaS 模块的资源文件和二进制文件目录,是当前工程所有 Targets 使用的 mPaaS 模块的并集,由 mPaaS 插件自动维护,不得手动修改。

mPaas框架详解介绍

启动托管

通过程序 main 函数的替换,直接接管应用的生命周期,整个启动的过程如下:
main -> DFClientDelegate -> 打开 Launcher 应用

应用生命周期管理

mPaaS 框架接入之后,完全替代了 AppDelegate 的角色,整个应用的生命周期由框架进行管理,但是用户依然可以实现应用生命周期各个阶段对应的代理方法,UIApplicationDelegate 中的所有代理方法,框架都提供了等价的接入方式,只需要在 Category 中覆盖对应的方法即可。

从前台到后台,从后台到前台,以及收到消息通知等都有等同方法。

应用模块划分

mPaaS 框架内定义了微应用和服务的概念来进行模块间的划分。其中,以是否有 UI 界面作为标准,Framework 将不同的模块划分为 微应用服务,通过 框架上下文 进行微应用与服务的生命周期管理。

微应用

在基于 mPaaS iOS 框架开发应用的过程中,一般会将带有 UI 界面的独立业务设置为一个微应用(如支付宝中的转账、手机充值等),与其他的业务隔离开,在微应用内实现自身业务逻辑。要添加一个微应用,您需要添加微应用模板代码,并注册微应用。

微应用在MobileRuntime.plist 中注册后,通过框架进行统一管理。包括注册delegatedescription以及name。然后继承DTMicroApplicationDelegate协议的自定义类DemoAppDelegate。以及继承自DTViewController自定义视图控制器DemoAppController

服务

在基于 mPaaS iOS 框架开发应用的过程中,没有 UI 界面且通用的功能,可以设置为服务(如登录服务),在整个 App 运行期可以方便地被其他微应用或服务获取。添加一个服务,您需要添加服务模板代码,并注册服务。

注册方式同微应用。实现一个提供协议接口方法的DemoService,以及遵循该协议的实现类DemoServiceImp

管理微应用和服务

管理微应用

  • 基于 mPaaS iOS 框架,可以根据微应用的 name,快速查找到此微应用,并在当前微应用中启动另一个微应用
  - (void)pushSubApp2
  {
 
      [DTContextGet() startApplication:@"20000002" params:@{} launchMode:kDTMicroApplicationLaunchModePushWithAnimation];
  }
  • 微应用堆栈中上层的微应用,可以快速跳转到堆栈底部的根应用:
 - (void)exitToLauncher
  {
      // 因为 Launcher 在下层,所以再启动 Launcher 实际是退出上层所有的 App,回到 Launcher
      [DTContextGet() startApplication:@"Launcher" params:nil animated:kDTMicroApplicationLaunchModePushNoAnimation];
  }
  • 快速退出当前微应用:
- (void)exitSelf
  {
      [[DTContextGet() currentApplication] exitAnimated:YES];
  }
  • 快速退出已启动的应用:
  - (void)exitApp2
  {
      // 当前顶层应用是 app3,但是可以强行把 app2 和它的窗口都退出。
      [[DTContextGet() findApplicationByName:@"20000002"] forceExit];
  }

管理服务
基于 mPaaS iOS 框架,可以快速在当前微应用中启动另一个服务。

- (void)findService
{
    id<DemoService> service = [DTContextGet() findServiceByName:@"DemoService"];
    [service doTask];
}

一个业务场景的微应用,使用一个delegate,注册的name使用其根VC。一个微应用中可以有多个vc,其中微应用内的VC跳转使用正常的push、pop模式。微应用间的跳转,才使用管理微应用的跳转模式。
而服务主要是一些不包含ui的业务逻辑抽象,比如请求一些数据,保存一些数据,以及获取标识符登录功能等。

主要功能

移动网关

移动网关服务(Mobile Gateway Service,MGS)是移动开发平台(mPaaS)提供的连接移动客户端与服务端的组件产品。该组件简化了移动端与服务端的数据协议和通讯协议,能够显著提升开发效率和网络通讯效率。
(就是封装的网络请求框架。提供服务端框架代码,生成客户端SDK)

特点
  • 自动生成客户端的 RPC 调用代码,用户不需要关心网络通信、协议以及使用的数据格式。(封装好)
  • 将服务端返回的数据自动反解生成 Objective-C 对象,无需额外编码。(省去自己截码)
  • 提供数据压缩、缓存、批量调用等增强服务。
  • 支持 RPC 拦截器,实现定制化的请求与处理。
  • 实行统一的安全加密机制和防篡改的请求签名验证机制。
网络请求框架APMobileNetwork

MPRpcInterface 提供异步请求。

/**
 初始化 MGS 组件,在调用第一个 RPC 之前必须调用,建议在 App 启动时较早时机调用
 */
+ (void)initRpc;

/**
 *  异步block,completion会在主线程回调
 *
 *  @param block      相关操作
 *  @param completion block完成后的处理
 *
 *  @return DTRpcAsyncCaller
 */
+ (DTRpcAsyncCaller *)callAsyncBlock:(void (^)(void))block completion:(void (^)(void))completion;

DTRpcClient 提供具体的网络请求方法。

+ (DTRpcClient *)defaultClient;

/**
 * 根据指定的 \code DTRpcMethod 执行一个 RPC 请求。
 *
 * @param method 一个 \code DTRpcCode 类型的实例,描述了 RPC 请求的相头信息。
 * @param params RPC 请求需要的参数。
 * @param field  添加到request里面的head
 * @param responseBlock 回调方法
 *
 * @return 如果请求成功,返回指定类型的对象,否则返回 nil。
 */
- (id)executeMethod:(DTRpcMethod *)method params:(NSArray *)params requestHeaderField:(NSDictionary*)field responseHeaderFields:(void (^)(NSDictionary* allHeaderFields))responseBlock;

结合使用

[MPRpcInterface callAsyncBlock:^{
    @try{
        DTRpcConfig *config = [[DTRpcClient defaultClient] configForScope:kDTRpcConfigScopeGlobal];//初始化
        config.isAMRPC = YES;
        DTRpcMethod *method = [[DTRpcMethod alloc] init];
        method.operationType = self.operationType;//请求地址
        method.checkLogin = NO;
        method.signCheck = YES;//加签
        method.returnType = @"@\"NSDictionary\"";
        method.timeoutInterval = 30.0f;
        result = [[DTRpcClient defaultClient] executeMethod:method params:@[dict?dict:[NSNull null]] requestHeaderField:self.realReqHeadJson responseHeaderFields:nil];
    }
    @catch (NSException *exception) {
        self.exceptionMsg=exception;
    }
} completion:^{
//        NSString *status = [result objectForKey:@"STATUS"];
    if ([result isKindOfClass:[NSDictionary class]]&&successBlock) {
        successBlock(result);//成功回调
    }else if (self.exceptionMsg&&errorBlock){
        errorBlock(self.exceptionMsg);
    }else {
        if(failBlock){failBlock(result);}
    }
}];

+ (NSDictionary *)getPublicHeader;//请求头
+ (NSString *)getIPAddress;//网络ip
+ (NSString*)getNetReachability;//获取网络状态

数据同步

数据同步是 mPaaS 平台的一个核心基础服务组件。数据同步源自蚂蚁集团内面向移动应用、从服务端到客户端进行海量数据推送的全链路解决方案 — SYNC。该组件提供了一个安全的基于传输控制协议(Transmission Control Protocol,简称 TCP)和安全套接层(Secure Sockets Layer,简称 SSL)的数据通道,能够及时、准确、有序地将服务器端的业务数据主动地同步(SYNC)到客户端 App。

传统的远程过程调用(Remote Procedure Call,简称 RPC)已立足互联网行业几十年,也能满足绝大部分业务场景和功能需求。但在现阶段,随着移动互联网的全面普及和发展,无论是 App 的规模还是用户对于 App 的要求都已进入了一个新的阶段。传统的 RPC 请求因其自身的特性,存在许多的不足:

  • 客户端在特定的场景下需要调用 RPC 请求来获取最新的数据,而服务端(云端)实际没有或仅有少量数据发生变化。
  • 在客户端启动时,不同的业务模块、业务功能因设计上的独立,需要分别进行 RPC 请求来完成各自业务的数据拉取。
  • 客户端无法及时感知服务端发生的数据变化,只能通过定时轮询 RPC 接口的方式来刷新数据。
  • 传统 RPC 大多基于 HTTP(S) 的短连接进行数据交互,连接上即使使用 keepalive 等特性也无法长期保持连接,无法做到链路持续复用。请求创建连接、证书交换、加解密等对网络耗时及性能都会代来不小的损耗

代码示例

为实现监听同步业务的逻辑,您需要创建一个类,最好是常驻内存的服务来一直监听 Sync 消息。在下面的示例中,创建了一个 MySyncService 类来监听同步业务的逻辑。

#import <MPMssAdapter/MPSyncInterface.h>
#define SYNC_BIZ_NAME "SYNC-TRADE-DATA";
 
@implementation MySyncService
+ (instancetype)sharedInstance
{
    static MySyncService *bizService;
 
    static dispatch_once_t llSOnceToken;
 
    dispatch_once(&llSOnceToken, ^{
 
        bizService = [[self alloc] init];
    });
    return bizService;
}
 
-(instancetype)init
{
    self = [super init];
    if (self) {
        [MPSyncInterface initSync];
        BOOL registerSingleDeviceSync = [MPSyncInterface registerSyncBizWithName:SYNC_BIZ_NAME syncObserver:self selector:@selector(revSyncBizNotification:)];
        [MPSyncInterface bindUserWithSessionId:@"SESSION_DEMO"]; // 此处的 User 对应控制台下发命令时,所需要填写的 userId, 需要和 MPaaSInterface 的 userId 函数中配置的值相对应;sessionId 是客户端携带的授权 token,userId 和 sessionId 都是用户登录系统返回的数据,当 userId 和 sessionId 变化时,需要重新调用此函数才能保证长连接的建立正确。
    }
    return self;
}
 
-(void)revSyncBizNotification:(NSNotification*)notify
{
    NSDictionary *userInfo = notify.userInfo;
    dispatch_async(dispatch_get_main_queue(), ^{
        //业务数据处理
        [MySyncService handleSyncData:userInfo];
        //回调 SyncSDK,表示业务数据已经处理
        [MPSyncInterface responseMessageNotify:userInfo];
    });
}
 
+(void)handleSyncData:(NSDictionary *)userInfo
{
    NSString * stringOp = userInfo[@"op"];
    NSArray *op = [NSJSONSerialization JSONObjectWithData:[stringOp dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
    if([op isKindOfClass:[NSArray class]]){
        [op enumerateObjectsUsingBlock:^(NSDictionary * item, NSUInteger idx, BOOL *stop) {
            if([item isKindOfClass:[NSDictionary class]]){
                NSString * plString = item[@"pl"];//业务数据 payload
                if(item[@"isB"]){
                    NSData *dataPl = [[NSData alloc] initWithBase64EncodedString:plString options:kNilOptions];
                    NSString *pl = [[NSString alloc] initWithData:dataPl encoding:NSUTF8StringEncoding];
                    NSLog(@"biz payload data:%@,string:%@",dataPl,pl);
                }else{
                     NSLog(@"biz payload:%@",plString);
                }
            }
        }];
    }
}
 
-(void)dealloc
{
    BOOL unRegisterSingleDeviceSync = [MPSyncInterface unRegisterSyncBizWithName:SYNC_BIZ_NAME syncObserver:[MySyncService sharedInstance]];
    [MPSyncInterface removeSyncNotificationObserver:self];
}
@end

类似于推送。不过不同于传统推送,阿里的实现方式更适用于大量数据。

常用api

+(void)initSync; //初始化
+(MPSyncNetConnectType)connectStatus;//查看链接状态
+(BOOL)registerSyncBizWithName:(NSString *)bizName syncObserver:(id)observer selector:(SEL)selector;//注册监听服务端接口名,以及监听回调方法
+(BOOL)unRegisterSyncBizWithName:(NSString *)bizName syncObserver:(id)observer;//解除注册监听
+(void)bindUserWithSessionId:(NSString *)sessionId;//绑定用户信息
+(void)unBindUser;//解绑

移动分析

阿里行为分析。

埋点实现较为简单。可使用swizzilng交换方式统一埋点。

实时发布

在 iOS 开发领域,由于 AppStore 审核标准严格、审核周期长、效率低,应用的发版速度极慢,因此能快速修复线上严重 Bug 而无需发布新版本的热修复方法对于 iOS 应用来说就显得尤其重要。

mPaaS 提供的 Hotpatch 热修复技术,在 Runtime 运行时特性的基础上,通过 JS 替换原有的 Objective-C 方法,从而达到修复线上 bug 的目的。目前包含的能力如下:

添加类,修改类(包括添加实例方法、类方法、属性,修改方法实现等)。
调用任意 Objective-C 类方法,访问成员变量。
使用 block、struct、GCD 等高级语法。
回滚操作热生效,被替换的方法能即时恢复。
脚本执行时机控制(启动前主线程运行、启动完成之后子线程运行)。
完善的安全加密、签名验证系统。

热修复的具体使用
  1. 接入sdk。
  2. 使用原生Objective-C代码解决bug。
  3. 用在线工具 JSPatchConvertorObjective-C 代码转为 JS 脚本
  4. 验证转化后 JS 脚本(假设为 Test.js)的正确性,可以将写好的 JS 文件拖入到工程中,并在程序启动时(推荐在 didFinishLaunchingWithOptions 中)手动调用 JS 脚本,验证问题是否被正确修复
    NSString *file = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:[NSString stringWithFormat:@"Test.js"]];
    [MPDynamicInterface runDynamicLocalFile:file];
    
  5. 为了安全,加密。
  6. 使用mPass工具生成热修复资源包。
  7. 发布热修复资源包,已集成热修复的客户端源码可自行下载并替换修复。

UI组件

H5容器和离线包

H5 容器是一款移动端 Hybrid 解决方案 SDK(Nebula SDK)。提供了良好的外部扩展功能,拥有功能插件化、事件机制、JSAPI 定制和 H5App 推送更新管理能力。
离线包 是将包括 HTML、JavaScript、CSS 等页面内静态资源打包到一个压缩包内。预先下载该离线包到本地,然后通过客户端打开,直接从本地加载离线包,从而最大程度地摆脱网络环境对 H5 页面的影响。

渲染过程

当 H5 容器发出资源请求时,其访问本地资源或线上资源所使用的 URL 是一致的。
H5 容器会先截获该请求,截获请求后,发生如下情况:

  • 如果本地有资源可以满足该请求的话,H5 容器会使用本地资源。
  • 如果没有可以满足请求的本地资源,H5 容器会使用线上资源。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容