http://blog.csdn.net/u011619283/article/details/52135977
Recently prepared to use UIWebView implementation of the JS and native mutual invocation function, with Wkwebview to replace. By the way the search organized the JS and OC Interactive Way, very much AH. Currently I know how JS interacts with OC:
* 1. Make a URL jump in JS, then intercept the jump in OC. (This is divided into UIWebView and Wkwebview two kinds, last year because it is also compatible with iOS 6, so there is no way to use only UIWebView to do.) )
* 2. Use Wkwebview's MessageHandler.
* 3. Use the system library JavaScriptCore to make calls to each other. (launched by IOS 7)
* 4. Use of third-party library Webviewjavascriptbridge.
* 5. Use of third-party Cordova Library, formerly known as PhoneGap. (This is a library of library platforms)
* 6. The current prevailing react Native.
Last year I also wrote a summary of mutual invocation: iOS js and native OC call each other (summary).
Write a rough, so prepare to open a new directory topic to record the JS and native interaction processing method. Just record JS and oc interaction of various ways, we can according to the actual situation and the scene to choose the right way.
Today, we will introduce a detailed introduction to the use of UIWebView blocking URLs to achieve JS and OC interaction.
Why not use a third-party library or RAC?
Because of the very few interfaces that are used to invoke each other, there are 32 of them, and there is absolutely no need to use sledgehammer.
UIWebView Intercept URL
I used to be UIWebView + block URL to implement the way JS and OC interaction.
The reason is because iOS 6 is compatible.
1. Create the UIWebView and load the local HTML.
The purpose of loading the local HTML is to make it easy to write the JS call for testing, and eventually load the Web HTML.
Self. WebView = [[UIWebView Alloc] initWithFrame:Self. View. frame];Self. WebView. Delegate =SelfNsurl *htmlurl = [[NSBundle Mainbundle] urlforresource:@"Index.html" Withextension:NIL];Nsurl *htmlurl = [Nsurl urlwithstring:@ "http://www.baidu.com"];Nsurlrequest *request = [nsurlrequest requestwithurl:htmlurl]; // If you do not want the rebound effect of WebView self.webview.scrollview.bounces = NO; //uiwebview scrolling slower, here set to normal speed self.webview.scrollview.decelerationRate = uiscrollviewdecelerationratenormal; [selfself.view Addsubview:self.webview];
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
In the local HTML, I have defined several buttons to trigger the invocation of the native method, and then callback the execution result into JS.
<inputType="Button" value="Sweep" onclick="Scanclick ()"/><inputType="Button" value="Get Positioning" onclick="Locationclick ()"/><inputType="Button" value="Modify Background Color" onclick="Colorclick ()"/><inputType="Button" value="Share" onclick="Shareclick ()"/><inputType="Button" value="Payment" onclick="Payclick ()"/><inputType="Button" value="Shake" onclick="Shake ()"/><inputType="Button" value="Back" onclick="GoBack ()"/>//JS on the list of a few more representative functions:functionLoadurl(URL) {var iFrame; IFrame = Document.createelement ("IFrame"); Iframe.setattribute ("src", url); Iframe.setattribute ("Style","Display:none;"); Iframe.setattribute ("Height","0px"); Iframe.setattribute ("Width","0px"); Iframe.setattribute ("Frameborder","0"); Document.body.appendChild (iframe); //The IFRAME is useless after initiating the request, so remove it from the DOM IFrame.parentNode.removeChild (IFRAME); iframe = null;}function asyncalert (content) { SetTimeout (function () { alert (content); },1);} function locationClick () {Loadurl (function setlocation "returnvalue"). Value = location;}
1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- Ten
- one
-
- 2
- (
- )
- +
- +
- /
- 0
-
- +
-
- all
- +
- +
- +
- -
- 29
-
- +
- +
- all
-
- +
- +
- PNS
- up
l>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
Although the content of HTML is very small, there is a lot of learning:
1. Why customize a loadURL
method that is not used directly window.location.href
?
A: Because if the current page is using window.location.href
the load page while calling window.location.href
to invoke the OC native method, the loading of the Web page will be canceled.
Similarly, if window.location.href
two OC native calls are executed consecutively, it is also possible to cause the first operation to be canceled. So we use custom to loadURL
avoid this problem.
loadURL
Implementation comes from a summary of UIWebView and PhoneGap.
2. Why is the link in Loadurl using a unified scheme?
A: Easy to do interception in OC, reduce in JS call some OC not implemented method, WebView do jump. Because when I intercept URLs in OC, it is based on scheme (that is haleyAction
) to distinguish between calling native methods or normal page jumps. It then distinguishes between what is done based on the host (that is, the//after section getLocation
).
3. Why customize a asyncAlert
method?
A: Because some JS call is required OC to return the result to JS. stringByEvaluatingJavaScriptFromString
is a synchronous method that waits for the JS method to complete, and the popup alert blocks the interface waiting for the user to respond, so they may cause a deadlock. Causes the alert card to die interface. If the callback's JS is a time-consuming operation, then it is recommended to put the time-consuming operation into it setTimeout
function
.
2. Intercepting URLs
The
UIWebView has a proxy method that can intercept every request to a link. Return yes,webview will load the link, and return No,webview will not load the connection. We are handling our own URLs in this blocking proxy method.
This is my sample code:
#pragma mark-uiwebviewdelegate-( Span class= "hljs-built_in" >bool) WebView: (uiwebview *) WebView Shouldstartloadwithrequest: (nsurlrequest *) Request Navigationtype: ( Uiwebviewnavigationtype) navigationtype{ nsurl *url = Requestnsstring *scheme = [URL scheme]; if ([scheme isequaltostring:@ "haleyaction"]) { [self handlecustomaction:url]; return no; } return Span class= "Hljs-literal" >yes;}
It is very easy to intercept custom URLs through scheme, and if different methods use different scheme, then it is very troublesome to judge them.
Then, look at my method of handling the connection:
#pragma mark-private method-(void) Handlecustomaction: (Nsurl *) url{NSString *host = [URL host];if ([Host isequaltostring:@"Scanclick"]) {NSLog (@"Sweep"); }Elseif ([Host isequaltostring:@"Shareclick"]) {[Self Share:url]; }Elseif ([Host isequaltostring:@"GetLocation"]) {[Self getLocation]; }else if ([Host Isequaltostring:@ " SetColor "]) { [self changebgcolor:url]; } else if ([Host Isequaltostring:@ "payAction"] ) { [self payaction:url]; } else if ([Host Isequaltostring:@" shake "]) { [self shakeaction]; } else if ([Host Isequaltostring:@ "GoBack"]) { [ Span class= "Hljs-keyword" >self goback]; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
By the way, see how to callback the result to JS:
- (void)getLocation{ // 获取位置信息 // 将结果返回给js NSString *jsStr = [NSString stringWithFormat:@"setLocation(‘%@‘)",@"广东省深圳市南山区学府路XXXX号"]; [self.webView stringByEvaluatingJavaScriptFromString:jsStr];}
Of course, sometimes when we call the OC method in JS, we also need to pass parameters to OC, how to pass it?
Just like a GET request, put the arguments in the back:
function shareClick() { loadURL("haleyAction://shareClick?title=测试分享的标题&content=测试分享的内容&url=http://www.baidu.com");}
So what if we get to these parameters?
All parameters are in the URL's query, first by splitting the &
string, by =
splitting the parameters into key and actual values. Here's the sample code:
- (void) Share: (Nsurl *) url{Nsarray *params =[url. Query componentsseparatedbystring:@"&"];Nsmutabledictionary *tempdic = [Nsmutabledictionary dictionary];for (NSString *paramstr in params) {Nsarray *dicarray = [Paramstr componentsseparatedbystring:@"="];if (Dicarray. Count >1) {NSString *decodevalue = [dicarray[1] stringbyreplacingpercentescapesusingencoding:nsutf8stringencoding]; [Tempdic Setobject:decodevalue forkey:dicarray[0]]; } } nsstring *title = [Tempdic objectforkey:@ "title"]; NSString * Content = [Tempdic objectforkey:@ "content"]; NSString *url = [tempdic objectforkey:@ "url"]; // Perform shared actions here //return share results to js nsstring *jsstr = [nsstring stringwithformat:@ "Shareresult ('%@ ', '%@ ', '%@ ')",title,content,url]; [ self.webview stringbyevaluatingjavascriptfromstring: JSSTR];}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
3. OC Call JS method
About returning OC execution results to JS It is important to note that:
If the callback executes the JS method with parameters, and the argument is not a string, do not add 单引号
, otherwise it may cause the invocation of the JS method failed. Like me:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:userProfile options:NSJSONWritingPrettyPrinted error:nil];NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];NSString *jsStr = [NSString stringWithFormat:@"loginResult(‘%@‘,%@)",type, jsonStr];[_webView stringByEvaluatingJavaScriptFromString:jsStr];
If the second argument is wrapped in single quotation marks, it will cause the JS end of the Loginresult not to be called.
Example Project address: Js_oc_url
iOS JS and OC call each other (a)--uiwebview intercept URL