2014-05-15 53 views
0

請注意,這不是重複的,因爲我的問題中的「iOS 7中」部分,以前的行爲(以及因此回答以前的問題)已發生變化。如何在iOS 7中的UIWebView中從JavaScript調用Objective-C?

我想知道如何通過UIWebView調用JavaScript代碼可以調用iOS 7中的Objective-C代碼。這是我以前在項目中廣泛使用的東西,但是iOS 7上的行爲已隨結果以前沒有調用webView委託的didFailLoadWithError。

我以前使用的自定義網址招調用Objective-C的功能:

function invokeObjectiveC(action, target, data) { 
    var iframe = document.createElement("IFRAME"); 
    iframe.setAttribute("src", "MY-URLScheme:" + action + ":" + target + ":" + data); 
    document.documentElement.appendChild(iframe); 
    iframe.parentNode.removeChild(iframe); 
    iframe = null; 
} 

導致didFailLoadWithError的特定行:得到所謂的是這個:

document.documentElement.appendChild(iframe); 

其他常見的替代方法灑在互聯網上做同樣的事情是這樣的:

window.location = "MY-URLScheme:" + action + ":" + target + ":" + data; 

這可以在iOS 7上運行,因爲didFailLoadWithError沒有被調用,但是它有一個(已知的)問題,如果連續第二次調用它的第一次調用會丟失。

所以我想知道科爾多瓦是怎麼做的這一點,所以我下載的源代碼,並看看我認爲他們正在做類似我這樣的(3號線是不同的):

var iframe = document.createElement("IFRAME"); 
iframe.setAttribute("src", "MY-URLScheme:" + action + ":" + target + ":" + data); 
document.body.appendChild(iframe); 
iframe.parentNode.removeChild(iframe); 
iframe = null; 

但是,仍會導致didFailLoadWithError被調用。這讓我很困惑,爲什麼科爾多瓦沒有采取任何措施來糾正這種情況(假設我正確地查看了他們的代碼)。

didFailLoadWithError被調用的事實似乎並沒有被破壞,因爲頁面仍然加載並且Objective-C仍然被調用。然而,讓代碼導致錯誤方法被調用是非常令人不滿意的,所以我想找到一種替代方法。

所以問題是:是否有一種方法可以在UIWebView中可靠加載的JS內調用Objective-C,而不需要在iOS 7上調用didFailLoadWithError?

任何人都可以確認科爾多瓦正在使用上面的方式或別的什麼?

在UIWebView中使用JavaScriptCore的解決方案(與UIWebView外部相反)在iOS/fragile中看起來沒有文檔/不支持?例如:

Access the JavaScriptCore engine of a UIWebView

Trigger objective C method from javascript using JavaScriptCore in iOS 7 in ViewControllers

回答

4

iframe的解決方法是有點馬車,是不是很可靠。 JavaScriptCore是一種很好的方法,但是框架在iOS 6和iOS 5上是私有的。從UIWebView調用Objetive-C有更好更快的方法。您可以爲警報功能實施類別方法。

@implementation UIWebView (JavaScriptAlert) 
- (void)webView:(UIWebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame 
{ 
    if ([message hasPrefix:CUSTOM_SCHEME_STRING]) { 
     //process your message 
    } 
    else { 
     UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:message delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil]; 
     [alert show]; 
     [alert release]; 
    } 
} 
@end 

當您從javascript調用window.alert()方法時,上述的Objetive-C函數被調用。爲您的消息使用自定義前綴,並在需要標準警報時回退到UIAlertView。

此方法適用於iOS 5,6和7,沒有任何問題。這非常可靠。我測試過一次調用10000次警報,沒有消息丟失。 iframe解決方案並非如此,如果您快速創建iframe,則會丟失許多消息,因此您必須在您的JS代碼上實現批處理隊列,並以〜1ms的間隔同步它們。

+0

謝謝,我會試試看。如果您只在iOS 7上運行,那麼JavaScriptCore解決方案有沒有? – Gruntcakes

+0

@MortimerGoro謝謝..我想知道你是什麼意思的WebFrame參數,感謝先進的 –

+0

@MacGeek WebFrame參數是有,因爲它在runJavaScriptAlertPanelWithMessage方法的簽名。您不必在方法實現中使用它,只需忽略它。 – MortimerGoro