In iOS, Objective-C and JavaScript are mutually called (implementing the same mechanism as Android)

Source: Internet
Author: User

Recently, in iOS projects, the interaction between oc and js needs to be used, and the implementation method must be the same as in Android to facilitate unified processing in js. So after studying the third-party library WebViewJavascriptBridge, we have implemented one following the interaction mechanism of WebView and JS in Android. we will share it with you here.

The first thing to note is that in iOS, JavaScript code calling Objective-C can only be carried out in the form of redirection, that is, js can modify the src of iframe, or directly jump to a url, in Objective-C

WebView: shouldStartLoadWithRequest: navigationType: The method intercepts this jump, and then retrieves the method name and parameter to be called by js by parsing the jump url. In Android, you only need to call the addJavascriptInterface method of WebView to bind a js object to a java class and implement corresponding functions in the class. When js needs to call the java method, you only need to call the corresponding function directly through the bound object in js.

Obviously, js interaction in Android is much more convenient than that in iOS. Therefore, we can implement a mechanism similar to Android on iOS. The following describes the implementation principle. To call the corresponding function directly through the bound object in js, you need to add the corresponding code in js, however, to ensure consistency with Android, js Code should be injected on the client. So let's first implement the code to be injected:

; (Function () {var messagingIframe, bridge = 'external', CUSTOM_PROTOCOL_SCHEME = 'jscall'; if (window [bridge]) {return} function _ createQueueReadyIframe (doc) {messagingIframe = doc. createElement ('iframe'); messagingIframe. style. display = 'one'domaindoc.doc umentElement. appendChild (messagingIframe);} window [bridge] ={}; var methods = ["test1", "test2"]; for (var I = 0; I
 
  
In the above Code, we added an iframe to the webpage so that webview can capture redirect requests when the iframe src is changed, it is much safer than modifying the url of a webpage directly. At the same time, an external object is set and the test1 and test2 methods are bound to the object. When the two methods are executed, the src of iframe will be modified, the methods and parameters to be called are constructed in url format. Then, we need to inject the webview when loading the web page to implement the following delegation:

-(Void) webViewDidFinishLoad :( UIWebView *) webView {// if (! [[WebView stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat: @ "typeof window. % @ = 'object' ", kBridgeName] isEqualToString: @" true "]) {NSBundle * bundle = _ resourceBundle? _ ResourceBundle: [NSBundle mainBundle]; NSString * filePath = [bundle pathForResource: @ "WebViewJsBridge" ofType: @ "js"]; NSString * js = [NSString stringWithContentsOfFile: filePath encoding: NSUTF8StringEncoding error: nil]; [webView stringByEvaluatingJavaScriptFromString: js] ;}}

Note: Before the above Code is injected, you must determine whether it has been injected to avoid repeated injection. Next, we can implement a webview delegate to intercept redirect events:

-(BOOL) webView :( UIWebView *) webView shouldStartLoadWithRequest :( NSURLRequest *) request navigationType :( UIWebViewNavigationType) navigationType {NSURL * url = [request URL]; NSString * requestString = [[request URL] absoluteString]; if ([requestString hasPrefix: kCustomProtocolScheme]) {NSArray * components = [[url absoluteString] componentsSeparatedByString: @ ":"]; NSString * function = (NSString *) [components objectAtIndex: 1]; NSString * argsAsString = [(NSString *) [components objectAtIndex: 2] stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding] NSData * argsData = [argsAsString dataUsingEncoding: encoding]; NSDictionary * argsDic = (NSDictionary *) [NSJSONSerialization JSONObjectWithData: argsData options: kNilOptions error: NULL]; // convert the js array to the objc array NSMutableArray * args = [NSMutableArray array]; for (int I = 0; I <[argsDic count]; I ++) {[args addObject: [argsDic objectForKey: [NSString stringWithFormat: @ "% d", I];} // call the oc method, ignore warning # pragma clang diagnostic ignored "-Warc-inform mselector-leaks" SEL selector = NSSelectorFromString ([function stringByAppendingString: @ ":"]); CLog (@ "sel :% @, args: % @ ", function, args); if ([self respondsToSelector: selector]) {[self owned mselector: selector withObject: args];} return NO ;} else {return YES ;}}

The above code judges the redirected url. if it complies with the Protocol we have defined in advance, it will be parsed; otherwise, it will jump. Separate the parameters with a colon to retrieve the function name and parameter list, and call the corresponding method. So far, we have implemented the same calling mechanism as Android in iOS.

However, the disadvantage of the above method is that it has not reached the convenience level in Android. The ideal method is to dynamically set the objects to be bound when javascript injection is performed, at the same time, it dynamically obtains the instance method of the current class and generates the corresponding js Code. This fully implements the binding mechanism in Android. This implementation is not difficult. If you are interested, you can try it.

For ease of use, I encapsulated the above code into a class. For specific usage instructions, see the Demo.

Note that:

1. in actual applications, JavaScript Execution sequence may occur. if Javascript in the webpage obtains the bound object before injection for saving, it cannot be obtained, this is because the object to be bound is empty. This requires js Initialization on the webpage after injection, so there is an initReady method in the above Code.

2. Because the performSelector can contain up to two parameters, the parameter list is transmitted through arrays in this example.


If you feel helpful to yourself, I hope you can help me with it. Thank you :) my blog: Sorry!

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.