JSPatch學習筆記

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

1.概念

JSPatch是一個輕量的JS引擎,可以使用JavaScript語言來調用任何object-c接口,替換任何原生的方法。目前主要用於發步JS腳本替換原生Objective-C代碼,實時修復線上buggit

2.原理

利用OC語言的動態性,動態的修改類的方法和屬性。在app啓動的時候加載咱們寫好的JavaScript文件並經過JavaScriptCore來執行,用JS寫好的類函數去篡改原有的OC函數。JSPatch只提供了篡改這個過程的代碼,像部署線上Js代碼、下載這些邏輯都得本身寫。固然你能夠用JSpatchSDK這個平臺,這個平臺幫咱們部署JS代碼、下載等一些邏輯。JSPatchSDK是收費的,也有免費版的。github

3.部署

經過pod或者其餘方式引入JSPatch,在didFinishLaunchingWithOptions函數加上以下代碼:web

[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.json

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   {width:, height:}
                    CGRect {x:, y:, width:, height:}
                    range  {location:, length:}
                */                
                var btn = require('UIButton').alloc().initWithFrame({x:20, y:30, width: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());
                
            }
            
        }
    );
     
相關文章
相關標籤/搜索