Reproduced: [IOS] objective-c and JavaScript call each other when using UIWebView

Source: Internet
Author: User

translated from: http://zonble.net/archives/2010_09/1385.phpWhen writing JavaScript, you can use an object called window, like we want to jump from the current page to another page, we will change the location of the window.location.href, in our Objective C code, If we can get the specified WebView indicator, we can get the window object that appears in JavaScript, that is, [WebView Windowscriptobject]. This object is the bridge between JS in WebView and our OBJ C program-window object can get all the JS functions and objects inside the page, and if we set an OBJ C object to Windowscriptobject Value,js You can also invoke the method of the Obj C object. As a result, we can ask WebView to execute a section of JS in the obj C program, which in turn allows JS to invoke a function that is implemented with obj C. ※ Use Objective c to get and set JavaScript object to get the JavaScript object from OBJ C in the Web page, that is, to make some KVC calls to Windowscriptobject, like Valueforkey: with Valu Eforkeypath:. If we are in JS, want to know the current location of the Web page, this will be written:
Varlocation = window.location.href;
This can be called with OBJC:
Nsstring*location = [[WebView windowscriptobject] valueforkeypath:@ "Location.href"];

If we want to set window.location.href, ask to open another page, in JS:

window.location.href = ' http://spring-studio.net ';
OBJ C:
[[WebView Windowscriptobject] setvalue:@ "http://spring-studio.net" forkeypath:@ "Location.href"];
Since the language characteristics of the OBJ C and JS itself are different, the difference between the two languages can be seen by passing things between them-
    • JS is OO, but there is no class, so the JS object into the OBJ C program, in addition to the basic string will be converted to NSString, the basic number will be turned into nsnumber, such as an Array and other objects, in OBJ C, are webscriptobj ECT this Class. It means that the JS Array will not help you convert to Nsarray.
    • From JS inside an empty object to the obj C program, not in obj C originally said "No things" way, such as NULL, nil, NSNull, etc., but the exclusive use of WebKit webundefined.
So, if we want to see something in a JS Array, we first get the value of the object called length, and then use Webscriptvalueatindex: To see the content at the index position. If we write this in JS:
Varjsarray = {' zonble ', ' dot ', ' net '};  for (vari = 0; i < jsarray.length; i++) {    console.log (jsarray[i]);}
This is what happens in OBJ C:
Webscriptobject *obj = (Webscriptobject *= [[obj valueforkey:@ "Length"] integervalue]; Nsmutablearray*a = [Nsmutablearrayarray];  for (nsuintegeri = 0; i < count; i++) {    nsstring*item = [obj webscriptvalueatindex:i];    NSLog (@"item:%@", item);}
※ Call JavaScript function with Objective C to invoke the JS function in the Web page with OBJ C, there are probably several methods. The first is to write a section directly with you in the Web page will be written in the same program, called Windowscriptobject with Evaluatewebscript: Execute. For example, we want to create a new JS function in the Web page with the following content:
Functionx (x) {    + 1;}
So it can be written in OBJ C;
[[WebView Windowscriptobject] evaluatewebscript:@ "function x (x) {return x + 1;}"];

Next we can call Window.x ():

Nsnumber*result = [[WebView windowscriptobject] evaluatewebscript:@ "x (1)"]; NSLog (@"result:%d", [result IntegerValue]); // Returns 2
Because in JS, each funciton is actually the object, so we can also directly get window.x call this object to execute itself. In JS If you write this:
Window.x.call (window.x, 1);
This is true in OBJ C:
Webscriptobject *x = [[WebView windowscriptobject] valueforkey:@ "x"]; NSNumber*result = [x callwebscriptmethod:@ "Call" witharguments:[nsarrayarraywithobjects:x, [ Nsnumbernumberwithint:1],nil]];
This allows some webscriptobject to execute their own writing, in fact, the comparison will not be used from OBJ C call JS this end, but next will be mentioned, by JS call Obj C, because so JS can send a callback function to obj C program inside. If we are doing a Web page and we just want to update a chunk of the page, we will use the AJAX technique to send a request to the server only for the data needed for that chunk, and request a callback function when the request is complete. Update the display of this chunk. From JS call obj C can also do similar things, if the obj C program takes a certain amount of time to operate, or we may be in obj C Crawl network data, we can send a callback function to the obj C program, request the obj C program in After finishing the work, perform this callback function. In ※domwebkit, all DOM objects inherit from Domobject,domobject and inherit from Webscriptobject, so we can also ask this Dom object to execute JS from the OBJ C program after we have obtained a DOM object. Program. If we have an ID called "#s" text input box in our Web page, and we want the focus of the keyboard input now on this input box, this will be written in JS:
Document.queryselector (' #s '). focus ();
OBJ C:
DOMDocument *document = [[WebView MainFrame] domdocument];[ [Document queryselector:@"#s"] callwebscriptmethod:@ "focus" witharguments:nil];
※ Accessing the value of Objective C with JavaScript allows the JS program in the Web page to invoke the obj C object by registering an obj C object as a property of the Window object in JS. After that, JS can also call this object's method, you can also obtain the object's various value, as long as the KVC can be obtained value, such as NSString, NSNumber, NSDate, Nsarray, Nsdictionary, Nsvalue ... such as JS transmission Array to OBJC, but also need to do some special processing to become Nsarray, from OBJ C to a nsarray to JS, will automatically become JS Array. The first thing to note is the time to register the OBJ C object with the Window object, because each time the page is re-loaded, the contents of the Window object will be changed-after all, each page will have a different JS program, so we need to do it at the appropriate time. We will first specify WebView's frame loading delegate (with Setframeloaddelegate:) and implement Webview:didclearwindowobject:forframe:,webview This section of the program is called whenever Windowscriptobject is updated. If we now want to let JS in the Web page can use the current controller object, this will write:
-(void) WebView: (WebView *) sender Didclearwindowobject: (Webscriptobject *) WindowObject forframe: (Webframe * ) frame{    [windowobject setvalue:selfforkey:@"Controller"];}
As a result, we can call our OBJ C object whenever Window.controller is called. If we have these member variables in OBJ C Class:
@interfaceMyController: nsobject{    *WebView;    Iboutlet nswindow*window;    NSString*stringvalue;    Nsintegernumbervalue;    Nsarray*arrayvalue;    NSDate*dateValue;    Nsdictionary*dictvalue;    Nsrectframevalue;} @end
Specify Value:
stringvalue [Email protected] "string"== [[nsarrayarraywithobjects:@ "Text", [ nsnumbernumberwithint:30== [[nsdictionarydictionarywithobjectsandkeys:@ "value1", @ "Key1", @ " Value2 ", @" Key2 ", @" Value3 ", @" Key3 "= [window frame];
Read and read with JS:
Varc == document.getElementById (' main '= '; if (c) {    + = ' <p> ' + c.stringvalue + ' <p>'    ; + = ' <p> ' + c.numbervalue + ' <p>'    ; + = ' <p> ' + c.arrayvalue + ' <p>'    ; + = ' <p> ' + c.datevalue + ' <p>'    ; + = ' <p> ' + c.dictvalue + ' <p>'    ; + = ' <p> ' + c.framevalue + ' <p>'    ; = HTML;}
The results are as follows:
string24text,302010-09-09 00:01:04 +0800{key1 = value1; key2 = value2; Key3 = Value3;} Nsrect: {{275, 72}, {570, 657}}
However, if you look at the example above, you do it directly, you should not directly succeed in the correct results, but will get a bunch of undefined, because the OBJ C object Value Preset is protected, will not let JS directly access. To allow JS to access the Value of the Obj C object, you need to implement +iskeyexcludedfromwebscript: for the incoming key one by one processing, if we want JS to be able to access this key, the callback NO:
+ (BOOL) Iskeyexcludedfromwebscript: (constchar*) name{    if(!strcmp (name, "StringValue")) {        Returnno;    }    Returnyes;}
In addition to reading the value of the obj C object, you can also set value, which is equivalent to using Setvalue:forkey in obj C: If in the JS program above, we want to modify StringValue, call c.stringvalue directly = ' New value '. As mentioned earlier, the JS object passed to OBJ C here, except for strings and numbers, class is webscriptobject, and the empty object is webundefined. ※ The syntax of calling Objective C methodobj C with JavaScript inherits from the selector of Smalltalk,obj C, which is quite different from the function syntax of JS. WebKit preset implementation is, if we want to call OBJ C selector in JS, is to put all the parameters to the back of the pendulum, and all the colon to the bottom line, and the original selector if there is a bottom line, but also to deal with. If our controller object has a method, it is written in OBJ C:
-(void) SetA: (ID) a B: (ID) b C: (ID) C;
This is called in JS:
Controller.seta_b_c_ (' A ', ' B ', ' C ');
It's really ugly. So WebKit provides a way for us to turn some OBJ C selector into a better-looking JS function. We want to do webscriptnameforselector:
+ (nsstring*) Webscriptnameforselector: (SEL) selector{    if(selector = =@selector (seta:b:c :)) {        return@ "SETABC";    }    Returnnil;}
You can call this later:
CONTROLLER.SETABC (' A ', ' B ', ' C ');
We can also decide which selector can be used for JS and which to protect, and the method is to implement Isselectorexcludedfromwebscript:. And we can change the name of an OBJ C selector in JS, we can also change the key of a value, by doing Webscriptnameforkey:. There are a few things to note: using JavaScript to call Objective C 2.0 property on top, we use JS call Window.controller.stringValue, and set the value inside, this side is much like we use The syntax of OBJ C 2.0, but actually doing is not the same thing. Call Controller.stringvalue with JS, corresponding to the obj c syntax is [controller valueforkey:@ "StringValue"], instead of invoking the property of the Obj C object. If our obj C object has a property called StringValue, we know that the Obj C property will actually become Getter/setter method at compile time, in JS, we should call CONTROLLER.S Tringvalue () and Controller.setstringvalue_ (). Javascript, function is the property of the object JS function is an object, when an OBJ C object method appears in JS, this method in JS, can more or less as object processing. We have a setabc on it, and we can try to pour it out and see:
Console.log (CONTROLLER.SETABC);

We can see from the results:

function setabc () {[native code]}
This function is native code. Because it is native code, we cannot invoke call or apply on this function. In addition, after registering our OBJ C object as Window.controller, we will also want to make the controller become a function to execute, such as Call Window.controller (); We just want to produce a function that allows JS to call, not the whole object into JS. As long as we implement invokedefaultmethodwitharguments in the Obj C object, we can return the desired result when we call Window.controller (). Now we can do a comprehensive exercise. As mentioned earlier, because we can put the JS object to webscriptobject this class into the obj C program, obj C program can also require the execution of webscriptobject function. If we want to throw a and B two numbers into the obj C program to do an addition, and then appear on the Web page, so we wrote an obj C method:
-(void) Numberwitha: (ID) a PLUSB: (ID) b callback: (ID) callback{    = [a integervalue] + [b IntegerValue];    [Callback callwebscriptmethod:@"call"witharguments:[nsarrayarraywithobjects:callback, [ Nsnumbernumberwithinteger:result],nil]];}

JS inside can call:

 window.controller.numberWithA_plusB_callback_ (1, 2,function   = document.getElementById (' main ' ); Main.innertext  = result;});  
※ WebKit on other platforms other than Mac OS X,webkit has been slowly ported to other operating systems and frameworks in the last few years, and more or less Native API requirements WebView Execute JS, as well as from JS call Native AP Mechanism of I. Compared to Mac OS X, UIWebView's public API on the iPhone is much less. Want to let UIWebView execute a section of JS, can call Stringbyevaluatingjavascriptfromstring:, will only return the string result, so can do things become limited, usually take to get like Window.title this information. There's no way we can turn an obj C object into a JS object on the IPhone, so some events are triggered in the Web page, and if you want to notify the end of obj C, you will often choose to use a customized URL scheme like "zonble://". ChromeOS is completely WebKit as a user interface, but there's no way we can write the desktop or mobile application we're talking about here on Chomeos, so it's not in our discussion. (Straight turnout problem, ChromeOS is designed to give Netbook use of the operating system, but like Toshiba have been using Android, make a smaller than Netbook Smartbook, and the application more, ChromeOS products do, it is really like G Oogle took out two sets of things, himself to fight with himself). Android's WebView object provides a method called Addjavascriptinterface () that can be used to register a Java object as a property of a JS window object, allowing JS to invoke a Java object. However, when invoking the Java object, only can pass the simple text, the number, the complex JS object can not be able. And on the Android want to WebView execute a section of JS, in the file did not see the relevant information, the network above find the saying is, can through the Loadurl (), a section of JS with the form of Bookmarklet passed in. In the Qtwebkit, you can call the Qwebframe addtojavascriptwindowobject, a qobject exposed in the JS environment, I do not know what JS can be transmitted to qobject insideJust DOM objects inside the page can also be obtained in Qtwebkit (qwebelement
, qwebelementcollection), we can call Evaluatejavascript on Qwebframe and these DOM objects to execute Javascript. GTK, because it is the C API, so between the application and JS, not through the operation of packaged objects, but instead of invoking the WebKit JavaScript Engine C API. ※javascriptcore Framework on Mac OS X, we can also request WebView to execute Javascript through the C API. The first thing to do is import. If we want to simply change the window.location.href:
Jsglobalcontextref globalcontext == = jsstringcreatewithutf8cstring ("window.location.href= ' http ://spring-studio.net ' "0, &exception); Jsstringrelease (script);

If we want to get JS inside WebView, we can call our C Function:

-(void) WebView: (WebView *) sender Didclearwindowobject: (Webscriptobject *) WindowObject forframe: (Webframe * ) frame{    = [frame globalcontext];     = Jsstringcreatewithutf8cstring ("MyFunc");     = Jsobjectmakefunctionwithcallback (globalcontext, Name, (Jsobjectcallasfunctioncallback) myFunc);     0, NULL);    Jsstringrelease (name);}

So, as long as JS call Window.myfunc (), you can get the results of the myFunc in this C function:

function, Jsobjectref thisobject,size_targumentcount,constjsvalueref arguments[], jsvalueref*  Exception) {    );}

Reproduced: [IOS] objective-c and JavaScript call each other when using UIWebView

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.