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":@};
self.privateKey = @"i am a private key"; [self initUI]; }
// js 覆盖
-(void)initUI{ if (false) {
UIButton * btn = [[UIButton alloc]initWithFrame:CGRectMake(,, , )];
[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: 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();
console.log('item1:'+item1.toString());
// 6.OC NSArray => JS array
var jsArray = self.testArray().toJS();
console.log('jsArray[0]:'+jsArray[]);
// 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:, y:, width:, height:});
btn.setBackgroundColor(UIColor.brownColor());
// 13.多参数函数 [btn setTitle:forState:];以_代替: btn.setTitle_forState()
btn.setTitle_forState('go',);
// 14.Selector 用字符代替
btn.addTarget_action_forControlEvents(self,'handlePress', << );
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()); } }
);
JSPatch学习笔记的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
随机推荐
- 【C#】时间戳转换
今天有时间戳转换的需求,网上找了半天才找到相关代码,经测试有效,特作此笔记和大家分享! 1.时间戳转为C#格式时间 /// <summary> /// 时间戳转为C#格式时间 /// &l ...
- Visual Studio 2015 Update 3 正式版下载
vs2015-update3 .NET Core 1.0 文件名 cn_visual_studio_enterprise_2015_with_update_3_x86_x64_dvd_8923 ...
- R 操作矩阵和计算SVD的基本操作记录
在R中可以用函数matrix()来创建一个矩阵,应用该函数时需要输入必要的参数值. > args(matrix) function (data = NA, nrow = 1, ncol = 1, ...
- 数据库备份checksum选项你会用么?
SQL SERVER有好多好多功能,选项也一大堆,很多功能选项并不常用.但是如果真有这种需求的时候又想不起来~ 本篇我们就来聊聊备份里的选项checksum,这是个啥玩意?听都没听过?来看下图: 就是 ...
- YbSoftwareFactory 代码生成插件【十六】:Web 下灵活、强大的审批流程实现(含流程控制组件、流程设计器和表单设计器)
程序=数据结构+算法,而企业级的软件=数据+流程,流程往往千差万别,客户自身有时都搞不清楚,随时变化的情况更是家常便饭,抛开功能等不谈,需求变化很大程度上就是流程的变化,流程的变化会给开发工作造成很大 ...
- babel6 的 export default bug
把export default 变成 module.exports 就行了
- Weblogic日志机制详解
服务器日志 每个 WebLogic Server 实例将来自子系统和应用程序的所有消息写入位于本地主机上的服务器日志文件.默认情况下,服务器日志文件位于服务器实例根目录下的 logs 目录中:例如, ...
- Java设计模式(一)——代理模式
有高手云:了解设计模式才算是入门级的程序员. 所以为了入门我打算把我学习到的设计模式逐条总结下来.和别人的文章不同,我几乎只提供了测试源码与细节分类.原因是,我相信对于设计来说,你永远无法给出终极答案 ...
- maven国内镜像(maven下载慢的解决方法)
Maven是当前流行的项目管理工具,但官方的库在国外经常连不上,连上也下载速度很慢.国内oschina的maven服务器很早之前就关了.今天发现阿里云的一个中央仓库,亲测可用. <mirror& ...
- HTML5的Video标签的属性,方法和事件汇总
<video>标签的属性 src :视频的属性 poster:视频封面,没有播放时显示的图片 preload:预加载 autoplay:自动播放 loop:循环播放 controls:浏览 ...