Recently in the company to do a js-native SDK, is used for the interaction between JS and the native.
The use of the scene is mainly WebView, then the original URL to intercept the way is no longer considered, we use the iOS7 after the javascriptcore.framework.
Overall, Apple's JavaScriptCore API is very easy to use, and the main steps are as follows:
1. Get a jscontext.
_jscontext = [_webview valueforkeypath:
@ "DocumentView.webView.mainFrame.javaScriptContext"];
2. Handle a JS-side-tuned method, such as log
_jscontext[@ "Log" = ^ () {
Nsarray *args = [Jscontext currentarguments];
for (id obj in args) {
//need to be aware that obj here is still jsvalue
NSLog (@ "%@", obj);
}
;
3. Call JS side to execute a JS method
[_jscontext
evaluatescript:@ "log (' Arg1 ')]";
[_jscontext
evaluatescript:@ "logcallback (' arg1 ')"];
4. Redefine a method of a JS end (in fact and 3 is a, but special point)
[_jscontext evaluatescript:@ ' Checkapi = function () {\ return
[\
' selectimage ', \
' Startrecord ', \
'] Login ', \
];\
} '];
Master the above 4 steps, basically in iOS end and JS interaction is completely OK.
Then we start to H5 with the Android end.
Here, we found a problem:
The Android side JS method calls the native method, you need to specify InterfaceName, so their JS invocation is this way:
Xxname.log (' arg1 ');
The front is more out of the xxname, this way, we directly use Jscontext for listening processing is not possible
This cannot be performed to the
_jscontext[@ "xxname.log"] = ^ () {
Nsarray *args = [Jscontext currentarguments];
for (id obj in args) {
//need to be aware that obj here is still jsvalue
NSLog (@ "%@", obj);
}
;
So what to do. When victory was in sight, it jammed. Do you want to make the H5 side of the call to distinguish by platform? If you call log (' xx ') on the iOS platform, Android calls Xxname.log (' xx ').
Fortunately, we are so sharp how can not solve this problem.
Here I introduce two ways to solve:
programme I:
Use Jsexport to achieve similar processing effects as Android
The steps are as follows:
1. Define WEBVIEWJSHELPERPROTOCOL protocol real line Jsexport protocol
And in the protocol to define all the JS end to call the method
@protocol webviewjshelperprotocol<jsexport>
-(void) log: (nsstring*) arg;
@end
2. Define class to implement this Protocol
@interface webviewjshelper () <WebViewJSHelperProtocol>
@end
@implementation webviewjshelper
-( void) log: (nsstring*) arg{
NSLog (@ "%@", Arg);
@end
3. Register the instance of the class to Jscontext
Webviewjshelper *_webviewjshelper = [[Webviewjshelper alloc]init];
_jscontext[@ "xxname"] = _webviewjshelper;
To this, JS calls the Xxname.log method, which is executed in the log method defined by our iOS side.
About Jsexport There are also some definitions of aliases and the like, interested students can see the API or online documentation.
The main note is that there is no _jscontext[@ "xxname"] = self; this is because it causes the self instance to be held by the JS end and memory is not released.
Programme II:
The operation of this scheme is much simpler, compared to one, without defining the implementation of the original method, the operation is as follows:
1. Arbitrarily define a class plus Jsexport protocol
@interface webviewjsexport:nsobject<jsexport>
@end
@implementation webviewjsexport
@end
2. Register to Jscontext
_jscontext[@ "xxname"] = [Webviewjsexport new];
3. Processing a JS-end-adjusted method
Define normal JS method without xxname
_jscontext[@ "Log" = ^ () {
Nsarray *args = [Jscontext currentarguments];
for (id obj in args) {
//need to be aware that obj here is still jsvalue
NSLog (@ "%@", obj);
}
;
Redefine the Xxname.log method
[_jscontext evaluatescript:@ "xxname.log = log"];
OK, now the whole set of features can be used.
The above scheme two way personal feel more, first more close to JS habit, next do not need to define so many methods, and for the JS end call, the number of indefinite parameters is also easier.
At the end of this article, say a little note:
1. Use Nsarray *args = [Jscontext currentarguments]; get args, Inside are jsvalue, pay attention to this, if you want to use, It is best to turn to the appropriate type, such as [obj toString], and so on, you can look at the Jsvalue header file
2. To note the problem of circular references, do not write _jscontext[@ "xxname" = self; The rest is in block, and the platitudes are no longer elaborate.
3. To pay attention to the JS end and the life cycle of the original end of the problem
both ends of the memory management is not the same, the JS end is GC, we are reference count, the general situation will not have life cycle problems, but when necessary, need to use jsvirtualmachine packaging, this piece I am also learning, I hope you will pay attention.