iOS的动态部署能极大的节约成本。苹果的审核周期很长,有的时候,你可能不得不等待将近2个星期去上架你的新功能或者bug。所以动态部署是有价值的。

我这里讨论的情况不把纯web应用考虑在内,因为用户体验过于差,偶尔出现几个页面还可以,但是整个app都是的话,无疑是非常糟糕的。

理论上讲,因为OC是一门动态语言,你可以利用runtime框架,把任意脚本语言,只要该脚本的解释器是由c语言解释器写成,就可以实现由文本向代码的转变。甚至你也可以自己实现一个解释器(也许会有人喜欢造这样的轮子),不过太小众的话,可能除了你自己,就没有人可以维护了。

说说比较大众的解决方案:

第一个是lua

lua目前来讲,更多的是应用在游戏上,通常游戏的包都很大,让玩家常常来更新你们的客户端,那么等着玩家删掉你们的客户端吧。lua第一次名声大噪大概是被魔兽世界所应用,现在手游上cocos-2d中的lua版本即便算不上很主流,但使用的厂商仍然不少。

iOS中,由阿里维护的wax是个比较好的选择,使用起来也比较稳定,具体的仍可以参见github上的文档,感觉阿里的同学的维护。

https://github.com/alibaba/wax

lua的优点在于:解释的速度要比js(下面介绍)要快一些

lua的缺点在于:需要将整个lua的解释器打入程序中,不过这也是可以接受的。另外lua的开发者可能会少一些,在招人上可能难一些。

第二个是js

js目前也是更多的应用在游戏上,由于游戏的特性驱动所产生技术的产生与成熟,确实让游戏在动态部署成熟了些。cocos-2d的js版本应用要比lua版本广泛一些。腾讯的bang同学为我们开源了 JSPatch,向他致敬。

https://github.com/bang590/JSPatch

js的优点在于:系统内置了js的解释器(iOS7及之后),会js的人多。

js的缺点在于:解释稍慢。

以上两种动态部署方案,我个人都尝试过,出现的一些坑,肯定要写出来分享给大家。

1.库冲突问题。这也是我为什么两种方案都尝试的原因。我在首先尝试的JSPatch,发现Aspects这个框架

https://github.com/steipete/Aspects    做一些AOP变成的hook库。

同时使用了_objc_msgForward这个IMP,上面是Aspects,下面是JSPatch。我抱着侥幸的心里,虽然已经认识到WaxPatch极有可能也是如此实现的,去尝试了WaxPatch,果不其然,依旧不行,看最下面的代码,就是lua的。

static BOOL aspect_isMsgForwardIMP(IMP impl) {
return impl == _objc_msgForward
#if !defined(__arm64__)
|| impl == (IMP)_objc_msgForward_stret
#endif
;
}
static void overrideMethod(Class cls, NSString *selectorName, JSValue *function, BOOL isClassMethod, const char *typeDescription)
{
SEL selector = NSSelectorFromString(selectorName); if (!typeDescription) {
Method method = class_getInstanceMethod(cls, selector);
typeDescription = (char *)method_getTypeEncoding(method);
} IMP originalImp = class_respondsToSelector(cls, selector) ? class_getMethodImplementation(cls, selector) : NULL; IMP msgForwardIMP = _objc_msgForward;
#if !defined(__arm64__)
if (typeDescription[0] == '{') {
//In some cases that returns struct, we should use the '_stret' API:
//http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html
//NSMethodSignature knows the detail but has no API to return, we can only get the info from debugDescription.
NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:typeDescription];
if ([methodSignature.debugDescription rangeOfString:@"is special struct return? YES"].location != NSNotFound) {
msgForwardIMP = (IMP)_objc_msgForward_stret;
}
}
#endif class_replaceMethod(cls, selector, msgForwardIMP, typeDescription); #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
if (class_getMethodImplementation(cls, @selector(forwardInvocation:)) != (IMP)JPForwardInvocation) {
IMP originalForwardImp = class_replaceMethod(cls, @selector(forwardInvocation:), (IMP)JPForwardInvocation, "v@:@");
class_addMethod(cls, @selector(ORIGforwardInvocation:), originalForwardImp, "v@:@");
}
#pragma clang diagnostic pop if (class_respondsToSelector(cls, selector)) {
NSString *originalSelectorName = [NSString stringWithFormat:@"ORIG%@", selectorName];
SEL originalSelector = NSSelectorFromString(originalSelectorName);
if(!class_respondsToSelector(cls, originalSelector)) {
class_addMethod(cls, originalSelector, originalImp, typeDescription);
}
} NSString *JPSelectorName = [NSString stringWithFormat:@"_JP%@", selectorName];
SEL JPSelector = NSSelectorFromString(JPSelectorName); _initJPOverideMethods(cls);
_JSOverideMethods[cls][JPSelectorName] = function; class_addMethod(cls, JPSelector, msgForwardIMP, typeDescription);
} static BOOL isMethodReplacedByInvocation(id klass, SEL selector){
Method selectorMethod = class_getInstanceMethod(klass, selector);
IMP imp = method_getImplementation(selectorMethod); #if defined(__arm64__)
return imp == _objc_msgForward;
#else
return imp == _objc_msgForward || imp == (IMP)_objc_msgForward_stret;
#endif
} static BOOL isMethodReplacedByInvocation(id klass, SEL selector){
Method selectorMethod = class_getInstanceMethod(klass, selector);
IMP imp = method_getImplementation(selectorMethod); #if defined(__arm64__)
return imp == _objc_msgForward;
#else
return imp == _objc_msgForward || imp == (IMP)_objc_msgForward_stret;
#endif
}
static void replaceMethodAndGenerateORIG(id klass, SEL selector, IMP newIMP){
Method selectorMethod = class_getInstanceMethod(klass, selector);
const char *typeDescription = method_getTypeEncoding(selectorMethod); IMP prevImp = class_replaceMethod(klass, selector, newIMP, typeDescription);
if(prevImp == newIMP){
// NSLog(@"Repetition replace but, never mind");
return ;
} const char *selectorName = sel_getName(selector);
char newSelectorName[strlen(selectorName) + 10];
strcpy(newSelectorName, WAX_ORIGINAL_METHOD_PREFIX);
strcat(newSelectorName, selectorName);
SEL newSelector = sel_getUid(newSelectorName);
if(!class_respondsToSelector(klass, newSelector)) {
BOOL res = class_addMethod(klass, newSelector, prevImp, typeDescription);
// NSLog(@"res=%d", res);
}
}

既然冲突了,就必须解决冲突。鱼与熊掌,二者不可得兼,舍鱼而取熊掌。只能把 Aspects干掉了。

可是Aspects,实现的方法如何去替换呢?我就直接用了method swizzle。简单的实现了下Aspects的功能,但是没那么优雅。

@implementation UIViewController (AOP)

+ (void)initialize {
Method ori_Method = class_getInstanceMethod([UIViewController class], @selector(viewDidAppear:));
Method my_Method = class_getInstanceMethod([UIViewController class], @selector(aop_viewDidAppear:));
method_exchangeImplementations(ori_Method, my_Method);
} - (void)aop_viewDidAppear:(BOOL)animated {
[self aop_viewDidAppear:animated];
NSLog(@"------hook");
} @end

对,就是简单的hook一下。不过你要考虑清楚,对同一个方法hook几次,最后的执行顺序问题。

ReactiveCocoa这个框架也可能存在类似问题,可能没那么好解决了。这个时候可能要做一些取舍,如果你是leader的话,可能要制定下规范来避免这个问题,

什么方法不可以用,要如何hook等等,暂时我也没有太好的解决方案。

iOS应用动态部署方案的更多相关文章

  1. iOS动态部署方案

    转载: iOS动态部署方案 前言 这里讨论的动态部署方案,就是指通过不发版的方式,将新的内容.新的业务流程部署进已发布的App.因为苹果的审核周期比较长,而且苹果的限制比较多,业界在这里也没有特别多的 ...

  2. Jenkins动态部署方案

    在之前一个项目开发中使用到了jenkins自动化测试,根据实际应用,简单整理了其部署方案. 1.部署 2.项目构建 3.重部署 1 部署 登录Jenkins应用管理界面 1)选中一个服务器上已在jen ...

  3. iOS动态部署之RSA加密传输Patch补丁

    概要:这一篇博客主要说明下iOS客户端动态部署方案中,patch(补丁)是如何比较安全的加载到客户端中. 在整个过程中,需要使用RSA来加密(你可以选择其它的非对称加密算法),MD5来做校验(同样,你 ...

  4. iOS应用架构谈 本地持久化方案及动态部署

    转载: iOS应用架构谈 本地持久化方案及动态部署 前言 嗯,你们要的大招.跟着这篇文章一起也发布了CTPersistance和CTJSBridge这两个库,希望大家在实际使用的时候如果遇到问题,就给 ...

  5. iOS应用架构谈part4-本地持久化方案及动态部署

    前言 嗯,你们要的大招.跟着这篇文章一起也发布了CTPersistance和CTJSBridge这两个库,希望大家在实际使用的时候如果遇到问题,就给我提issue或者PR或者评论区.每一个issue和 ...

  6. ssiOS应用架构谈 本地持久化方案及动态部署

    本文转载至 http://casatwy.com/iosying-yong-jia-gou-tan-ben-di-chi-jiu-hua-fang-an-ji-dong-tai-bu-shu.html ...

  7. fir.im Weekly - iOS / Android 动态化更新方案盘点

    动态化更新是 App 开发必然面对的问题.在 iOS 环境下,Apple 开发者们像是" 带着手铐脚镣跳舞" ,相比之下 Android 开发者会轻松一点,有很多相关的开源框架帮助 ...

  8. iOS 中的 HotFix 方案总结详解

    相信HotFix大家应该都很熟悉了,今天主要对于最近调研的一些方案做一些总结.iOS中的HotFix方案大致可以分为四种: WaxPatch(Alibaba) Dynamic Framework(Ap ...

  9. ActiveMQ实现负载均衡+高可用部署方案

    一.架构和技术介绍 1.简介 ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.完全支持JMS1.1和J2EE 1.4规范的JMS Provider实现 2.activemq的特 ...

随机推荐

  1. OpenCV 之 支持向量机 (一)

    机器学习是由 模型 + 策略 + 算法 构成的,构建一种机器学习方法 (例如,支持向量机),就是具体去确定这三个要素. 1  支持向量机 支持向量机,简称 SVM (Support Vector Ma ...

  2. OpenStack 企业私有云的若干需求(6):大规模扩展性支持

    本系列会介绍OpenStack 企业私有云的几个需求: 自动扩展(Auto-scaling)支持 多租户和租户隔离 (multi-tenancy and tenancy isolation) 混合云( ...

  3. Codeforces Round #378 (Div. 2)

    A: 思路: 水题,没啥意思; B: 思路: 暴力,也没啥意思; C: 思路: 思维,可以发现从前往后和为b[i]的分成一块,然后这一块里面如果都相同就没法开始吃,然后再暴力找到那个最大的且能一开始就 ...

  4. CF732D. Exams[二分答案 贪心]

    D. Exams time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...

  5. AC日记——I Hate It 洛谷 P1531

    题目背景 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 题目描述 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的 ...

  6. dotnet core 出现Can not find runtime target for framework '.NETCoreApp,Version=v1.6' 的解决办法

    如果你在更新dotnet core新的类库后运行程序提示如下的错误: Can not find runtime target for framework '.NETCoreAPP, Version=v ...

  7. ThinkPHP常用配置路径

    //系统常量定义 //去THinkPHP手册中进行查找 echo "<br>"."网站的根目录地址".__ROOT__." "; ...

  8. Python-03-基础

    一.集合 集合(set)是一个无序的.不重复的元素组合,它的主要作用如下: 去重:把一个列表变成集合,就会自动去重. 关系测试:测试两组数据之前的交集.差集.并集等关系. 常用操作 # 创建数值集合 ...

  9. C++学习笔记(1)

    本学习笔记是C++ primer plus(第六版)学习笔记.复习C++基础知识的可以瞄瞄. 转载请注明出处http://www.cnblogs.com/zrtqsk/p/3874148.html,谢 ...

  10. 让游戏以高性能GPU(独立显卡)运行

    在EXE中导出全局变量: N卡: extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001 ...