前言web
項目中H5與原生的交互是一個比較大的問題,固然,只要是涉及到交互邏輯的,都會很繁瑣,並非說很難,但絕對是很繁瑣的。原來項目中使用的是JavaScriptCore這個庫,經過JS與原生進行交互,可是使用下來,以爲並非很穩定,因此新版本更新的時候,準備把以前全部的交互邏輯所有拋棄,採用url跳轉並截取url信息的思路,建立通用的跳轉方法機制;session
(一)H5與原生的交互方法封裝類;app
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface H5NativeInteractTool : NSObject<NSCopying> + (H5NativeInteractTool *)shareInstance; - (void)goFromSourceController:(UIViewController *)source toTargetUrl:(NSString *)url refreshBlock:(void(^)(NSString *url))refreshBlock; - (NSString *)addParaOfSessionKeyByUrlString:(NSString *)url; @end #import "H5NativeInteractTool.h" #import "PayViewController.h" #import "Contants.h" @interface H5NativeInteractTool () @property (nonatomic,strong) UIViewController *object; @property (nonatomic,copy) void(^backRefreshBlock)(NSString *url); @end @implementation H5NativeInteractTool static H5NativeInteractTool *_h5NativeInteractTool = nil; + (H5NativeInteractTool *)shareInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (!_h5NativeInteractTool) { _h5NativeInteractTool = [[self alloc] init]; } }); return _h5NativeInteractTool; } +(instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (!_h5NativeInteractTool) { _h5NativeInteractTool = [super allocWithZone:zone]; } }); return _h5NativeInteractTool; } - (instancetype)copyWithZone:(NSZone *)zone { return _h5NativeInteractTool; } - (NSString *)addParaOfSessionKeyByUrlString:(NSString *)url { if (!url) { return nil; } if ([url rangeOfString:@"SessionKey=" options:NSCaseInsensitiveSearch].location != NSNotFound) { url = [url stringByReplacingOccurrencesOfString:@"{0}" withString:APPDELEGETE.sessionKey]; } return url; } //根據url提供的信息,跳轉至相應的原生界面,成功執行完操做最後會執行refreshBlock,回到原頁面刷新; - (void)goFromSourceController:(UIViewController *)source toTargetUrl:(NSString *)url refreshBlock:(void (^)(NSString *))refreshBlock { self.object = source; self.backRefreshBlock = refreshBlock; url = [url stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSRange start = [url rangeOfString:@":"]; NSRange end = [url rangeOfString:@"?"]; NSString *methodStr = [url substringWithRange:NSMakeRange(start.location+start.length, end.location-start.location-start.length)]; NSString *paraStr = [url substringWithRange:NSMakeRange(end.location+end.length, url.length-(end.length+end.location))]; NSData *paraData = [paraStr dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *paraDict = [NSJSONSerialization JSONObjectWithData:paraData options:NSJSONReadingAllowFragments error:nil]; if (paraDict) { methodStr = [NSString stringWithFormat:@"%@:",methodStr]; } SEL selector = NSSelectorFromString(methodStr); if (![self respondsToSelector:selector]) { return; } [self performSelector:selector withObject:paraDict afterDelay:0.1f]; } - (void)Recharge:(NSDictionary *)paraDict { PayViewController *pay = [[PayViewController alloc] init]; if ([paraDict objectForKey:@"back"]) { pay.backRefreshBlock = _backRefreshBlock; pay.backRefreshUrl = [paraDict objectForKey:@"back"]; } pay.InvestState = @"Invest"; __weak typeof(self) weakSelf = self; [weakSelf.object.navigationController pushViewController:pay animated:YES]; } @end
以上的內容只包含了一個函數;後面全部的H5交互都會採用這種形式進行交互。函數
(二)如何使用,下面給出一個例子;atom
[[H5NativeInteractTool shareInstance] goFromSourceController:self toTargetUrl:urlString refreshBlock:^(NSString *url) { __weak typeof(self) weakSelf = self; NSURLRequest *newRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0f]; [weakSelf.allWebVC loadRequest:newRequest]; weakSelf.backRefreshState = @"refresh"; }];
執行完跳轉頁面的全部邏輯成功後,最後執行refreshBlock;url
(三)webview中有回調地址的疑惑;spa
(1)上述代碼中有一個block(refreshBlock),這個主要是用來,操做成功後頁面回調所執行的刷新url的操做。我使用它以前一直是有疑問的,由於我見不少的app都沒有backurl的概念,通常都是截取url,push到新的原生界面,而後在pop回來。code
(2)我我的認爲,若是真的要實現跳轉指定的url,就應該建立一個通用的webview界面,而全部的跳轉url都會到這個webview中顯示,由於這樣控制性會相對來得好一些,webview的goBack操做,若是webview的歷史記錄混亂了,將是一個比較難忍的問題。orm