前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简单的 iOS 线上热修复方案

简单的 iOS 线上热修复方案

作者头像
molier
发布2022-11-03 08:53:42
8040
发布2022-11-03 08:53:42
举报
文章被收录于专栏:Molier的小站Molier的小站

# 向大佬致敬

总是喜欢把参考资料、致谢等写在文章最前面,毕竟是站在人家的肩膀上,向大佬致敬,写这篇文章的也是参考他的 然后加上一些自己的思考,主要目的还是自己再写一遍 Demo 和文档,以便加深记忆,也帮助自己更好的理解,有句话说:看懂的东西不一定就是学会了,自己能在不看资料的前提下写出来才算是略知一二。

以下是 ** 原文链接有兴趣的还可以看下大佬博客 **

# 工作原理分析

要实现热修复其实原理就是我们可以动态的修改代码,在方法前、中、后插入自己想要的东西或者代码。其实这个需求并不难,iOS 的运行时机制可以满足我们的这个要求,但是如果是已经上架了的 APP, 已经打成了 Ipa 包我们该如何修改呢?这里就需要服务端去控制,通过下发不同的内容来达到我们想要的目的,但是这里有一个要求,服务端所下发的内容并不能是任意的,而是要通过下发的内容调起我们 App 内的 RunTime 机制然后进行偷梁换柱。满足这个要求的数据格式只有字符串化的 JS 代码,因为我们知道在 iOS 中 JS 代码是可以调用 OC 的代码。综上所述打到热修复整套流程所需的技术如下:

  • Runtime: 可以在本站搜索 Runtime 关键字找到 Runtime 相关资料
  • 与服务器交互: 现在大部分 APP 都具有于服务端交互的能力,就是我们常说的网络请求 AFNetWorking 等
  • JS 与 OC 交互: 大家可以参考这篇文章,主要参考方式二,使用 JavaScriptCore 进行交互

进行了上述操作后每次用户启动,App 都会进行如下操作

这样一来如果开发在项目发布出去后发现有 Crash 那么可以立即通过服务器下发 JS 代码来制定 APp 每次执行新方法 (新方法的定义也是在下发的 JS 代码中),可以避免一些问题。

# 实际使用

# 第三方

这里用到一个第三方库 Aspects 这个库可以理解为一个 iOS 中的 Runtime 库,我们不用写繁琐的代码,直接调用他的接口即可,

代码语言:javascript
复制
+ (id<AspectToken>)aspect_hookSelector:(SEL)selector
                           withOptions:(AspectOptions)options
                            usingBlock:(id)block
                                 error:(NSError **)error;

其中的枚举就是选择我们要插入方法的位置,其中包含

代码语言:javascript
复制
typedef NS_OPTIONS(NSUInteger, AspectOptions) {
    AspectPositionAfter   = 0,            /// Called after the original implementation (default)
    AspectPositionInstead = 1,            /// Will replace the original implementation.
    AspectPositionBefore  = 2,            /// Called before the original implementation.

    AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.
};

这个库据说是对上线没有影响。

# 配置工程

用实际代码来证明下,这是我 Controller 中的一个代码,很明显会产生数组越界的 Crash,假如我们在上线后才发现了这个问题,这时候需要修复

代码语言:javascript
复制
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self crashMethod:0];

    // Do any additional setup after loading the view, typically from a nib.
}



- (void)crashMethod:(NSInteger)argument
{
    if (argument == 0) {
        NSArray * arr = @[@"1"];
        [arr objectAtIndex:2];
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

导入上面说的那个第三方.h 和.m 然后自己建立一个桥接类,用来处理 JS 和 O 的交互,大概的结构就是这样

其中交互类中暴露出如下接口

代码语言:javascript
复制
#import <Foundation/Foundation.h>
#import "Aspects.h"
#import <objc/runtime.h>
#import <JavaScriptCore/JavaScriptCore.h>
@interface Felix : NSObject

/**
 初始化
 */
+ (void)fixIt;


/**
 开始执行JS代码

 @param javascriptString 需要执行的JS
 */
+ (void)evalString:(NSString *)javascriptString;
@end

.m 文件的内容可以到大佬博客中参考这里不放出,不然篇幅太长。

# 开始使用

因为我们最好用能控制代码里面的所有方法,所以我们要尽早的注册交互类,在 APpdelegate 中如下注册

代码语言:javascript
复制
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.


    [Felix fixIt];
    NSString *fixScriptString = @" \
    fixInstanceMethodReplace('ViewController', 'crashMethod:', function(instance, originInvocation, originArguments){ \
    if (originArguments[0] == 0) { \
    console.log('crash!!!!!'); \
    } else { \
    runInvocation(originInvocation); \
    } \
    }); \
    \
    ";
    [Felix evalString:fixScriptString];

//    如果是多个方法建议用循环执行
//    NSArray * hotFixStr = @[fixScriptString];
//    for (int i = 0; i < hotFixStr.count; i ++) {
//        [Felix evalString:hotFixStr[i]];
//    }

    return YES;
}

其中 JS 的代码就是我们所要修改的内容,可以看到当参数为 0 的时候输出 crash!!!然后不再继续执行了。实际项目中这段代码是由服务器动态返回的,如果我们要修改多个方法,就需要服务器返回 JS 字符串数组我们这边来进行循环处理即可。这时候在运行下代码不会崩溃,下面会输出一个 crash!!!!

# 思考

这个方法相比较之前的 JSpatch 是非常轻量级的,而且也只是实现了简单的容错功能,并不能做一些复杂的操作,比如生成一个对象之类的,不过对于一般的控制已经可以满足了,毕竟在苹果爸爸这么严厉的管制下能有这样的方法也还不错啊。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-03-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 向大佬致敬
  • # 工作原理分析
  • # 实际使用
    • # 第三方
      • # 配置工程
        • # 开始使用
        • # 思考
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档