An interactive explanation of OC and JS

Source: Internet
Author: User
Tags sublime text

The cause of the event is driven by the demand for the project. Toss for two days, because there is no uiwebview and JS interaction experience, and feel this time in the function of a certain creativity, hereby leave a little text, convenient to review later.

I want to implement a requirement: to display a string of Web-based text that is only body part of the network, in accordance with the local CSS file, you need to spell the full HTML yourself. In addition, you also need to disable the acquisition of HTML text from the "IMG" tag automatically loaded, and the operation of the download image is placed on the native side to process, and through JS to the image in the cache address to UIWebView.

The advantage of putting picture operations on the native side is:

    • 1, can be local cache, next entry This article can be read directly from the cache, improve response speed and save user traffic.
    • 2, can achieve click on the image to enlarge, save pictures to albums and other operations.

There are also two technical difficulties:

    • 1, how to let the HTML text onload, disable their own image loading, but to get pictures from the local?
    • 2. How to return the downloaded pictures of native to the webpage?

At first, I was also helpless, look through the document can only find a-(NSString *) stringbyevaluatingjavascriptfromstring: (NSString *) script and JS simple interaction method, failed. Until I saw Webviewjavascriptbridge on GitHub, this wrapper library for Uiwebview/webviews and JS interaction.

Just read sample When I almost did not get dizzy, good memory than rotten pen, I never hide their stupidity, so I drew a diagram. Let's look at the code before we put it on the map.

At first, we initialize the native and JS sides separately:

OC End:

1 @property webviewjavascriptbridge* Bridge;

The corresponding initialization code is as follows, which directly includes a callback to receive JS in the initialization:

1 _bridge = [Webviewjavascriptbridge bridgeforwebview:webview webviewdelegate:self handler:^ (ID data, Wvjbresponsecallback responsecallback) {  2         NSLog (@ "OBJC received message from JS:%@", data); 3         Responsecallback (@ "Response for message from OBJC"); 4}];

JS End: (The following is a fixed notation, your own JS file must contain the following code)

1 function Connectwebviewjavascriptbridge (callback) {   2     if (window. Webviewjavascriptbridge) {3         callback (Webviewjavascriptbridge) 4     } else {5         document.addeventlistener (' Webviewjavascriptbridgeready ',   function () {6             callback (Webviewjavascriptbridge) 7         }, False) 8     } 9}10 Connectwebviewjavascriptbridge (function (bridge) {     bridge.init (function (message, responsecallback) {12         log (' JS got a message ', message)-         var data = {' Javascript responds ': ' wee! '} +         log (' JS responding with ', data)         responsecallback (data)     17}

Then, we need to know that in Webviewjavascriptbridge, there are only two ways of interacting: Send and Callhandle,js and OC have both methods, so the corresponding four kinds of relationships are:

The interpretation of the corresponding relationship in the above table is, for example, the first: if Bridge.send () is called in JS, then the callback in the OC-side _bridge initialization method is triggered.

Similarly, the second, in JS called the Bridge.callhandler (' Testjavascripthandler '), it will trigger the OC-side registration of the same name method:

1 Bridge.registerhandler (' Testjavascripthandler ', function (data, responsecallback) {  2         log (' OBJC called Testjavascripthandler with ', data] 3         var responsedata = {' Javascript Says ': ' Right Back atcha! '} 4         log (' JS responding with ', ResponseData) 5         responsecallback (responsedata) 6})

Understanding the rules of use, here's a look at the overall approach to our practical needs:

--1--

First, the first step is to replace the default SRC in the obtained HTML text to prevent it from loading the image automatically.

1 NSString *_content = [contentstring stringbyreplacingoccurrencesofstring:@ "src" withstring:@ "esrc"];

--2--

Because we get only the body part of the HTML, we need to write the full HTML ourselves.

We let "body onload=" onLoaded () "In the time to call the JS onLoaded () function. In this function we traverse the ESRC of all IMG tags, save as an array to the OC end, and let the native side download the images.

1 function onLoaded () {2     Connectwebviewjavascriptbridge (bridge) {3         var allimage = Document.queryselectorall ("img"); 4         allimage = Array.prototype.slice.call (allimage, 0); 5         var imageurlsarray = new Array (); 6         Allimage.foreach (function (image) {7             var esrc = Image.getattribute ("ESRC"); 8             var newlength = Imageurlsarray.push (ESRC); 9         });         bridge.send (Imageurlsarray);     12}

--3--

Bridge.send triggers Webviewjavascriptbridge initialization method + (Instancetype) Bridgeforwebview: (wvjb_webview_type*) WEBVIEW Webviewdelegate: (wvjb_webview_delegate_type*) webviewdelegate handler: (Wvjbhandler) handler; In the handler, we download all the images in the handler block. and return the downloaded image to the address in the cache to a JS.

 1 #pragma mark--Download All pictures 2-(void) Downloadallimagesinnative: (Nsarray *) imageurls{3 Sdwebimagemanager *manager = [SDW Ebimagemanager Sharedmanager]; 4//Initialize an empty element array 5 _allimagesofthisarticle = [Nsmutablearray arraywithcapacity:imageurls.count];//a local array for saving all pictures  6 for (Nsuinteger i = 0; i < imageurls.count-1; i++) {7 [_allimagesofthisarticle addobject:[nsnull NULL]];         8} 9 for (Nsuinteger i = 0; i < imageurls.count-1; i++) {NSString *_url = imageurls[i];11 [Manager Downloadimagewithurl:[nsurl Urlwithstring:_url] options:sdwebimagehighpriority progress:nil completed:^ (      UIImage *image, Nserror *error, Sdimagecachetype CacheType, BOOL finished, Nsurl *imageurl) {if (image) {13 Dispatch_async (Dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{14 nsstring *imgB * = [UIImageJPEGRepresentation (image, 1.0) Base64encodedstringwithoptions:    Nsdatabase64encoding64characterlinelength];15                 Return the image on disk to JS16 nsstring *key = [Manager cachekeyforurl:imageurl];17  NSString *source = [NSString stringwithformat:@ "data:image/png;base64,%@", imgb64];18 [_bridge callhandler:@ "Imagesdownloadcomplete" data:@[key,source]];19}); 20}21}];22}23 }

--4--

[_bridge callhandler:@ "Imagesdownloadcomplete" Data:@[key,source]] will trigger the function Imagesdownloadcomplete () in JS. Iterate through all the IMG tags in this function and assign the image address you sent to the IMG src.

1 function Imagesdownloadcomplete (Poldurl, Pnewurl) {  2     var allimage = Document.queryselectorall ("img"); 3     allimage = Array.prototype.slice.call (allimage, 0); 4     Allimage.foreach (function (image) {5         if ( Image.getattribute ("esrc") = = Poldurl | | Image.getattribute ("esrc") = = decodeURIComponent (Poldurl)) {6             image.src = pnewurl;7         }8     }); 9}

At this point, through the Webviewjavascriptbridge processing UIWebView and JS Interactive implementation of the local processing of the download of the Web page picture is basically completed. This example shows a complete process, basically involving JS and OC of various interactions including OC call JS, JS call oc and so on. If you have other business needs, and basically follow this process can be leaf out, the only difference is the business logic.

Let me give you one more example. Also appear in my business needs, is to click on the picture on the page, the image will be zoom-out animation to enlarge, left and right to see other pictures, but also need to double-click to enlarge View, save pictures and other functions. Similar to this:

At first glance, we are clicking on a picture on a webpage, how can we let this image jump out of the picture alone? And you can swipe left and right to show other pictures?

First, we still need to transform the Web to get the HTML text, the regular match img esrc=http://..., plus the onclick event, bind a JS method, and put this esrc as a parameter into the binding method.

Regular replacement

Nsregularexpression *regex = [nsregularexpression regularexpressionwithpattern:@ "(img[^]+esrc=\") (\\S+) \ "" options:0 Error:nil];

result = [Regex stringbyreplacingmatchesinstring:newcontent options:0 range:nsmakerange (0, Newcontent.length) withtemplate:@ "img esrc=\" $2\ "onclick=\" Javascript:onimageclick (' $ $ ') \ ""];

JS in the Onimageclick () function. The main task of this function is to get the number of the clicked Image in all pictures and the position in the current screen. and return this information to OC.

 1 function Onimageclick (picurl) {2 Connectwebviewjavascriptbridge (function (bridge) {3 var allimage = Documen T.queryselectorall ("P img[esrc]"); 4 Allimage = Array.prototype.slice.call (allimage, 0); 5 var urls = new Array (); 6 var index =-1; 7 var x = 0; 8 var y = 0;  9 var width = 0;10 var height = 0;11 Allimage.foreach (function (image) {var imgurl = Image.getattribute ("ESRC"), var newlength = Urls.push (Imgurl), if (Imgurl = Picurl | | imgurl = = decodeURIComponent (picurl)) {index = newlength-1;16 x = Image.getboundingclientrect () . left;17 y = Image.getboundingclientrect (). top;18 x = x + Document.documentElement.scrollL                 Eft;19 y = y + document.documentelement.scrolltop;20 width = image.width;21 Height = image.height;22 Console.log ("x:" +x + "; y:"+ y+ "; width:" +image.width + "; height:" +image.height);}24}); Console.log ("Detected click"); 26 Bridge.callhandler (' imagedidclicked ', {' index ': index, ' x ': x, ' y ': y, ' width ': width, ' height ': height}, function ( Response) {Console.log ("JS has issued Imgurl and index, at the same time received a callback stating that OC has received the data"); 28}); 29}); 30}

Bridge.callhandler will trigger the [_bridge registerhandler:@ "imagedidclicked" handler:^ in OC (ID data, Wvjbresponsecallback Responsecallback) {}]. We can get the handler of the click image in all the pictures, and click on the picture in the current picture space position. To achieve the effect of clicking on the picture zoom-out, we should be good at "cheating". The picture in the webpage can't "jump" to enlarge, but we can make the position information of x, y, Width and height according to JS, create a uiimageview,image and the current click picture consistent, set the transparency to 0,add to UIWebView above. And through the Idmphotobrowser this open source library to achieve picture browsing.

1   [_bridge registerhandler:@ "imagedidclicked" handler:^ (ID data, Wvjbresponsecallback responsecallback) {2         Nsinteger index = [[Data objectforkey:@ "index"] integervalue]; 3         cgfloat Originx = [[Data objectforkey:@ "X"] floatvalue]; 4         cgfloat originy = [[Data objectforkey:@ "Y"] floatval UE]; 5         cgfloat width   = [[Data objectforkey:@ ' width '] floatvalue]; 6         cgfloat height  = [[Data objectforkey:@] Height "] floatvalue]; 7         tappedimageview.alpha = 0; 8         tappedimageview.frame = CGRectMake (Originx, originy, width, height); 9         Tappedimageview.image = _allimagesofthisarticle[index];//_allimagesofthisarticle is a local array used to hold all images of         the NSLog (@ " OC has received JS imagedidclicked:%@ ", data), one         responsecallback (@" OC has received JS imagedidclicked ");         click to enlarge image 13         [self Presentphotosbrowserwithinitialpage:index animatedfromview:tappedimageview];14     }];

Tips

Because I use sublime Text, so I can not do JS debugging. If you want to debug with atom, it feels a little overkill. I just want a place where you can easily see if the Console.log or JS function is called. Always believe that any problem can be solved. We can use Safari.

Connect your iphone or use the simulator, when your program currently shows a Uiwebview,safari will automatically recognize this uiwebview, and you can find your device in the Development menu bar to debug.

Choose the console, you can see the long-Lost debugging window and JS Console.log.

The above is an example of the deep interaction between UIWebView and JS using Webviewjavascriptbridge.

Toss Webviewjavascriptbridge these days down, my greatest feeling is, learning. Think of node. JS can write server, React native can develop iOS, and GitHub is the most popular language is JS, which led me to a little want to learn JS. But I calmed down again, clear my main task what, think Swift is not thoroughly understand, which have time to engage in front-end. According to my experience, let me sleep, I guess tomorrow is not the idea. ^ ^

An interactive explanation of OC and JS

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.