1 Star 0 Fork 0

ios_shen / OCRunner

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

OCRunner

Demo运行

直接下载zip,是无法正常运行的。必须通过git clone --recursive。

git clone --recursive https://github.com/SilverFruity/OCRunner.git

简介

OCRunner开发补丁的工作流

0

初衷

为了能够实现一篇文章的思路:Objective-C源码 -> 二进制补丁文件 ->热更新(具体是哪篇我忘了)。当时刚好开始了oc2mango翻译器的漫漫长路(顺带为了学习编译原理,嘻嘻),等基本完成以后,就开始肝OCRunner:完全兼容struct,enum,系统C函数调用,魔改libffi,生成补丁文件等,尽可能兼容Objective-C,为了做一个直接运行OC的快乐人。

各方职责

  • oc2mangoLib相当于一个简单的编译器,负责生成语法树
  • ORPatchFile负责将语法树序列化、反序列化和版本判断
  • PatchGenerator负责将oc2mangoLib和ORPatchFile的功能整合(以上工具都在oc2mango项目下)
  • OCRunner负责解释执行语法树

与其他库的区别

  • 下发二进制补丁文件。增加安全性,减小补丁大小,省去词法分析与语法分析,优化启动时间,可在PatchGenerator阶段进行优化

  • 自定义的Arm64 ABI (可以不使用libffi)

  • 完整的Objective-C语法支持,除去预编译和部分语法

本地使用OCRunner运行补丁

OCRunnerDemo可以作为整个流程的参照.

Cocoapods导入OCRunner

pod 'OCRunner'      #支持所有架构,包含libffi.a
# 或者
pod 'OCRunnerArm64' #仅支持 arm64和arm64e,没有libffi.a

下载 PatchGenerator

解压PatchGenerato.zip,然后将PatchGenerator保存到/usr/bin/或项目目录下.

添加PatchGenerator的 Run Script

  1. Project Setting -> Build Phases -> 左上角的 + -> New Run Script Phase

  2. PatchGenerator的路径 -files Objective-C源文件列表或者文件夹 -refs Objective-C头文件列表或者文件夹 -output 输出补丁保存的位置

  3. 比如OCRunnerDemo中的Run Script

    $SRCROOT/OCRunnerDemo/PatchGenerator -files $SRCROOT/OCRunnerDemo/ViewController1 -refs  $SRCROOT/OCRunnerDemo/Scripts.bundle -output $SRCROOT/OCRunnerDemo/binarypatch

开发环境下: 运行补丁

  1. 将生成的补丁文件作为资源文件添加到项目中

  2. Appdelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
#if DEBUG
    NSString *patchFilePath = [[NSBundle mainBundle] pathForResource:@"PatchFileName" ofType:nil];
#else
   // download from server
#endif
    [ORInterpreter excuteBinaryPatchFile:patchFilePath];
    return YES;
}
  1. 每次修改文件,记得Command+B,调用Run Scrip,重新生成补丁文件.

正式环境

  1. 将补丁上传到服务器
  2. App中下载补丁文件并保存到本地
  3. 使用**[ORInterpreter excuteBinaryPatchFile:PatchFilePath]** 执行补丁

使用介绍

引入结构体、枚举、typedef

可以通过修改OCRunnerDemo中的ViewController1,运行以下代码.

// 将添加一个名为dispatch_once_t的新类型
typedef NSInteger dispatch_once_t;
// link NSLog
void NSLog(NSString *format, ...);

typedef enum: NSUInteger{
    UIControlEventTouchDown                                         = 1 <<  0,
    UIControlEventTouchDownRepeat                                   = 1 <<  1,
    UIControlEventTouchDragInside                                   = 1 <<  2,
    UIControlEventTouchDragOutside                                  = 1 <<  3,
    UIControlEventTouchDragEnter                                    = 1 <<  4
}UIControlEvents;

int main(){
    UIControlEvents events = UIControlEventTouchDown | UIControlEventTouchDownRepeat;
    if (events & UIControlEventTouchDown){
        NSLog(@"UIControlEventTouchDown");
    }
    NSLog(@"enum test: %lu",events);
    return events;
}
main();

Tips:

推荐新建一个文件来放置以上代码,类似于OCRunnerDemo中的UIKitRefrence和GCDRefrence文件,然后使用PatchGenerator以**-links**的形式加入补丁生成。作者想偷偷懒,不想再去CV了,头文件太多了😭.

使用系统内置C函数

//you only need to add the C function declaration in Script.
//link NSLog
void NSLog(NSString *format, ...);

//then you can use it in Scrtips.
NSLog(@"test for link function %@", @"xixi");

当你运行以上代码时. OCRunner将会使用ORSearchedFunction 搜索函数的指针.

这个过程的核心实现是 SymbolSearch (修改自fishhook).

如果搜索到的结果是NULL,OCRunner将会自动在控制台打印如下信息:

|----------------------------------------------|
|you need add ⬇️ code in the application file |
|----------------------------------------------|
[ORSystemFunctionTable reg:@"dispatch_source_set_timer" pointer:&dispatch_source_set_timer];

修复OC对象(类)方法、添加属性

小天才英语学习机,不会哪里点哪里

想修复哪个方法,将改方法实现即可,不用实现其他方法.

@interface ORTestClassProperty:NSObject
@property (nonatomic,copy)NSString *strTypeProperty;
@property (nonatomic,weak)id weakObjectProperty;
@end
@implementation ORTestClassProperty
- (void)otherMethod{
    self.strTypeProperty = @"Mango";
}
- (NSString *)testObjectPropertyTest{
  	[self ORGtestObjectPropertyTest] //方法名前加'ORG'调用原方法
    [self otherMethod];
    return self.strTypeProperty;
}
@end

Block使用、解决循环引用

// 用于解决循环引用
__weak id object = [NSObject new];
// 最简block声明
void (^a)(void) = ^{
    int b = 0;
};
a();

使用GCD

本质就是 使用系统内置C函数,通过GCDRefrences文件添加,GCD相关的函数声明以及typedef皆在其中.

比如:

// link dispatch_sync
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
void main(){
  dispatch_queue_t queue = dispatch_queue_create("com.plliang19.mango",DISPATCH_QUEUE_SERIAL);
	dispatch_async(queue, ^{
   	completion(@"success");
	});
}
main();

使用内联函数、预编译函数

// 内联函数:在补丁中,添加一个全局函数中即可,比如UIKitRefrences中的CGRectMake
CGRect CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
  CGRect rect;
  rect.origin.x = x; rect.origin.y = y;
  rect.size.width = width; rect.size.height = height;
  return rect;
}
// 预编译函数:需要在App中预埋
[[MFScopeChain top] setValue:[MFValue valueWithBlock:^void(dispatch_once_t *onceTokenPtr,
                                                                  dispatch_block_t _Nullable handler){
        dispatch_once(onceTokenPtr,handler);
    }] withIndentifier:@"dispatch_once"];

如何确定补丁中是否包含源文件

1

查看Run Script打印的 InputFiles 中是否包含源文件.

性能测试

2

根据已知数据,OCRunner的补丁加载速度是JSPatch的20倍+,随着补丁大小的不断增加,这个倍数会不断增加。运行速度和内存占用与MangoFix差距不大。内存占用方面应该会更优,OCRunner中MFValue的值采用malloc来复制值,不会有多个类型的实例变量。

目前的问题

  1. 指针与乘号识别冲突问题,衍生的问题:类型转换等等
  2. 不支持static、inline函数声明
  3. 不支持C数组声明: type a[]和type a[2],以及 value = { 0 , 0 , 0 , 0 } 这种表达式
  4. 不支持 ‘->’ 操作符号
  5. 不支持C函数替换

支持语法

  1. 类声明与实现,支持分类写法
  2. Protocol
  3. Block语法
  4. 结构体、枚举、typedef
  5. 使用函数声明,链接系统函数指针
  6. 全局函数
  7. 多参数调用(方法和函数)
  8. *& (指针操作)
  9. 变量static关键字
  10. NSArray: @[value1, value2],NSDictionary: @{ key: value }, NSNumer: @(value)
  11. NSArray取值和NSDictionary取值和赋值语法,id value = a[var]; a[var] = value;
  12. 运算符,除去'->'皆已实现

... 等

目标

  • 完善当前的语法支持
  • 更多的单元测试覆盖(尽管目前显示是84%)
  • PatchGenerator阶段进行优化:未被调用的函数声明、结构体、枚举等,不会在补丁中,减少包大小以及加载时间等
  • 尝试Swift热更新(新建库吧,哈哈)
MIT License Copyright (c) 2020 Silver Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

暂无描述 展开 收起
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/ios_shen/OCRunner.git
git@gitee.com:ios_shen/OCRunner.git
ios_shen
OCRunner
OCRunner
master

搜索帮助