一、原生與H5頁面交互方式
- 登陸后將token放入wkwebview的cookie中。以后wkwebview也可以同步原生app的登陸狀態了。
以下代碼 @"document.cookie = 'UID=%@';document.cookie = 'CLIENT=App';document.cookie = 'TOKEN=%@'" 根據自己項目的cookie格式傳遞。
1 NSString *js = @"function clearCache(){localStorage.setItem('fundType',null);localStorage.setItem('fundTypeIndex',null);}clearCache();"; 2 NSString *cookie = 3 [NSString stringWithFormat:@"document.cookie = 'UID=%@';document.cookie = 'CLIENT=App';document.cookie = 'TOKEN=%@'", 4 [USER_DEFAULT objectForKey:KUSERUID] == nil ? @"":[USER_DEFAULT objectForKey:KUSERUID],[USER_DEFAULT objectForKey:KUSERTOKEN] == nil ?@"":[USER_DEFAULT objectForKey:KUSERTOKEN]]; 5 WKUserScript *cookieScript = [[WKUserScript alloc] 6 initWithSource:cookie 7 injectionTime:WKUserScriptInjectionTimeAtDocumentStart 8 forMainFrameOnly:YES]; 9 [self.configuration.userContentController addUserScript:cookieScript]; 10 [self reloadFromOrigin];
2、審查wkwebview中的頁面元素,提取wkwebview登陸頁面中的登陸按鈕所調用的JS代碼(盡量向js開發人員要)
然后通過這句代碼執行js:把參數傳遞到js中。讓wkwebview執行js,wkwebview就登陸了。
以下代碼 @"function clearCache(){localStorage.setItem('fundType',null);localStorage.setItem('fundTypeIndex',null);}clearCache();" 是純js代碼,ios程序可以直接使用。
1 NSString *js = @"function clearCache(){localStorage.setItem('fundType',null);localStorage.setItem('fundTypeIndex',null);}clearCache();"; 2 [self.baseWebView evaluateJavaScript:js completionHandler:^(id _Nullable other, NSError * _Nullable error) { 3 }];
3、通過該方法,截取H5頁面將要請求的頁面地址,來做原生相應的操作。這里可以讓wkwebview跳轉到“hello://uid=123_token=321”的方式來告訴原生,js傳了2個參數:uid=123 token=321(注意,這里是以hello開頭,可以寫成你們商量好的)然后通過:decisionHandler(WKNavigationActionPolicyCancel);
不讓wkwebview跳轉到“hello://uid=123_token=321”。去做我們真正要做的事情。
1 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ 2 NSString *str = navigationAction.request.URL.absoluteString;//獲取當前正在請求的url 4 if ([str isEqualToString:@"https://m.cgjr.com/"] && self.viewController.tabBarController.selectedIndex != 0) { 5 decisionHandler(WKNavigationActionPolicyCancel); 6 [self.viewController.tabBarController setSelectedIndex:0]; 7 } 8 if ([str isEqualToString:@"https://m.cgjr.com/site/login.html"] && self.viewController.tabBarController.selectedIndex == 0) { 9 decisionHandler(WKNavigationActionPolicyCancel); 10 UIStoryboard *sb = [UIStoryboard storyboardWithName:@"CGTZLogin" bundle:nil]; 11 CGTZLoginViewController *navC = [sb instantiateViewControllerWithIdentifier:@"CGTZLoginViewController"]; 12 navC.tabBarItem.title = @"登錄"; 13 [self.viewController presentViewController:navC animated:YES completion:^{ 14 }]; 15 [self.viewController.tabBarController setSelectedIndex:0]; 16 } 17 if ([str isEqualToString:@"https://m.cgjr.com/site/login.html"] && self.viewController.tabBarController.selectedIndex == 1) { 18 decisionHandler(WKNavigationActionPolicyCancel); 19 UIStoryboard *sb = [UIStoryboard storyboardWithName:@"CGTZLogin" bundle:nil]; 20 CGTZLoginViewController *navC = [sb instantiateViewControllerWithIdentifier:@"CGTZLoginViewController"]; 21 navC.tabBarItem.title = @"登錄"; 22 [self.viewController presentViewController:navC animated:YES completion:^{ 23 }]; 24 [self.viewController.tabBarController setSelectedIndex:1]; 25 } 26 if ([str isEqualToString:@"https://m.cgjr.com/site/login.html"] && self.viewController.tabBarController.selectedIndex == 2) { 27 decisionHandler(WKNavigationActionPolicyCancel); 28 UIStoryboard *sb = [UIStoryboard storyboardWithName:@"CGTZLogin" bundle:nil]; 29 CGTZLoginViewController *navC = [sb instantiateViewControllerWithIdentifier:@"CGTZLoginViewController"]; 30 navC.tabBarItem.title = @"登錄"; 31 [self.viewController presentViewController:navC animated:YES completion:^{ 32 }]; 33 [self.viewController.tabBarController setSelectedIndex:2]; 34 } 35 decisionHandler(WKNavigationActionPolicyAllow); 36 }
在Cocos2d-JS v3.0 RC2中,與Android上js調用Java一樣,Cocos2d-JS也提供了在iOS和Mac上js直接調用Objective-C的方法,示例代碼如下:
var ojb = jsb.reflection.callStaticMethod(className, methodNmae, arg1, arg2, .....);
在jsb.reflection.callStaticMethod
方法中,我們通過傳入OC的類名,方法名,參數就可以直接調用OC的靜態方法,並且可以獲得OC方法的返回值。
類
- 參數中的類名,只需要傳入OC中的類名即可,與Java不同,類名並不需要路徑。比如你在工程底下新建一個類
NativeOcClass
,只要你將他引入工程,那么他的類名就是NativeOcClass
,你並不需要傳入它的路徑。
1 import <Foundation/Foundation.h> 2 @interface NativeOcClass : NSObject 3 +(BOOL)callNativeUIWithTitle:(NSString *) title andContent:(NSString *)content; 4 @end
方法
- js到OC的反射僅支持OC中類的靜態方法。
- 方法名比較要需要注意,我們需要傳入完整的方法名,特別是當某個方法帶有參數的時候,你需要將他的**:**也帶上。根據上面的例子。此時的方法名字是**callNativeUIWithTitle:andContent:**,不要漏掉了他們之間的**:**。
- 如果是沒有參數的函數,那么他就不需要**:**,如下代碼,他的方法名是
callNativeWithReturnString
,由於沒有參數,他不需要**:**,跟OC的method寫法一致。
1 +(NSString *)callNativeWithReturnString;
使用示例
- 下面的示例代碼將調用上面
NativeOcClass
的方法,在js層我們只需要這樣調用:
1 var ret = jsb.reflection.callStaticMethod("NativeOcClass", 2 "callNativeUIWithTitle:andContent:", 3 "cocos2d-js", 4 "Yes! you call a Native UI from Reflection");
- 這里是這個方法在OC的實現,可以看到是彈出一個native的對話框。並把
title
和content
設置成你傳入的參數,並返回一個boolean類型的返回值。
1 +(BOOL)callNativeUIWithTitle:(NSString *) title andContent:(NSString *)content{ 2 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:content delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil]; 3 [alertView show]; 4 return true; 5 }
- 此時,你就可以在
ret
中接受到從OC傳回的返回值(true)了。
注意
在OC的實現中,如果方法的參數需要使用float、int、bool的,請使用如下類型進行轉換:
- float,int 請使用NSNumber類型
- bool請使用BOOL類型。
- 例如下面代碼,我們傳入2個浮點數,然后計算他們的合並返回,我們使用NSNumber而不是int、float去作為參數類型。
1 +(float) addTwoNumber:(NSNumber *)num1 and:(NSNumber *)num2{ 2 float result = [num1 floatValue]+[num2 floatValue]; 3 return result; 4 }
- 目前參數和返回值支持 int, float, bool, string,其余的類型暫時不支持。
5、wkwebview獨有,跟uiwebview的 jscontext 相似的 WKScriptMessage
js端這樣調用:紅色部分
1 function onLoaded(){ 2 changeImageSrc(); 3 var allImage = document.getElementsByClassName("img-cache"); 4 allImage = Array.prototype.slice.call(allImage, 0); 5 var imageUrlsArray = new Array(); 6 allImage.forEach(function(image) { 7 var esrc = image.getAttribute("esrc"); 8 if(esrc){ 9 var newLength = imageUrlsArray.push(esrc); 10 } 11 }); 12 window.webkit.messageHandlers.XXXApp.postMessage({"key":"getImageUrlArr","getImageUrlArr":imageUrlsArray}); 13 14 }onLoaded();
創建wkwebview時候:
1 WKWebViewConfiguration *configuration = [WKWebViewConfiguration new]; 2 configuration.selectionGranularity = WKSelectionGranularityCharacter; 3 configuration.userContentController = userVC; 4 [configuration.userContentController addScriptMessageHandler:self name:@"XXXApp"];//這里是iOS端的標識符 5 WKWebView * webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, kSCreenWidth, kSCreenHeight-64) configuration:configuration]; 6 webView.navigationDelegate = self; 7 webView.UIDelegate = self; 8 NSURL *url = [NSURL URLWithString:self.urlString]; 9 NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url]; 10 [webView loadRequest:request];
需要實現的代理方法:
1 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { 2 NSDictionary *dataDic = message.body; 3 if ([dataDic[@"key"] isEqualToString:@"getImageUrlArr"]) {//根據key的鍵值對,判斷調用哪一段代碼 4 NSArray *imageArr = dataDic[@"getImageUrlArr"]; 5 if (imageArr != nil) { 6 // js傳過來的數組我們已經拿到了!,去做你想做的! 7 } 8 } 9 if ([dataDic[@"key"] isEqualToString:@"imageDidClicked"]) { 10 // [self imageDidClicked:dataDic[@"imageDidClicked"]]; 11 } 12 if ([dataDic[@"key"] isEqualToString:@"imagesDownloadComplete"]) { 13 } 19 }
wkwebview相關參考資料:http://www.henishuo.com/wkwebview-js-h5-oc/
(swift)http://www.henishuo.com/wkwebview-js/
WKWebView所有相關的類的API漢化: http://www.henishuo.com/wkwebview-objc/