Deep interaction between UIWebView and JS-b

Source: Internet
Author: User

To achieve such a requirement: according to the local CSS file to show a string of Web-formatted text with only the body part of HTML, you need to spell the full HTML. In addition, you also need to disable the acquisition of HTML text in the < IMG > tag auto-loading, 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 reason to put the picture operation on the native side is the advantage: 1, can be local cache, the next time to enter 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.
Technical difficulties also have two: 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, looking through the document can only find a-(NSString ) stringbyevaluatingjavascriptfromstring: (nsstring ) script and JS simple interaction method, Failed to fulfill. 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:

@property webviewjavascriptbridge* Bridge;

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

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

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

function Connectwebviewjavascriptbridge (callback) {          if (window. Webviewjavascriptbridge) {                     callback (webviewjav Ascriptbridge)            } else {                ()     Document.addeventlistener (' Webviewjavascriptbridgeready ',    function () {                 callback (Webviewjavascriptbridge)             &NBSP ;   &NBSP;}, False)    }}   Connectwebviewjavascriptbridge (function (bridge) {      BRI Dge.init (function (message, responsecallback) {        log (' JS got a message ', message)         var data = {' Javascript responds ': ' wee! '}         log (' JS responding with ', data) &nbs P       Responsecallback (data) &NBsp  })}

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:

Bridge.registerhandler (' Testjavascripthandler ', function (data, responsecallback) {log (' OBJC called TESTJAVASCRI         Pthandler with ', data] var responsedata = {' Javascript Says ': ' Right Back atcha! '} Log (' JS responding with ', ResponseData) Responsecallback (ResponseData)})

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.

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.

...

Let's call the onLoaded () function in JS. 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.

function onLoaded () {Connectwebviewjavascriptbridge (bridge) {var allimage = Document.queryselecto         Rall ("img");         Allimage = Array.prototype.slice.call (allimage, 0);         var imageurlsarray = new Array ();             Allimage.foreach (function (image) {var esrc = Image.getattribute ("ESRC");         var newlength = Imageurlsarray.push (ESRC);          });      Bridge.send (Imageurlsarray);  }); }

--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.

pragma mark-Download all pictures-(void) Downloadallimagesinnative: (Nsarray ) imageurls{SdwebimagemanagerManager = [Sdwebimagemanager Sharedmanager]; Initializes an array of empty elements _allimagesofthisarticle = [Nsmutablearray arraywithcapacity:imageurls.count];//a local array for saving all pictures for (Nsuinteger i = 0; i < imageurls.count-1; i++)     {[_allimagesofthisarticle addobject:[nsnull null]]; } for (Nsuinteger i = 0; i < imageurls.count-1; i++) {NSString _url = imageurls[i]; [Manager Downloadimagewithurl:[nsurl Urlwithstring:_url] options:sdwebimagehighpriority progress:nil completed:^ ( UIImageImage, Nserror error, Sdimagecachetype CacheType, BOOL finished, NsurlImageURL) {if (image) {Dispatch_async (Dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^ {NSString imgB64 = [UIImageJPEGRepresentation (image, 1.0) Base64encodedstringwithoptions:                      Nsdatabase64encoding64characterlinelength]; Return the image on disk to JS NSStringkey = [Manager Cachekeyforurl:imageurl];                     NSString *source = [NSString stringwithformat:@ "data:image/png;base64,%@", imgB64];                  [_bridge callhandler:@ "Imagesdownloadcomplete" Data:@[key,source]];              });      }          }]; }  }

--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.

function Imagesdownloadcomplete (Poldurl, Pnewurl) {var allimage = document.queryselectorall ("img");     Allimage = Array.prototype.slice.call (allimage, 0); Allimage.foreach (function (image) {if (Image.getattribute ("esrc") = = Poldurl | | image.getattribute ("esrc") = = Deco         Deuricomponent (Poldurl)) {image.src = Pnewurl; }     }); }

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

Regular replacement Nsregularexpression *regex = [nsregularexpression regularexpressionwithpattern:@ "(]+esrc=\") (\S    +) \ "" "options:0 Error:nil]; result = [Regex stringbyreplacingmatchesinstring:newcontent options:0 range:nsmakerange (0, Newcontent.length) withtemplate:@ "

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.

function Onimageclick (picurl) {     connectwebviewjavascriptbridge (function (bridge) {        var allimage = Document.queryselectorall ("P img[esrc]");         allimage = Array.prototype.slice.call (allimage, 0);         var urls = new Array ();         var index =-1;         var x = 0;         var y = 0;         var width = 0;         var height = 0;         Allimage.foreach (function image) {            imgurl var = imag E.getattribute ("ESRC");             var newlength = Urls.push (Imgurl);             if (Imgurl = = Picurl | | imgurl = decodeuricomponent (Picurl)) {    &nbs P           index = newLength-1;                 x = Image.getBoundingclientrect (). Left;                 y = Image.getboundingclientrect (). Top;                 x = x + document.documentElement.scrollLeft;                 y = y + document.documentElement.scrollTop;                 width = image.width;                 height = image.height;                 Console.log ("x:" +x + "; y:" + y+ "; width:" +image.width + "; Height:" +im Age.height);            }        });          console.log ("detected clicks");          bridge.callhandler (' imagedidclicked ', {' index ': index, ' x ': x, ' y ': y, ' width ': width, ' Height ': height}, Function (response) {            Console.log ("JS has issued Imgurl and index, and has received a callback, Stating that OC has received the data ");       });    });  }

The

Bridge.callhandler triggers 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.

 [_bridge registerhandler:@ "imagedidclicked" handler:^ (ID data, Wvjbresponsecallback responsecallback) {         nsinteger index = [[Data objectforkey:@ ' index '] integervalue];       &N Bsp  cgfloat Originx = [[Data objectforkey:@ "X"] floatvalue];         CGFloat originy = [[Data objectforkey:@ "Y"] floatvalue];         cgfloat width   = [[Data objectforkey:@ ' width '] floatvalue];         cgfloat height  = [[Data objectforkey:@ "height"] floatvalue];          tappedimageview.alpha = 0;         Tappedimageview.frame = CGRectMake (Originx, originy, width, height);         Tappedimageview.image = _allimagesofthisarticle[index];//_ Allimagesofthisarticle is a local array to hold all images          nslog (@ "OC has received JS imagedidclicked:%@", data) ;         Responsecallback (@ "OC has received JS ImagedidclickeD ");          //Click to enlarge image         [self presentphotosbrowserwithinitialpage:index an Imatedfromview:tappedimageview];    }];

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.

Deep interaction between UIWebView and JS-b

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.