简介

  • 项目主页: https://github.com/bang590/JSPatch
  • 示例下载: https://github.com/ios122/ios122

JSPatch 可以让你用 JavaScript 书写原生 iOS APP。只需在项目引入极小的引擎,就可以使用 JavaScript 调用任何 Objective-C 的原生接口,获得脚本语言的优势:为项目动态添加模块,或替换项目原生代码动态修复 bug。

优势

  • 在项目中引入JSPatch,就可以在发现bug时下发JS脚本替换原生方法,可以做到无需更新整个APP即时修复bug!

  • JSPatch用iOS内置的 JavaScriptCore.framework作为引擎;JSPatch也符合苹果的规则。苹果不允许动态下发可执行代码,但通过苹果 JavaScriptCore.framework 或 WebKit 执行的代码除外,JS 正是通过 JavaScriptCore.framework 执行的。

  • JSPatch非常小巧

实例预览

@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{[JPEngine startEngine];NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"];NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];[JPEngine evaluateScript:script];self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];[self.window addSubview:[self genView]];[self.window makeKeyAndVisible];return YES;
}- (UIView *)genView
{return [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
}@end
// demo.js
require('UIView, UIColor, UILabel')
defineClass('AppDelegate', {// 替换这个 -genView 方法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;}
});

安装

通过Cocopods安装

pod 'JSPatch' # 在线更新应用.

手动导入

  1. 下载https://github.com/bang590/JSPatch并解压

  2. 复制JSPatch文件夹到你的工程

使用

objective-C:

  1. 导入头文件#import "JPEngine.h"

  2. 导入本地JS(demo.js)见文首github示例demo(可选,实际项目中,根据自己实际需要进行.)

  3. 调用[JPEngine startEngine] 加载引擎
  4. 通过[JPEngine evaluateScript:@""]接口执行 JavaScript。

[JPEngine startEngine];// 直接执行js
[JPEngine evaluateScript:@"\var alertView = require('UIAlertView').alloc().init();\alertView.setTitle('Alert');\alertView.setMessage('AlertView from js'); \alertView.addButtonWithTitle('OK');\alertView.show(); \
"];// 从网络拉回js脚本执行
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://cnbang.net/test.js"]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {NSString *script = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];[JPEngine evaluateScript:script];
}];// 执行本地js文件
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"js"];
NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];
[JPEngine evaluateScript:script];
// 另一个例子// 加载引擎
[JPEngine startEngine];//  本地JS,动态更新技术就是通过服务器获取JS更新这个JS
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"];
NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];
[JPEngine evaluateScript:script]

JavaScript:

基础使用方式

// 调用require引入要使用的OC类
require('UIView, UIColor, UISlider, NSIndexPath')// 调用类方法
var redColor = UIColor.redColor();// 调用实例方法
var view = UIView.alloc().init();
view.setNeedsLayout();// set proerty
view.setBackgroundColor(redColor);// get property
var bgColor = view.backgroundColor();// 多参数方法名用'_'隔开:
// OC:NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:1];
var indexPath = NSIndexPath.indexPathForRow_inSection(0, 1);// 方法名包含下划线'_',js用双下划线表示
// OC: [JPObject _privateMethod];
JPObject.__privateMethod()// 如果要把 `NSArray` / `NSString` / `NSDictionary` 转为对应的 JS 类型,使用 `.toJS()` 接口.
var arr = require('NSMutableArray').alloc().init()
arr.addObject("JS")
jsArr = arr.toJS()
console.log(jsArr.push("Patch").join(''))  //output: JSPatch// 在JS用字典的方式表示 CGRect / CGSize / CGPoint / NSRange
var view = UIView.alloc().initWithFrame({x:20, y:20, width:100, height:100});
var x = view.bounds.x;// block 从 JavaScript 传入 Objective-C 时,需要写上每个参数的类型。
// OC Method: + (void)request:(void(^)(NSString *content, BOOL success))callback
require('JPObject').request(block("NSString *, BOOL", function(ctn, succ) {if (succ) log(ctn)
}));// GCD
dispatch_after(function(1.0, function(){// do something
}))
dispatch_async_main(function(){// do something
})

详细文档请参考wiki页面:基础用法

定义类/替换方法

defineClass() 定义 Objective-C 的类,对类和实例方法进行动态替换。

// OC
@implementation JPTableViewController
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{NSString *content = self.dataSource[[indexPath row]];  //may cause out of boundJPViewController *ctrl = [[JPViewController alloc] initWithContent:content];[self.navigationController pushViewController:ctrl];
}
- (NSArray *)dataSource
{return @[@"JSPatch", @"is"];
}
- (void)customMethod
{NSLog(@"callCustom method")
}
@end
// JS
defineClass("JPTableViewController", {// instance method definitionstableView_didSelectRowAtIndexPath: function(tableView, indexPath) {var row = indexPath.row()if (self.dataSource().count() > row) {  //fix the out of bound bug herevar content = self.dataSource().objectAtIndex(row);var ctrl = JPViewController.alloc().initWithContent(content);self.navigationController().pushViewController(ctrl);}},dataSource: function() {// get the original method by adding prefix 'ORIG'var data = self.ORIGdataSource().toJS();return data.push('Good!');}
}, {})

详细文档请参考wiki页面:defineClass的用法

扩展

一些自定义的struct类型、C函数调用以及其他功能可以通过扩展实现,调用 +addExtensions: 可以加载扩展接口:

@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{[JPEngine startEngine];//添加扩展[JPEngine addExtensions:@[@"JPInclude", @"JPCGTransform"]];NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"];NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];[JPEngine evaluateScript:script];
}
include('test.js')   //`include()`方法在扩展 JPInclude.m 里提供
var view = require('UIView').alloc().init()//struct CGAffineTransform 类型在 JPCGTransform.m 里提供支持
view.setTransform({a:1, b:0, c:0, d:1, tx:0, ty:100})

扩展可以在JS动态加载,更推荐这种加载方式,在需要用到时才加载:

require('JPEngine').addExtensions(['JPInclude', 'JPCGTransform'])// `include()` and `CGAffineTransform` is avaliable now.

可以通过新增扩展为自己项目里的 struct 类型以及C函数添加支持,详情请见wiki页面:添加新扩展

安全性

JSPatch非常强大,因而最好将通过服务器获取JS的链接进行加密,本地JS也最好加密处理


注: 文章由我们 iOS122 的小伙伴 @偌一茗 整理,喜欢就一起参与: iOS122 任务池

转载于:https://www.cnblogs.com/ios122/p/4952112.html

JSPatch库, 一个Apple官方支持的实现在线更新iOS应用的库相关推荐

  1. android 监听媒体库,一个蛋疼的功能,监听android系统媒体库的变动

    思考了很久,最后决定写博客,这是我入android坑两年多以来的第一篇博客,如果写的不好,往见谅. 废话不多说,直接上菜!!! 最近遇到一个非常奇葩的功能,做一个类似相册类的应用,名曰:智能相册,涉及 ...

  2. iOS架构-静态库.framework脚本化打包补充(5)

    静态库.framework脚本化打包打包已经在iOS架构-静态库.framework手动打包及脚本化打包(5)中讲过.这里补充是通过Xcode 配置Aggregate自动执行脚本打包Framework ...

  3. 库到底是个啥?为啥要链接,链接库的本质又是个啥?

    目录 前言 一.库是个啥? ①最开始的库是用来解决啥问题? ②库的基本构成 ③动态库与静态库 二.如何生成库 0.相关知识 ①生成静态库 ②生成动态库 三.库的使用 ①修改环境变量 ②拷贝.so文件到 ...

  4. iOS架构-静态库.a 和.framework的区别(0)

    原文网址:https://my.oschina.net/kaqijiang/blog/649632 一.什么是库? 库是共享程序代码的方式. 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存 ...

  5. 一个已经存在 10 年,却被严重低估的库!

    来源 | 写代码的明哥 头图 | 下载于视觉中国 今天介绍的是一个已经存在十三年,但是依旧不红的库 decorator,好像很少有人知道他的存在一样. 这个库可以帮你做什么呢 ? 其实很简单,就是可以 ...

  6. 【Python】一个已经存在 10 年,却被严重低估的库

    今天介绍的是一个已经存在十三年,但是依旧不红的库 decorator,好像很少有人知道他的存在一样. 这个库可以帮你做什么呢 ? 其实很简单,就是可以帮你更方便地写python装饰器代码,更重要的是, ...

  7. 一个已经存在 10 年,却被严重低估的库

    今天介绍的是一个已经存在十三年,但是依旧不红的库 decorator,好像很少有人知道他的存在一样. 这个库可以帮你做什么呢 ? 其实很简单,就是可以帮你更方便地写python装饰器代码,更重要的是, ...

  8. 25个恶意JavaScript 库通过NPM官方包仓库分发

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 专栏·供应链安全 数字化时代,软件无处不在.软件如同社会中的"虚拟人",已经成为支撑社会正常运转的最基本元素之一,软件的安全 ...

  9. Apple官方优化Stable Diffusion绘画教程

    Apple官方优化Stable Diffusion绘画教程 苹果为M1芯片优化Stable Diffusion模型,其中Mac Studio (M1 Ultra, 64-core GPU)生成512* ...

最新文章

  1. java NIO详解
  2. python自定义随机数_python:numpy.random模块生成随机数
  3. move函数c语言,C++11 move()函数:将左值强制转换为右值
  4. SpringBoot自动装载
  5. 一篇带你了解函数指针
  6. C++Heap Sort堆排序的实现算法(附完整源码)
  7. 商务英语如何利用计算机思维,如何更好的运用商务英语
  8. sqlserver 查询表锁死,解除表锁死
  9. CountDownLatch 多线程使用示例
  10. SATA接口Raid、AHCI、IDE三种模式
  11. cmd命令行查看wifi密码
  12. 会议安排(经典贪心算法例题)
  13. CS客户端渗透测试(二)信息收集与流量分析
  14. 7个实用的Python自动化代码,别再重复造轮子了!
  15. ECS服务器10M带宽能让多少人同时访问?
  16. 白苹果了怎么强制开机_苹果手机开机卡在开机界面怎么办?
  17. Kaggle 大神 Eureka 的高手进阶之路
  18. php alpine postgres,docker环境下搭建使用postgresql10
  19. 并联串联混合的电压和电流_并联型的有源滤波器能够有多少种用法?
  20. 爆破3389密码:目标主机Win2008(私有IP为192.168.1.167)开放3389端口,使用kali中的Hydra爆破密码。

热门文章

  1. php在图片左上角加入水印,如何在PHP中将图像添加到图像上,如水印
  2. 埃及分数怎么计算java_贪心算法之埃及分数问题(附c++源代码)
  3. 拓扑排序排课系统_木犀互联网技术周刊(第四十五期): 分布式系统简介
  4. python从html中提取文本_使用Python从HTML中提取可读文本?
  5. python全局变量可以改变吗_在Python中避免我的全局变量,我有几个函数可以改变一个变量...
  6. python在linux编程_python要在linux下编程吗
  7. pytorch模型转onnx遇到的问题记录
  8. python函数编程实例_Python函数式编程实例详解
  9. java8 comparator接口_Java8 Comparator 排序方法
  10. centos7删除符号链接_如何在 Linux 上查找和删除损坏的符号链接 | Linux 中国