在 iOS 中,如何从 Javascript 中调用 Objective-C 方法UIWebView
并将数据发送回 Javascript?我知道这可以在 OS X 上使用 Webkit 库完成,但这在 iOS 上可行吗?PhoneGap 如何做到这一点?
如何从 Javascript 调用 Objective-C 方法并将数据发送回 iOS 中的 Javascript?
有一个 API 可以直接从 Objective-C 调用 JavaScript,但你不能直接从 Javascript 调用 Objective-C。
如何告诉您的 Objective-C 代码从 WebView 中的 Javascript 执行某些操作
您必须将您的 Javascript 操作序列化为一个特殊的 URL,并在 UIWebView 的委托shouldStartLoadWithRequest
方法中拦截该 URL 。
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType;
在那里你可以反序列化那个特殊的 URL 并解释它以在 Objective-C 端做你想做的事情。(您应该NO
在上述shouldStartLoadWithRequest
方法中返回,以便 UIWebView 不会使用您的虚假 URL 来实际发出 HTTP 请求来加载网页。)
如何从 Objective-C 运行 Javascript 代码
然后你可以通过在你的 webview 上调用这个方法从 Objective-C 运行 Javascript。
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
示例代码
我建议使用伪造的 URL 方案,这样很容易区分您的操作 URL 和合法请求之间的区别。您可以按照以下方式在 Javascript 中发出此请求:
// JavaScript to send an action to your Objective-C code
var myAppName = 'myfakeappname';
var myActionType = 'myJavascriptActionType';
var myActionParameters = {}; // put extra info into a dict if you need it
// (separating the actionType from parameters makes it easier to parse in ObjC.)
var jsonString = (JSON.stringify(myActionParameters));
var escapedJsonParameters = escape(jsonString);
var url = myAppName + '://' + myActionType + "#" + escapedJsonParameters;
document.location.href = url;
然后在UIWebView.delegate
的shouldStartLoadWithRequest
方法中,您可以检查 URL 方案和片段以检查它是正常请求还是您的特殊操作之一。(URL 的片段是#
.之后的内容。)
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
// these need to match the values defined in your JavaScript
NSString *myAppScheme = @"myfakeappname";
NSString *myActionType = @"myJavascriptActionType";
// ignore legit webview requests so they load normally
if (![request.URL.scheme isEqualToString:myAppScheme]) {
return YES;
}
// get the action from the path
NSString *actionType = request.URL.host;
// deserialize the request JSON
NSString *jsonDictString = [request.URL.fragment stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
// look at the actionType and do whatever you want here
if ([actionType isEqualToString:myActionType]) {
// do something in response to your javascript action
// if you used an action parameters dict, deserialize and inspect it here
}
// make sure to return NO so that your webview doesn't try to load your made-up URL
return NO;
}
(如果您需要帮助将 json 字符串反序列化为 NSDictionary,请阅读此答案。)
更改页面的位置可能会导致几个问题:
- 所有 setInterval 和 setTimeout 立即停止位置更改
- 取消位置更改后,每个 innerHTML 都将无法工作!
- 您可能会遇到其他非常奇怪的错误,很难诊断……
此处提供的解决方案是:
继续使用相同的 URL 技术(在 js 和 Objective-c 上),只需使用 iframe 更改位置:
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "js-frame:myObjectiveCFunction";
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
希望有帮助
从 Objective-C:您可以将字符串中的 javascript 函数传递给 UIWebView。网页将执行它并返回结果。通过这种方式,您可以传递变量并从 Javascript 取回数据。
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
例子:
NSString *script = @"document.getElementById('myTextField').value";
NSString *output = [myWebView stringByEvaluatingJavaScriptFromString:script];
来自 Javascript:在 URL 中传递您的数据。在 UIWebViewDelegate 中拦截 URL 请求。通过返回 NO 获取数据并中止 URL 请求。
<script>window.location = "url://key1/value1"; </script>
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType