Use JavaScriptCore to do both Android and iOS compatible js-nativesdk__c#

Source: Internet
Author: User

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.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.