亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS中使用JSPatch框架使Objective-C與JavaScript代碼交互

2020-07-26 03:19:27
字體:
來源:轉載
供稿:網友

JSPatch是GitHub上一個開源的框架,其可以通過Objective-C的run-time機制動態的使用JavaScript調用與替換項目中的Objective-C屬性與方法。其框架小巧,代碼簡潔,并且通過系統的JavaScriptCore框架與Objective-C進行交互,這使其在安全性和審核風險上都有很強的優勢。Git源碼地址:https://github.com/bang590/JSPatch。

一、從一個官方的小demo看起

通過cocoapods將JSPath集成進一個Xcode工程中,在AppDelegate類的中編寫如下代碼:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  //開始初始化引擎  [JPEngine startEngine];  //讀取js文件  NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"];  NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];  //運行js文件  [JPEngine evaluateScript:script];  self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];  self.window.rootViewController = [[ViewController alloc]init];  [self.window addSubview:[self genView]];  [self.window makeKeyAndVisible];  return YES;}- (UIView *)genView{  UIView * view= [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];  view.backgroundColor = [UIColor redColor];  return view;}

在工程中添加一個js文件,編寫如下:

  

 require('UIView, UIColor, UILabel')  //要替換函數的類  defineClass('AppDelegate', {      //替換函數        //要替換函數的名稱        genView: function() {          var view = self.ORIGgenView();          view.setBackgroundColor(UIColor.greenColor())          var label = UILabel.alloc().initWithFrame(view.frame());          label.setText("JSPatch");          label.setTextAlignment(1);          view.addSubview(label);          return view;      }  });

運行工程,可以看到genView方法被替換成了js文件中的方法,原本紅色的視圖被修改成了綠色。

二、使用JavaScript代碼向Objective-C中修改或添加方法

JSPatch引擎中支持3中方式進行JavaScript代碼的調用,分別是使用JavaScript字符串進行代碼運行,讀取本地的JavaScript文件進行代碼運行和獲取網絡的JavaScript文件進行代碼運行。例如,如果想要通過JavaScript代碼在項目中彈出一個警告框,在Objective-C代碼中插入如下代碼:

- (void)viewDidLoad {  [super viewDidLoad];  // ‘/'符用于進行換行  [JPEngine evaluateScript:@"/   var alertView = require('UIAlertView').alloc().init();/   alertView.setTitle('Alert');/   alertView.setMessage('AlertView from js'); /   alertView.addButtonWithTitle('OK');/   alertView.show(); /   "];}

開發者也可以動態在Objective-C類文件中添加方法,例如在ViewController類中編寫如下:

- (void)viewDidLoad {  [super viewDidLoad];  self.view.backgroundColor = [UIColor whiteColor];  [JPEngine startEngine];  NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"];  NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];  [JPEngine evaluateScript:script];  [self performSelectorOnMainThread:@selector(creatView) withObject:nil waitUntilDone:nil];}

JavaScript文件代碼如下:

 require('UIView, UIColor, UILabel')  defineClass('ViewController', {      // replace the -genView method        creatView: function() {          var view = UIView.alloc().initWithFrame({x:20, y:20, width:100, height:100});          view.setBackgroundColor(UIColor.greenColor());          var label = UILabel.alloc().initWithFrame({x:0, y:0, width:100, height:100});          label.setText("JSPatch");          label.setTextAlignment(1);          view.addSubview(label);        self.view().addSubview(view)      }  });

除了上面的代碼,在ViewController.m文件中沒有編寫任何其他的方法,運行工程,可以看到程序并沒有崩潰,ViewController執行了creatView方法。

通過上面的示例,我們發現使用JSPatch可以做一些十分有趣的事。對于iOS應用來說,通過官方渠道AppStore進行應用程序的發布要通過人工審核,有時這個審核周期會非常長,如果在開發者在編寫代碼時留下了一些小漏洞,應用一旦上線,若要修改掉這個bug就十分艱難了。有了JSPatch,我們可以想象,如果可以定位到線上應用有問題的方法,使用JS文件來修改掉這個方法,這將是多么cool的一件事,事實上,JSPatch的主要用途也是可以實現線上應用極小問題的hotfix。

三、JavaScript與Objective-C交互的基礎方法

要使用JSPatch來進行Objective-C風格的方法編寫,需要遵守一些JavaScript與Objective-C交互的規則。

1.在JavaScript文件中使用Objective-C類

在編寫JavaScript代碼時如果需要用到Objective-C的類,必須先對這個類進行require引用,例如,如果需要使用UIView這個類,需要在使用前進行如下引用:

require('UIView')

同樣也可以一次對多個Objective-C類進行引用:

require('UIView, UIColor, UILabel')

還有一種更加簡便的寫法,直接在使用的時候對其進行引用:

require('UIView').alloc().init()

2.在JavaScript文件中進行Objective-C方法的調用

在進行Objective-C方法的調用時,分為兩種,一種是調用類方法,一種是調用類的對象方法。

調用類方法:通過類名打點的方式來調用類方法,格式類似如下,括號內為參數傳遞:

UIColor.redColor()

調用實例方法:通過對象打點的方式調用類的實例方法,格式如下,括號內為參數傳遞:

view.addSubview(label)

對于Objective-C中的多參數方法,轉化為JavaScript將參數分割的位置以_進行分割,參數全部放入后面的括號中,以逗號分割,示例如下:

view.setBackgroundColor(UIColor.colorWithRed_green_blue_alpha(0,0.5,0.5,1))
對于Objective-C類的屬性變量,在JavaScript中只能使用getter與setter方法來訪問,示例如下:

label.setText("JSPatch")

提示:如果原Objective-C的方法中已經包含了_符號,則在JavaScript中使用__代替。

3.在JavaScript中操作與修改Objective-C類

JSPatch的最大應用是在應用運行時動態的操作和修改類。

重寫或者添加類的方法:

在JavaScript中使用defineClass來定義和修改類中的方法,其編寫格式如下所示:

/*classDeclaration:要添加或者重寫方法的類名 字符串 如果此類不存在 則會創建新的類instanceMethods:要添加或者重寫的實例方法 {}classMethods:要添加或者重寫的類方法 {}*/defineClass(classDeclaration, instanceMethods, classMethods)

示例如下:

defineClass('ViewController', {      // replace the -genView method        newFunc: function() {          //編寫實例方法          self.view().setBackgroundColor(UIColor.redColor())        }        },{        myLoad:function(){          //編寫類方法        }      }      )

如果在重寫了類中的方法后要調用原方法,需要使用ORIG前綴,示例如下:

defineClass('ViewController', {      // replace the -genView method        viewDidLoad: function() {          //編寫實例方法          self.ORIGviewDidLoad()        }        }      )

對于Objective-C中super關鍵字調用的方法,在JavaScript中可以使用self.super()來調用,例如:

defineClass('ViewController', {      // replace the -genView method        viewDidLoad: function() {          //編寫實例方法          self.super().viewDidLoad()        }        }      )

同樣JSPatch也可以為類添加臨時屬性,用于在方法間參數傳遞,使用set_Prop_forKey()來添加屬性,使用getProp()來獲取屬性,注意,JSPatch添加的屬性不能使用Objective-C的setter與getter方法訪問,如下:

defineClass('ViewController', {      // replace the -genView method        viewDidLoad: function() {          //編寫實例方法          self.super().viewDidLoad()          self.setProp_forKey("JSPatch", "data")        },        touchesBegan_withEvent(id,touch){          self.getProp("data")          self.view().setBackgroundColor(UIColor.redColor())        }        }      )

關于為類添加協議的遵守,和Objective-C中遵守協議的方式一致,如下:

defineClass("ViewController2: UIViewController <UIAlertViewDelegate>", {      viewDidAppear: function(animated) {      var alertView = require('UIAlertView')      .alloc()      .initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles(                                        "Alert",                                        "content",                                        self,                                        "OK",                                        null                                        )      alertView.show()      },      alertView_clickedButtonAtIndex:function(alertView, buttonIndex) {      console.log('clicked index ' + buttonIndex)      }      })

四、JavaScript與Objective-C交互的幾種常用類型

1.結構體

在Objective-C代碼中,我們經常會使用到結構體,JSPatch中原生支持的結構體有如下幾種:CGPoint,CGSize,CGRect,NSRange。并且這幾種結構體在進行界面操作時也會經常使用到。

對于CGRect類型,JavaScript使用如下代碼創建:

  var view = require('UIView').alloc().init()  view.setFrame({x:100,y:100,width:100,height:100})

對于CGPoint類型,JavaScript使用如下代碼創建:

   

view.setCenter({x:200,y:200})

對于CGSize類型,JavaScript使用如下代碼創建:

  var size = {width:200,height:200}  view.setFrame({x:100,y:100,width:size.width,height:size.height})

對于NSRange類型,JavaScript使用如下代碼創建:

  var range = {location: 0, length: 1}

2.選擇器Selector

對于Objective-C中的方法選擇器Selector,在JavaScript中使用字符串的形式創建,例如:

self.performSelector_withObject("func:", 1)

3.關于空對象

在JavaScript中,null與undefined都對應于Objective-C中的nil,Objective-C中的NSNull空對象,在JavaScript中使用nsnull來代替。

4.在Objective-C與JavaScript中進行block的交互

在JavaScript與Objective-C進行block交互有兩種方式,一種是在JavaScript文件中調用Objective-C中的block,一種是將JavaScript文件中的函數塊作為block參數傳遞給Objective-C。

在JavaScript文件中使用Objective-C中的block十分簡單,因為JavaScript中沒有block的概念,Objective-C會被自動轉換為函數,示例如下:

Objective-C:

typedef void(^block)(NSString * str);@interface ViewController ()@end@implementation ViewController-(block)getBlock{  block block = ^(NSString * str){NSLog(@"%@",str);};  return block;}@end

JavaScript:

defineClass("ViewController", {      viewDidAppear: function(animated) {       var func = self.getBlock()        func("123")      }      })

在JavaScript文件中將func作為參數block傳遞給Objective-C就復雜一些,需要使用block()方法進行包裝,例如:

Objective-C:

@interface ViewController ()@end@implementation ViewController-(void)run:(void(^)(NSString * str))block{  block(@"123");}@end

JavaScript:

defineClass("ViewController", {      viewDidAppear: function(animated) {      //run 方法中需要傳入一個block      self.run(block("NSString*",function(str){console.log(str)}))      }      })

在使用block()方法對JavaScript中的Func進行包裝時,block(param1,param2)有兩個參數,第1個參數設置func中的參數類型,如果有多個參數,使用逗號分割;第2個參數為func函數體。

注意:在block()包裝的func中不可以使用self指針,如果需要使用self,需要在block外進行臨時變量的轉換,示例如下:

defineClass("ViewController", {      viewDidAppear: function(animated) {      //run 方法中需要傳入一個block      var slf = self      self.run(block("NSString*",              function(str){              console.log(str)              slf.log(str)              }))      }      })

在JavaScript中分別使用__weak()與__strong來聲明弱引用與強引用對象,例如:

 var slf = __weak(self) var stgSef = __strong(self)

5.關于GCD與枚舉

在JSPatch中,可以使用如下JavaScript代碼來調用GCD方法:

//阻塞當前線程一定時間dispatch_after(1.0, function(){ })//為主線程添加異步任務dispatch_async_main(function(){ })//為主線程添加同步任務dispatch_sync_main(function(){ })//向全局隊列中添加任務dispatch_async_global_queue(function(){ })JSPatch中不可以直接使用Objective-C中定義的枚舉,但是可以用其枚舉的真實值進行傳遞。例如://UIControlEventTouchUpInside的值是1<<6btn.addTarget_action_forControlEvents(self, "handleBtn", 1<<6);

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品狼人色视频一区| 欧美一级大胆视频| 高清日韩电视剧大全免费播放在线观看| 中文字幕亚洲二区| 97**国产露脸精品国产| 懂色av中文一区二区三区天美| 最新69国产成人精品视频免费| 国产一区二区在线免费视频| 亚洲sss综合天堂久久| 欧美日韩免费看| 国产精品免费视频久久久| 亚洲男人天堂网站| 黄色成人在线免费| 91日韩在线视频| 97国产真实伦对白精彩视频8| 日韩中文字幕视频在线观看| 亚洲色图在线观看| 成人97在线观看视频| 性欧美视频videos6一9| 国产日韩在线看| 亚洲成年人在线| 日韩欧美大尺度| 亚洲精品丝袜日韩| 九九热视频这里只有精品| 久久久伊人日本| 亚洲精品videossex少妇| 成人女保姆的销魂服务| 日韩精品在线观| 亚洲毛片在线免费观看| 欧美xxxx综合视频| 亚洲有声小说3d| 国产在线一区二区三区| 日韩欧美999| 国产剧情久久久久久| 久久亚洲成人精品| 久久在线观看视频| 亚洲精品国产电影| 亚洲色图50p| 伦理中文字幕亚洲| 日本午夜人人精品| 亚洲国语精品自产拍在线观看| 青青久久av北条麻妃黑人| 日韩精品极品在线观看播放免费视频| 在线观看亚洲区| 成人免费直播live| 国产精品亚洲精品| 国产日韩换脸av一区在线观看| 91久久精品国产91久久性色| 欧美天天综合色影久久精品| 欧美大尺度激情区在线播放| 久久精品国产69国产精品亚洲| 久久久综合av| 91香蕉嫩草神马影院在线观看| 国产aaa精品| 欧美专区在线视频| 亚洲精品福利视频| 国产91精品久久久| 日韩欧美福利视频| 国产精品福利在线观看| 国产成人97精品免费看片| 国产精品永久免费视频| 性色av一区二区三区免费| 欧美午夜女人视频在线| 国产精品揄拍一区二区| 国产成人精品一区| 久久久精品国产一区二区| 日韩最新免费不卡| 亚洲午夜小视频| 欧美综合在线观看| 亚洲自拍偷拍区| 日韩中文字幕av| 亚洲激情免费观看| 欧美日韩国产精品一区二区不卡中文| 亚洲视频欧洲视频| 久久久久亚洲精品| 精品精品国产国产自在线| 欧美猛少妇色xxxxx| 国产成人精品999| 久久精品久久久久电影| 日韩成人在线免费观看| 国产日韩欧美在线观看| 91色在线观看| 综合激情国产一区| 国产aaa精品| 好吊成人免视频| 久久久久久91香蕉国产| 亚洲成年人在线| 欧美成人国产va精品日本一级| 亚洲天堂av高清| 韩剧1988免费观看全集| 一区二区三区无码高清视频| 在线视频欧美性高潮| 色综合久久中文字幕综合网小说| 97在线视频精品| 色狠狠久久aa北条麻妃| 中文字幕欧美日韩va免费视频| 国产一区私人高清影院| 欧美激情精品久久久久久蜜臀| 亚洲精品电影在线观看| 日韩国产精品亚洲а∨天堂免| 欧美福利在线观看| 国产精品丝袜白浆摸在线| 亚洲片av在线| 青青在线视频一区二区三区| 久久久久久久一区二区| 中文字幕综合在线| 日韩美女在线看| 美女精品久久久| 亚洲美女精品成人在线视频| 国内精品一区二区三区四区| 日韩中文字幕精品视频| 久久精品在线视频| 日本高清不卡的在线| 日韩av手机在线看| 深夜福利日韩在线看| 国产美女直播视频一区| 大伊人狠狠躁夜夜躁av一区| 国产成+人+综合+亚洲欧美丁香花| 日韩www在线| 国产精品久久久久久久久久| 韩剧1988在线观看免费完整版| 九九精品在线观看| 成人情趣片在线观看免费| 欧美激情亚洲激情| 97视频免费在线观看| 国产福利视频一区二区| 国产精品一久久香蕉国产线看观看| 国产精品久久久久久av福利| 精品中文视频在线| 欧美激情精品久久久久久大尺度| 国色天香2019中文字幕在线观看| 色综合天天综合网国产成人网| 成人国产在线视频| 日韩免费观看av| 日本aⅴ大伊香蕉精品视频| 日韩av在线精品| 久久夜色精品亚洲噜噜国产mv| 中文字幕日本精品| 久久精品一本久久99精品| 亚洲精品丝袜日韩| 久久久亚洲欧洲日产国码aⅴ| 欧美一级成年大片在线观看| 国产欧美精品一区二区| 日韩视频亚洲视频| 亚洲国产精品va在线| 国产精品美女无圣光视频| 国产精品吴梦梦| 深夜福利亚洲导航| 久久精品久久久久久| 日韩免费观看网站| 欧美激情亚洲一区| 国产欧美一区二区| 久热精品视频在线观看| 欧美日韩国产在线| 国产综合在线观看视频| 国产女人18毛片水18精品| 亚洲国产成人久久综合一区| 欧美视频精品一区| 日韩欧美精品网站| 欧美高清不卡在线| 精品国产乱码久久久久久虫虫漫画| 欧美激情性做爰免费视频| 久久久综合免费视频| 成人免费观看网址|