JSPatch

JSPatch

原理:在APP启动的时候,通过JavaScrptCore来执行编写的JavaScript脚本,利用OC的运行时特性来修改类的方法和属性。

1:执行JS脚本

#import "AppDelegate.h"
// 导入JSPatch框架
#import <JSPatch/JPEngine.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [Bugly startWithAppId:BuglyAppId];
    [JPEngine startEngine];
//    加载本地的JS文件
//    NSString *path = [[NSBundle mainBundle] pathForResource:@"firstChange" ofType:@"js"];
//    NSString *script = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//    [JPEngine evaluateScript:script];

// 记载请求的JS文件
    [[FFNetworkHelper share] GetFile:[NSString stringWithFormat:@"xxx/%@", @"firstChange.js"] successBlock:^(id  _Nonnull responseObject) {
        [JPEngine evaluateScript:responseObject];
    } failuerBlock:^(NSString * _Nonnull str) {
#if DEBUG
        FFShowInfo(@"JS 修复文件下载失败");
#endif
    }];
    
    self.window = [[UIWindow alloc] initWithFrame:MainScreenBounds];                                                   
s self.window.rootViewController = [self FF_GetTabBarController]; [self.window makeKeyAndVisible]; return YES; }

2: 在动态修改OC类的方法和属性时的核心方法 defineClass('className', instanceMethod, classMethod)

   className--要覆盖的类名,字符串类型

   instanceMethod--实例方法

   classMethod--类方法(要修改类方法,必须有实例方法,如果实例方法省略,就会默认为instanceMethod)

/*
##API

defineClass(classDeclaration, instanceMethods, classMethods)

@param classDeclaration: class name, super classname and protocols
@param instanceMethods: instance methods you want to override or add
@param classMethods: class methods you want to override or add



1.Use _ to separate multiple params: 使用_链接多个参数

2.Use __ to represent _ in the Objective-C method name: 如果原来的方法名中有_用__代替

3.Call original method by adding prefix ORIG to the method name. 如果想调用OC中对应的初始方法,添加前缀ORIG

4.Super / Property / Member variables
    a: Use self.super() to call super methods. 使用self.super()调用super method
    b: Call methods to get / set existing property. 通过get / set 方法来操作存在的属性
        // JS
        defineClass("JPTableViewController", {
              viewDidLoad: function() {
                 var data = self.data()     //get property value
                 self.setData(data.toJS().push("JSPatch"))     //set property value
              },
        })
    c: Use getProp() and setProp_forKey() to get / set new property 通过getProp() 和 setProp_forKey()来get / set 一个新属性
        // JS
        defineClass("JPTableViewController", {
          init: function() {
             self = self.super().init()
             self.setProp_forKey("JSPatch", "data")     //add new property (id data)
             return self;
          }
          viewDidLoad: function() {
             var data = self.getProp("data")     //get the new property value
          },
        })
    d: Use valueForKey() and setValue_forKey() to get / set member variables 成员变量操作
       // JS
        defineClass("JPTableViewController", {
          viewDidLoad: function() {
             var data = self.valueForKey("_data")     //get member variables
             self.setValue_forKey(["JSPatch"], "_data")     //set member variables
          },
        })
5.You can add new methods to the existing Class, if you want to call the new method in Objective-C, all the params type is id.
  在已经存在的类中添加一个新方法,在OC中回调是,参数是id类型

6.Special types
  Use hash object to represent CGRect / CGPoint / CGSize / NSRange
  // JS
    var view = UIView.alloc().initWithFrame({x:20, y:20, 100, height:100})
    view.setCenter({x: 10, y: 10})
    view.sizeThatFits({ 100, height:100})

    var x = view.frame.x
    var range = {location: 0, length: 1}

 

*/

/// 要用到的类,用require导入
require('UIView, NSString, NSDate, NSLog')
/// 要重载的类, 修改viewDidLoad方法
defineClass(
    'FFBaseViewController',
    {
        /// 实例方法
        viewDidLoad: function(){
            /// self.super() 回调 super method
            self.super().viewDidLoad();
            /// 要执行的操作
            ...

        };
    })

/// 要重载的类, 调用viewDidLoad方法
defineClass(
    'FFBaseViewController',
    {
        /// 实例方法
        viewDidLoad: function(){
            /// self.super() 回调 parent method
            self.ORIGviewDidLoad();
            /// 要执行的操作
            ...

        };
    })

/// 要重载的类, 修改viewDidLoad方法, 添加一个类方法FFPrint
defineClass(
    'FFBaseViewController',
    {
        /// 实例方法
        viewDidLoad: function(){
            /// self.super() 回调 parent method
            self.super().viewDidLoad();
            /// 要执行的操作
            ...

        };
    },
    {
        /// 类方法
        FFPrint: functon(){
            NSLog('类方法');
        }
    }
)

  

原文地址:https://www.cnblogs.com/jisa/p/10792483.html