Jspatch is a GitHub open source framework that can dynamically use JavaScript to invoke and replace Objective-c properties and methods in the project through the objective-c run-time mechanism. Its compact Framework, concise code, and interaction with OBJECTIVE-C through the JavaScriptCore framework of the system make it highly advantageous in both security and audit risk. Git source address: https://github.com/bang590/JSPatch.
One, from an official small demo to look at
The Jspath is integrated into a Xcode project through Cocoapods, and the following code is written in the Appdelegate class:
-(BOOL) Application: (UIApplication *) application didfinishlaunchingwithoptions: (Nsdictionary *) launchOptions {
Start initialization engine
[Jpengine startengine];
Read JS file
nsstring *sourcepath = [[NSBundle Mainbundle] pathforresource:@ "demo" oftype:@ "JS"];
NSString *script = [NSString stringwithcontentsoffile:sourcepath encoding:nsutf8stringencoding Error:nil];
Run JS file
[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, O,)];
View.backgroundcolor = [Uicolor redcolor];
return view;
}
In the project add a JS file, written as follows:
Require (' UIView, Uicolor, Uilabel ')
//To replace the function's class
defineclass (' appdelegate ', {///
Replace function
///To replace the name
of the function) 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;
}
});
Run engineering, you can see the Genview method is replaced by the JS file method, the original red view was modified to green.
modifying or adding methods to Objective-c using JavaScript code
The Jspatch engine supports 3-way JavaScript code calls, using JavaScript strings to run code, reading local JavaScript files to run code, and fetching JavaScript files from the network for code to run. For example, if you want to eject a warning box in your project through JavaScript code, insert the following code in the OBJECTIVE-C code:
-(void) viewdidload {
[super viewdidload];
The ' \ ' character is used for line breaks
[jpengine evaluatescript:@ \
var alertview = require (' Uialertview '). Alloc (). init (); \
Alertview.settitle (' Alert '); \
alertview.setmessage (' Alertview from JS '); \
Alertview.addbuttonwithtitle (' Ok '); \
alertview.show (); \
"];
}
Developers can also dynamically add methods to objective-c class files, such as the following in the Viewcontroller class:
-(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];
}
The JavaScript file code is as follows:
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)
}
);
In addition to the code above, no other method was written in the viewcontroller.m file to run the project, you can see that the program did not crash, Viewcontroller executed the Creatview method.
With the example above, we find that using Jspatch can do some very interesting things. For iOS applications, the official channel of the App Store for the release of the application through manual audit, sometimes the audit cycle will be very long, if the developer in the code to leave a few small holes, the application once online, to modify the bug is very difficult. With Jspatch, we can imagine, if you can locate the online application of the problem, using the JS file to modify this method, this will be how cool thing, in fact, the main use of Jspatch is also to achieve online application of the minimum problem hotfix.
Three, the basic method of interaction between JavaScript and Objective-c
To use Jspatch to write objective-c-style methods, you need to follow some of the rules that JavaScript interacts with objective-c.
1. Use the Objective-c class in JavaScript files
If you need to use a objective-c class when writing JavaScript code, you must first make a require reference to the class, for example, if you need to use the UIView class, you need to make the following reference before you use it:
You can also refer to multiple OBJECTIVE-C classes at once:
Require (' UIView, Uicolor, Uilabel ')
There is also a simpler way of writing, which is referenced directly when it is used:
Require (' UIView '). Alloc (). Init ()
2. Call to Objective-c method in JavaScript file
When making a call to the Objective-c method, it is divided into two types, one is to invoke the class method, and the other is to invoke the object method of the class.
Calling class methods: calling class methods by means of class names, which are similar in format and passed in parentheses for parameters:
Invoke instance method: Invokes an instance method of a class by means of an object, in the form of a parameter passed in parentheses:
For the multiple parameter method in Objective-c, it is transformed into JavaScript to divide the parameter by _, all the parameters are put in the following parentheses, separated by commas, examples are as follows:
View.setbackgroundcolor (Uicolor.colorwithred_green_blue_alpha (0,0.5,0.5,1))
For attribute variables of the Objective-c class, only getter and setter methods can be used in JavaScript, and the example is as follows:
Label.settext ("Jspatch")
Tip: If the original Objective-c method already contains an _ symbol, use __ in JavaScript instead.
3. Manipulate and modify Objective-c classes in JavaScript
The maximum application of Jspatch is to dynamically manipulate and modify classes at the time of application runtime.
Override or add a method for a class:
Use DefineClass in JavaScript to define and modify methods in a class, which are written in the following format:
/*
ClassDeclaration: Class name string to add or override method if this class does not exist, a new class Instancemethods will be created
: Instance method {} Classmethods to add or override
: class method to add or override {}
/DefineClass (classdeclaration, Instancemethods, Classmethods)
Examples are as follows:
DefineClass (' Viewcontroller ', {
//Replace The-genview
method Newfunc:function () {//
write instance methods
Self.view (). SetBackgroundColor (Uicolor.redcolor ())
}
},{
myload:function () {
//write class method
}
}
)
If you want to invoke the original method after overriding the method in the class, you need to use the orig prefix, as shown in the following example:
DefineClass (' Viewcontroller ', {
//Replace The-genview
method Viewdidload:function () {//
Write instance methods
self. Origviewdidload ()
}
}
)
For a method called by the Super keyword in objective-c, you can use Self.super () in JavaScript to invoke, for example:
DefineClass (' Viewcontroller ', {
//Replace The-genview
method Viewdidload:function () {//
Write instance methods
self.super (). Viewdidload ()
}
)
Similarly jspatch can also add temporary properties for a class to pass arguments between methods, use Set_prop_forkey () to add properties, and use Getprop () to get properties, note that Jspatch added properties cannot be accessed using the Objective-c setter and getter method, as follows:
DefineClass (' Viewcontroller ', {
//Replace The-genview
method Viewdidload:function () {//
write instance methods
Self.super (). Viewdidload ()
self.setprop_forkey ("Jspatch", "Data")
},
touchesbegan_withevent (ID, Touch) {
Self.getprop ("Data")
Self.view (). SetBackgroundColor (Uicolor.redcolor ())
}
)
Compliance with the Protocol is added to the class in a manner consistent with the agreement in Objective-c, as follows:
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)
}}
)
Four common types of interaction between JavaScript and Objective-c
1. Structural body
In the Objective-c code, we often use the structure, jspatch the central support of the structure of the following several: Cgpoint,cgsize,cgrect,nsrange. These structures are also used frequently in the interface operation.
For the CGRect type, JavaScript is created using the following code:
var view = require (' UIView '). Alloc (). Init ()
view.setframe ({x:100,y:100,width:100,height:100})
For the Cgpoint type, JavaScript is created using the following code:
View.setcenter ({x:200,y:200})
For the Cgsize type, JavaScript is created using the following code:
var size = {width:200,height:200}
view.setframe ({x:100,y:100,width:size.width,height:size.height})
For the Nsrange type, JavaScript is created using the following code:
var range = {location:0, length:1}
2. Selector Selector
For the method selector in Objective-c, selector is created in JavaScript using a string, for example:
Self.performselector_withobject ("func:", 1)
3. About empty objects
In JavaScript, null and undefined correspond to the Nsnull null object in the nil,objective-c in Objective-c, instead of using Nsnull in JavaScript.
4. Block interaction in Objective-c and JavaScript
There are two ways to block interaction between JavaScript and Objective-c, one of which is to call block in Objective-c in a JavaScript file. One is to pass function blocks in JavaScript files to OBJECTIVE-C as block arguments.
Using the block in Objective-c in a JavaScript file is simple because there is no block concept in JavaScript and objective-c is automatically converted to functions, as shown in the following example:
Objective-c:
typedef void (^block) (NSString * str);
@interface Viewcontroller ()
@end
@implementation Viewcontroller
-(block) getblock{block
= ^ ( NSString * str) {NSLog (@ "%@", str);
return blocks;
}
@end
Javascript:
DefineClass ("Viewcontroller", {
viewdidappear:function (animated) {
var func = Self.getblock ()
func ("123 ")
}
})
It is more complicated to pass Func as a parameter block in a JavaScript file to objective-c, which needs to be packaged using the block () method, for example:
Objective-c:
@interface Viewcontroller ()
@end
@implementation viewcontroller
-(void) Run: (void (^) (NSString * str)) block{block
(@ "123");
}
@end
Javascript:
DefineClass ("Viewcontroller", {
viewdidappear:function (animated) {
//run method needs to pass in a block
Self.run ( Block ("nsstring*", function (str) {console.log (str)})}
)
When wrapping a func in JavaScript using the Block () method, the block (PARAM1,PARAM2) has two parameters, the 1th parameter sets the type of the argument in Func, if there are multiple arguments, a comma is used, and the 2nd is the Func function body.
Note: The self pointer is not available in the Func of the Block () wrapper, and if you need to use self, you need to convert the temporary variable outside the block, as shown in the following example:
DefineClass ("Viewcontroller", {
viewdidappear:function (animated) {
//run method needs to pass in a block
var SLF = self
Self.run (Block ("nsstring*",
function (str) {
console.log (str)
slf.log (str
)})}} )
Use __weak () and __strong respectively in JavaScript to declare weak references and strong reference objects, for example:
var SLF = __weak (self)
var Stgsef = __strong (self)
5. About GCD and enumeration
In Jspatch, you can use the following JavaScript code to invoke the GCD method:
Blocks the current thread
for a certain time Dispatch_after (1.0, function () {
})
//To add an asynchronous task
Dispatch_async_main (function () {
})
Add a synchronization task
Dispatch_sync_main (function () {
})
//to the global queue for the main thread
dispatch_async_global_queue (
The enumeration defined in Objective-c can not be used directly in Jspatch of the function () {}), but it can be passed with the actual value of its enumeration. For example:
The value of//uicontroleventtouchupinside is 1<<6
btn.addtarget_action_forcontrolevents (self, "handleBtn ", 1<<6);