iOS中动态更新补丁策略JSPatch运用基础一

简介:

iOS中动态更新补丁策略JSPatch运用基础

        JSPatch是GitHub上一个开源的框架,其可以通过Objective-C的run-time机制动态的使用JavaScript调用与替换项目中的Objective-C属性与方法。其框架小巧,代码简洁,并且通过系统的JavaScriptCore框架与Objective-C进行交互,这使其在安全性和审核风险上都有很强的优势。Git源码地址:https://github.com/bang590/JSPatch

一、从一个官方的小demo看起

        通过cocoapods将JSPath集成进一个Xcode工程中,在AppDelegate类的中编写如下代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- ( 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文件,编写如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
     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代码中插入如下代码:

?
1
2
3
4
5
6
7
8
9
10
11
- ( 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类中编写如下:

?
1
2
3
4
5
6
7
8
9
- ( 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文件代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
  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这个类,需要在使用前进行如下引用:

?
1
require( 'UIView' )

同样也可以一次对多个Objective-C类进行引用:

?
1
require( 'UIView, UIColor, UILabel' )

还有一种更加简便的写法,直接在使用的时候对其进行引用:

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

2.在JavaScript文件中进行Objective-C方法的调用

    在进行Objective-C方法的调用时,分为两种,一种是调用类方法,一种是调用类的对象方法。

调用类方法:通过类名打点的方式来调用类方法,格式类似如下,括号内为参数传递:

?
1
UIColor.redColor()

调用实例方法:通过对象打点的方式调用类的实例方法,格式如下,括号内为参数传递:

?
1
view.addSubview(label)

对于Objective-C中的多参数方法,转化为JavaScript将参数分割的位置以_进行分割,参数全部放入后面的括号中,以逗号分割,示例如下:

?
1
view.setBackgroundColor(UIColor.colorWithRed_green_blue_alpha(0,0.5,0.5,1))

对于Objective-C类的属性变量,在JavaScript中只能使用getter与setter方法来访问,示例如下:

?
1
label.setText( "JSPatch" )

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

3.在JavaScript中操作与修改Objective-C类

    JSPatch的最大应用是在应用运行时动态的操作和修改类。

重写或者添加类的方法:

在JavaScript中使用defineClass来定义和修改类中的方法,其编写格式如下所示:

?
1
2
3
4
5
6
/*
classDeclaration:要添加或者重写方法的类名 字符串  如果此类不存在 则会创建新的类
instanceMethods:要添加或者重写的实例方法 {}
classMethods:要添加或者重写的类方法 {}
*/
defineClass(classDeclaration, instanceMethods, classMethods)

示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
defineClass( 'ViewController' , {
             // replace the -genView method
                 newFunc:  function () {
                     //编写实例方法
                     self.view().setBackgroundColor(UIColor.redColor())
                 }
     
             },{
 
                 myLoad: function (){
                     //编写类方法
                 }
 
             }
             )

如果在重写了类中的方法后要调用原方法,需要使用ORIG前缀,示例如下:

?
1
2
3
4
5
6
7
8
9
defineClass( 'ViewController' , {
             // replace the -genView method
                 viewDidLoad:  function () {
                     //编写实例方法
                     self.ORIGviewDidLoad()
                 }
     
             }
             )

对于Objective-C中super关键字调用的方法,在JavaScript中可以使用self.super()来调用,例如:

?
1
2
3
4
5
6
7
8
9
defineClass( 'ViewController' , {
             // replace the -genView method
                 viewDidLoad:  function () {
                     //编写实例方法
                     self. super ().viewDidLoad()
                 }
     
             }
             )

同样JSPatch也可以为类添加临时属性,用于在方法间参数传递,使用set_Prop_forKey()来添加属性,使用getProp()来获取属性,注意,JSPatch添加的属性不能使用Objective-C的setter与getter方法访问,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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中遵守协议的方式一致,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)
             }
             })

目录
相关文章
|
9天前
|
安全 数据安全/隐私保护 Android开发
探索Android与iOS的隐私保护策略
在数字时代,智能手机已成为我们生活中不可或缺的一部分,而随之而来的则是对个人隐私和数据安全的日益关注。本文将深入探讨Android与iOS两大操作系统在隐私保护方面的策略和实践,分析它们如何应对日益严峻的隐私挑战,以及用户应如何保护自己的数据安全。通过对比分析,我们将揭示两大系统在隐私保护方面的优势和不足,为用户提供有价值的见解和建议。
|
3月前
|
缓存 监控 Android开发
探索iOS与安卓开发中的性能优化策略
在移动应用开发的竞技场上,iOS和安卓这两大操作系统不断推动着技术的边界。性能优化,作为提升用户体验的关键因素,已成为开发者们关注的焦点。本文将深入探讨两大平台上的性能优化实践,揭示如何通过工具、技术和策略来提升应用的响应速度和流畅度,同时考虑到电池寿命和内存管理等关键指标。
|
10天前
|
前端开发 Android开发 开发者
探索Android与iOS的跨平台开发策略
在当今多元化的移动设备市场中,开发者面临着为不同操作系统设计应用的挑战。本文深入探讨了Android和iOS两大主流平台的跨平台开发策略。我们将分析使用Flutter、React Native等框架进行跨平台开发的优劣,并讨论如何克服各平台间的差异性,以实现高效、一致的用户体验。此外,文章还将提供一些实用的技巧和最佳实践,帮助开发者优化跨平台应用的性能和兼容性。
28 4
|
11天前
|
前端开发 Android开发 iOS开发
探索Android与iOS的跨平台开发策略
在移动应用开发的多元化时代,跨平台开发已成为开发者追求效率和广泛覆盖的重要手段。本文深入探讨了Android与iOS两大主流平台下的跨平台开发策略,分析了各自的优势与挑战,并通过实际案例展示了如何有效实施跨平台解决方案,以期为开发者提供有价值的参考和启示。
|
5月前
|
存储 安全 编译器
我给 iOS 系统打了个补丁——修复 iOS 16 系统键盘重大 Crash
我给 iOS 系统打了个补丁——修复 iOS 16 系统键盘重大 Crash
151 2
我给 iOS 系统打了个补丁——修复 iOS 16 系统键盘重大 Crash
|
19天前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。
|
3月前
|
安全 Android开发 iOS开发
安卓与iOS开发之道:探索移动应用的差异化策略
【8月更文挑战第21天】在移动应用开发的广阔天地中,安卓和iOS这两大操作系统平台各领风骚。本文将深入探讨这两个平台的差异化策略,帮助开发者理解如何根据不同平台的特性优化应用设计,提升用户体验,并最大化市场潜力。我们将从用户界面、性能优化、市场定位、安全性以及发布策略等多个维度进行比较分析,旨在为开发者提供一个全面的视角,以便在竞争激烈的应用市场中占据一席之地。
|
4月前
|
IDE API Android开发
安卓与iOS开发环境的差异及适配策略
在移动应用开发的广阔舞台上,Android和iOS两大操作系统各据一方,各自拥有独特的开发环境和工具集。本文旨在深入探讨这两个平台在开发环境上的关键差异,并提供有效的适配策略,帮助开发者优化跨平台开发流程。通过比较Android的Java/Kotlin和iOS的Swift/Objective-C语言特性、IDE的选择、以及API和系统服务的访问方式,本文揭示了两个操作系统在开发实践中的主要分歧点,并提出了一套实用的适配方法,以期为移动开发者提供指导和启示。
|
4月前
|
算法 数据库 Android开发
探索iOS与安卓应用开发的性能优化策略
在移动应用开发领域,性能优化是提升用户体验、增强应用市场竞争力的关键因素。本文深入探讨了iOS和安卓平台下,开发者如何通过具体技术和方法有效优化应用性能。文章首先概述了性能优化的重要性,随后详细分析了iOS和安卓开发中的优化策略,包括代码优化、资源管理和异步处理等技术手段。最后,通过案例分析,展示了这些优化措施在实际开发中的应用效果,旨在为开发者提供实用的性能提升建议。
|
6月前
|
缓存 Android开发 iOS开发
打造高效移动应用:Android与iOS性能优化策略
【4月更文挑战第29天】 在移动设备日益成为用户日常互动的主要平台的今天,应用程序的性能已成为决定其成功的关键因素之一。本文将探讨针对Android和iOS平台的性能优化技巧,涵盖内存管理、多线程处理、网络请求优化以及用户界面的流畅性提升等方面。通过分析不同操作系统的架构特点,我们旨在提供一套综合性的策略,帮助开发者构建快速、响应迅捷且用户体验良好的应用。