JSPatch库, 一个Apple官方支持的实现在线更新iOS应用的库
简介
- 项目主页: 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' # 在线更新应用.
手动导入
下载https://github.com/bang590/JSPatch并解压
复制JSPatch文件夹到你的工程
使用
objective-C:
导入头文件#import "JPEngine.h"
导入本地JS(demo.js)见文首github示例demo(可选,实际项目中,根据自己实际需要进行.)
- 调用
[JPEngine startEngine]
加载引擎 通过
[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应用的库相关推荐
- android 监听媒体库,一个蛋疼的功能,监听android系统媒体库的变动
思考了很久,最后决定写博客,这是我入android坑两年多以来的第一篇博客,如果写的不好,往见谅. 废话不多说,直接上菜!!! 最近遇到一个非常奇葩的功能,做一个类似相册类的应用,名曰:智能相册,涉及 ...
- iOS架构-静态库.framework脚本化打包补充(5)
静态库.framework脚本化打包打包已经在iOS架构-静态库.framework手动打包及脚本化打包(5)中讲过.这里补充是通过Xcode 配置Aggregate自动执行脚本打包Framework ...
- 库到底是个啥?为啥要链接,链接库的本质又是个啥?
目录 前言 一.库是个啥? ①最开始的库是用来解决啥问题? ②库的基本构成 ③动态库与静态库 二.如何生成库 0.相关知识 ①生成静态库 ②生成动态库 三.库的使用 ①修改环境变量 ②拷贝.so文件到 ...
- iOS架构-静态库.a 和.framework的区别(0)
原文网址:https://my.oschina.net/kaqijiang/blog/649632 一.什么是库? 库是共享程序代码的方式. 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存 ...
- 一个已经存在 10 年,却被严重低估的库!
来源 | 写代码的明哥 头图 | 下载于视觉中国 今天介绍的是一个已经存在十三年,但是依旧不红的库 decorator,好像很少有人知道他的存在一样. 这个库可以帮你做什么呢 ? 其实很简单,就是可以 ...
- 【Python】一个已经存在 10 年,却被严重低估的库
今天介绍的是一个已经存在十三年,但是依旧不红的库 decorator,好像很少有人知道他的存在一样. 这个库可以帮你做什么呢 ? 其实很简单,就是可以帮你更方便地写python装饰器代码,更重要的是, ...
- 一个已经存在 10 年,却被严重低估的库
今天介绍的是一个已经存在十三年,但是依旧不红的库 decorator,好像很少有人知道他的存在一样. 这个库可以帮你做什么呢 ? 其实很简单,就是可以帮你更方便地写python装饰器代码,更重要的是, ...
- 25个恶意JavaScript 库通过NPM官方包仓库分发
聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 专栏·供应链安全 数字化时代,软件无处不在.软件如同社会中的"虚拟人",已经成为支撑社会正常运转的最基本元素之一,软件的安全 ...
- Apple官方优化Stable Diffusion绘画教程
Apple官方优化Stable Diffusion绘画教程 苹果为M1芯片优化Stable Diffusion模型,其中Mac Studio (M1 Ultra, 64-core GPU)生成512* ...
最新文章
- java NIO详解
- python自定义随机数_python:numpy.random模块生成随机数
- move函数c语言,C++11 move()函数:将左值强制转换为右值
- SpringBoot自动装载
- 一篇带你了解函数指针
- C++Heap Sort堆排序的实现算法(附完整源码)
- 商务英语如何利用计算机思维,如何更好的运用商务英语
- sqlserver 查询表锁死,解除表锁死
- CountDownLatch 多线程使用示例
- SATA接口Raid、AHCI、IDE三种模式
- cmd命令行查看wifi密码
- 会议安排(经典贪心算法例题)
- CS客户端渗透测试(二)信息收集与流量分析
- 7个实用的Python自动化代码,别再重复造轮子了!
- ECS服务器10M带宽能让多少人同时访问?
- 白苹果了怎么强制开机_苹果手机开机卡在开机界面怎么办?
- Kaggle 大神 Eureka 的高手进阶之路
- php alpine postgres,docker环境下搭建使用postgresql10
- 并联串联混合的电压和电流_并联型的有源滤波器能够有多少种用法?
- 爆破3389密码:目标主机Win2008(私有IP为192.168.1.167)开放3389端口,使用kali中的Hydra爆破密码。
热门文章
- php在图片左上角加入水印,如何在PHP中将图像添加到图像上,如水印
- 埃及分数怎么计算java_贪心算法之埃及分数问题(附c++源代码)
- 拓扑排序排课系统_木犀互联网技术周刊(第四十五期): 分布式系统简介
- python从html中提取文本_使用Python从HTML中提取可读文本?
- python全局变量可以改变吗_在Python中避免我的全局变量,我有几个函数可以改变一个变量...
- python在linux编程_python要在linux下编程吗
- pytorch模型转onnx遇到的问题记录
- python函数编程实例_Python函数式编程实例详解
- java8 comparator接口_Java8 Comparator 排序方法
- centos7删除符号链接_如何在 Linux 上查找和删除损坏的符号链接 | Linux 中国