• JSPatch学习笔记


    本文参考JSPatch wiki :https://github.com/bang590/JSPatch/wiki

    1.概念

    JSPatch是一个轻量的JS引擎,能够使用JavaScript语言来调用任何object-c接口,替换任何原生的方法。目前主要用于发步JS脚本替换原生Objective-C代码,实时修复线上bug

    2.原理

    利用OC语言的动态性,动态的修改类的方法和属性。在app启动的时候加载我们写好的JavaScript文件并通过JavaScriptCore来执行,用JS写好的类函数去篡改原有的OC函数。JSPatch只提供了篡改这个过程的代码,像部署线上Js代码、下载这些逻辑都得自己写。当然你可以用JSpatchSDK这个平台,这个平台帮我们部署JS代码、下载等一些逻辑。JSPatchSDK是收费的,也有免费版的。

    3.部署

    通过pod或者其他方式引入JSPatch,在didFinishLaunchingWithOptions函数加上如下代码:

    [JPEngine startEngine]; 
    NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"js"];
    NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];
    [JPEngine evaluateScript:script];

    部署完OC代码,我们就可以在index.js专心写JavaScript来修复线上的bug.

    4.写JS代码

    • defineClass 用来定义(覆盖)一个类
    • defineClass(classDeclaration, [properties,] instanceMethods, classMethods)
      
      classDeclaration:字符串类型,代表类名字
      properties:一个字符串数组,代表要添加的属性列表
      instanceMethods:实例方法
      classMethods:累方法
    • 下面是一个例子:
    • 包含了22个知识点,学会了这22个点,就能完成JSPatch的大部分工作了
    • 如果还有不明白的地方可以看官网
    • 1.appDelegate.m文件
    •     [JPEngine startEngine];
          NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"js"];
          NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];
          [JPEngine evaluateScript:script];
          
          
          self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
          
          UINavigationController * navi = [[UINavigationController alloc]initWithRootViewController:[[MainViewController alloc]initWithNibName:@"MainViewController" bundle:nil]];
          self.window.rootViewController = navi;
          [self.window makeKeyAndVisible];
    • 2.MainViewController.h
    • //
      //  MainViewController.h
      //  JSPatchDemo
      //
      //  Created by 朱国清 on 16/12/23.
      //  Copyright © 2016年 bang. All rights reserved.
      //
      
      #import <UIKit/UIKit.h>
      
      @interface MainViewController : UIViewController
      
      @property (nonatomic,strong) NSArray * testArray;
      @property (nonatomic,strong) NSDictionary * testDictionary;
      
      @end
    • 3.MainViewController.m
    • //
      //  MainViewController.m
      //  JSPatchDemo
      //
      //  Created by 朱国清 on 16/12/23.
      //  Copyright © 2016年 bang. All rights reserved.
      //
      
      #import "MainViewController.h"
      
      @interface MainViewController ()
      
      @property NSString * privateKey;
      
      @end
      
      @implementation MainViewController
      
      - (void)viewDidLoad {
          [super viewDidLoad];
          
          self.testArray      = @[@"Apple",@"Boy",@"Cat",@"Dog",];
          self.testDictionary = @{@"name":@"jack",@"age":@20};
          self.privateKey     = @"i am a private key";
      
          [self initUI];
          
      }
      // js 覆盖
      -(void)initUI{
          
          if (false) {
              UIButton * btn = [[UIButton alloc]initWithFrame:CGRectMake(10,30, 100, 30)];
              [btn setTitle:@"go" forState:UIControlStateNormal];
              [btn setBackgroundColor:[UIColor brownColor]];
              [btn addTarget:self action:@selector(handleButton) forControlEvents:UIControlEventTouchUpInside];
              
              
              
          }
      }
      
      -(void)handleButton{
          
      }
      
      -(void)testString:(NSString *)string{
          NSLog(@"testString : %@",string);
      }
      - (void)testPointer:(NSError **)error {
          NSError *err = [[NSError alloc]initWithDomain:@"com.jspatch" code:42 userInfo:nil];
          *error = err;
      }
      -(void)request:(void(^)(NSString *content, BOOL success))callback
      {
          callback(@"I'm content", YES);
      }
      typedef void (^JSBlock)(NSString *str);
      -(JSBlock)getBlock{
          JSBlock block = ^(NSString *str) {
              NSLog(@"I'm %@",str);
          };
          return block;
      }
      
      - (void)didReceiveMemoryWarning {
          [super didReceiveMemoryWarning];
      }
      
      @end
    • 4.index.js
    • defineClass(
          'MainViewController',
          {            
              viewWillAppear:function(animated){
                  // 1.调用父类 self.super()
                  self.super().viewWillAppear(animated);
                  // 2.设置navigationBarHidden属性值 .setNavigationBarHidden(true)
                  self.navigationController().setNavigationBarHidden(true);
              },
              initUI:function(){
                  
                  // 3.oc的NSString对象,在JS里面是Object
                  // 4.privateKey 为私有属性
                  var privateKey = self.valueForKey("privateKey");
                  self.testString(privateKey);            
                  console.log('privateKey:'+ privateKey);
      
                  // 5.OC NSArray
                  var item1 = self.testArray().objectAtIndex(0);
                  console.log('item1:'+item1.toString());
                  // 6.OC NSArray => JS array
                  var jsArray = self.testArray().toJS();
                  console.log('jsArray[0]:'+jsArray[0]);
                  // 7.OC NSDictionary 
                  var name1 = self.testDictionary().valueForKey('name');
                  console.log('name1:'+name1);
                  // 8.OC NSDictionary => JS json
                  var dic = self.testDictionary().toJS();
                  console.log('name2:'+dic['name']);
                          
                  // 10.获取属性 self.view()
                  // 11.获取一个类 require('UIColor')
                  self.view().setBackgroundColor(require('UIColor').grayColor());
                  /*
                      12.
                      特殊变量
                      point  {x:, y: }
                      size   {, height:}
                      CGRect {x:, y:, , height:}
                      range  {location:, length:}
                  */                
                  var btn = require('UIButton').alloc().initWithFrame({x:20, y:30, 100, height:30});
                  btn.setBackgroundColor(UIColor.brownColor());
                  // 13.多参数函数 [btn setTitle:forState:];以_代替: btn.setTitle_forState()
                  btn.setTitle_forState('go',0);
                  // 14.Selector 用字符代替 
                  btn.addTarget_action_forControlEvents(self,'handlePress',1 << 6);
                  self.view().addSubview(btn);
      
                  // 15.block无法使用self,需要保存一下
                  var slf = self;
                  // 16.
                  // 弱引用 var weakSelf = __weak(self)
                  // 强引用 var strongSelf = __strong(self)
      
                  // 17. block
                  // block  block的参数类型用字符串标示,block对象用NSBlock*类型            
                  /*
                      从 JS 传 block 到 OC,有两个限制:
                      A. block 参数个数最多支持6个。(若需要支持更多,可以修改源码)
                      B. block 参数类型不能是 double / NSBlock / struct 类型。
                  */
                  self.request(block("NSString *, BOOL", function(ctn, succ) {
                        if (succ) 
                            console.log(ctn)      //output: I'm content
                        
                        slf.testString("block self");
                        
                  }));
                  // 18. oc 返回的block就是一个js函数,可以直接调用
                  slf.getBlock()('JavaScrict');    
      
      
      
      
                  // 19.GCD
                  // JS
                  dispatch_after(1.0, function(){
                        console.log('dispatch_after 1s');
                  })
                  dispatch_async_main(function(){
                      console.log('dispatch_async_main');
                  })
                  dispatch_sync_main(function(){
                    console.log('dispatch_sync_main');
                  })
                  dispatch_async_global_queue(function(){
                    console.log('dispatch_async_global_queue');
                  })    
      
                  // 20.参入id * 指针
                  //malloc() pval() free() is provided by JPMemory extension
                  require('JPEngine').addExtensions(['JPMemory'])
                  var pError = malloc(sizeof("id"))
                  self.testPointer(pError)
                  var error = pval(pError)
                  if (!error) {
                      console.log("success")
                  } else {
                      console.log(error)
                  }
                  releaseTmpObj(pError)
                  free(pError)
              },
              handlePress:function(){
                  console.log('handlePress');
      
                  var vc = InfoViewController.alloc().init();
                  self.navigationController().pushViewController_animated(vc,true);
              }
          }
      )
      
      // 21.定义一个继承 UIViewController的类
      // 22.定义两个属性 url、info
      defineClass('InfoViewController : UIViewController',
          [
              'url',
              'info',
          ],
          {
              viewDidLoad:function(){
                  self.super().viewDidLoad();
                  self.navigationController().setNavigationBarHidden(false);
                  self.view().setBackgroundColor(require('UIColor').whiteColor());
                  self.setUrl('www.pingan.com.cn');
                  console.log(self.url());
                  
              }
              
          }
      );
       
  • 相关阅读:
    3D切割轮播图
    网站公共部分的复用
    Git的安装及布置
    完整轮播图
    百度检索例子
    第五章 pycharm编辑器安装和使用
    第四章 散列类型的方法
    第一章 认识爬虫以及环境安装
    主机访问Ubuntu虚拟机的jupyter
    12306购票的testerSunshine带源码刷票
  • 原文地址:https://www.cnblogs.com/shuigu/p/6215093.html
Copyright © 2020-2023  润新知