如何从Javascript调用Objective C方法并将数据发送回iOS中的Javascript?

Kri*_*nan 31 javascript objective-c uiwebview ios

在iOS中,如何从Javascript中调用Objective-C方法UIWebView并让它将数据发送回Javascript?我知道这可以使用Webkit库在OS X上完成,但是这可以在iOS上实现吗?PhoneGap如何实现这一目标?

zek*_*kel 64

有一个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;
Run Code Online (Sandbox Code Playgroud)

在那里,您可以反序列化该特殊URL并将其解释为在Objective-C端执行您想要的操作.(您应该NO在上面的shouldStartLoadWithRequest方法中返回,以便UIWebView不会使用您的虚假URL来实际发出加载网页的HTTP请求.)

如何从Objective-C运行Javascript代码

然后,您可以通过在webview上调用此方法从Objective-C运行Javascript.

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
Run Code Online (Sandbox Code Playgroud)

示例代码

我建议使用伪造的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;
Run Code Online (Sandbox Code Playgroud)

然后在UIWebView.delegateshouldStartLoadWithRequest方法,你可以检查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;
}
Run Code Online (Sandbox Code Playgroud)

(如果需要帮助将json字符串反序列化为NSDictionary,请阅读此答案.)


Yan*_*aim 12

更改页面的位置可能会导致以下问题:

  1. 所有setInterval和setTimeout立即停止在位置更改上
  2. 取消位置更改后,每个innerHTML都不起作用!
  3. 你可能会得到其他非常奇怪的错误,真的难以诊断......

这里提供的解决方案是:

继续使用相同的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;
Run Code Online (Sandbox Code Playgroud)

希望有所帮助


Ale*_*x L 5

从Objective-C:您可以将字符串中的javascript函数传递给UIWebView.网页将执行它并返回结果.这样您就可以传递变量并从Javascript中获取数据.

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
Run Code Online (Sandbox Code Playgroud)

例:

NSString *script = @"document.getElementById('myTextField').value";
NSString *output = [myWebView stringByEvaluatingJavaScriptFromString:script];
Run Code Online (Sandbox Code Playgroud)

来自Javascript:将您的数据传递到URL中.拦截UIWebViewDelegate中的URL请求.通过返回NO获取数据并中止URL请求.

<script>window.location = "url://key1/value1"; </script>
Run Code Online (Sandbox Code Playgroud)

拦截URL请求

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
Run Code Online (Sandbox Code Playgroud)