我已经实现了似乎是使用UIWebView委托shouldStartLoadWithRequest()方法在iOS上从javascript到objective-c进行通信的唯一方式。
一开始似乎工作正常,但现在我注意到如果我在短时间内从javascript到objective-c多次调用,通常会忽略第二个调用(应用程序是钢琴键盘,每个按键触发对本机代码的调用,在处理多个触摸时,本机代码不会为每个手指调用。
这是我的响应javascript调用的Objective-c代码。我知道这很狡猾,但我只是想要现在有用的东西。
- (BOOL)webView:(UIWebView *)webView2 shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
// Intercept custom location change, URL begins with "js-call:"
NSString * requestString = [[request URL] absoluteString];
if ([requestString hasPrefix:@"js-call:"])
{
// Extract the selector name from the URL
NSArray * components = [requestString componentsSeparatedByString:@":"];
NSString * functionCall = [components objectAtIndex:1];
NSArray * params = [functionCall componentsSeparatedByString:@"%20"];
NSString * functionName = [params objectAtIndex:0];
// Parse playnote event
if ([functionName isEqualToString:@"playNote"])
{
NSString * param = [params objectAtIndex:1];
NoteInstanceID note_id = [m_audioController playNote:[param intValue]];
NSString * jscall = [NSString stringWithFormat:@"document.PlayNoteCallback(%i);", note_id];
NSLog(@"playNote: %i", (int)note_id);
[m_webView stringByEvaluatingJavaScriptFromString:jscall];
}
// Parse stopnote event
if ([functionName isEqualToString:@"stopNote"])
{
NSString * param = [params objectAtIndex:1];
NoteInstanceID note_id = [param intValue];
NSLog(@"stopNote: %i", (int)note_id);
[m_audioController stopNote:note_id];
}
// Parse log event
if ([functionName isEqualToString:@"debugLog"])
{
NSString * str = [requestString stringByReplacingOccurrencesOfString:@"%20" withString:@" "];
NSLog(@"%s", [str cStringUsingEncoding:NSStringEncodingConversionAllowLossy]);
}
// Cancel the location change
return NO;
}
// Accept this location change
return YES;
}
从javascript我通过设置单个隐藏iframe的src属性来调用objective-c方法。这将触发objective-c中的委托方法,然后调用所需的本机代码。
$("#app_handle").attr("src", "js-call:playNote " + key.data("pitch"));
app_handle是有问题的iframe的ID。
总而言之,我的方法的基础工作,但在短时间内多次调用不起作用。这只是我们被迫从javascript到objective-c的可怕方法的神器吗?或者我做错了什么?我知道PhoneGap做了类似的事情来达到同样的目标。我宁愿不使用PhoneGap,所以如果他们没有遇到这个问题,那么我很想知道他们正在做些什么来使这项工作。
更新
我刚发现:send a notification from javascript in UIWebView to ObjectiveC 这证实了我对快速接连的电话迷路的怀疑。显然我需要将我的呼叫混为一谈或手动延迟呼叫,以便在我再次呼叫时返回url请求。
答案 0 :(得分:4)
接受的答案无法解决问题,因为仍会忽略在处理第一个之前到达的位置更改。请参阅第一条评论。
我建议采用以下方法:
function execute(url)
{
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", url);
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
}
您重复调用execute
函数,因为每个调用都在自己的iframe中执行,所以在快速调用时不应忽略它们。
致this guy的信用。
答案 1 :(得分:1)
不是在JavaScript端对所有内容进行排队,而是使用GCD将复杂逻辑(如对音频处理程序的调用)移出主线程可能更容易,更快捷。您可以使用dispatch_async()
对事件进行排队。如果你将它们放入一个串行队列,那么它们肯定会按顺序运行,但你会更快地回到javascript。例如:
在初始化期间为对象创建队列:
self.queue = dispatch_queue_create(“player”,NULL);
在你的回调中:
if ([functionName isEqualToString:@"stopNote"])
{
NSString * param = [params objectAtIndex:1];
NoteInstanceID note_id = [param intValue];
NSLog(@"stopNote: %i", (int)note_id);
dispatch_async(self.queue, ^{[m_audioController stopNote:note_id]});
}