diff --git a/README.md b/README.md index 644cb4b..fe40920 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ English| [中文简体](https://github.com/wendux/DSBridge-IOS/blob/master/readme-chs.md) -# DSBridge for IOS +# DSBridge for iOS ![dsBridge](https://github.com/wendux/DSBridge-IOS/raw/master/img/dsbridge.png) @@ -70,12 +70,12 @@ To use a dsBridge in your own project: ... @implementation JsApiTest //for synchronous invocation - - (NSString *) testSyn:(NSString *) msg + - (NSString *)testSyn:(NSString *)msg { return [msg stringByAppendingString:@"[ syn call]"]; } //for asynchronous invocation - - (void) testAsyn:(NSString *) msg :(JSCallback)completionHandler + - (void)testAsyn:(NSString *)msg callback:(JSCallback)completionHandler { completionHandler([msg stringByAppendingString:@" [ asyn call]"],YES); } @@ -85,7 +85,7 @@ To use a dsBridge in your own project: 2. add API object to DWKWebView ```objective-c - DWKWebView * dwebview=[[DWKWebView alloc] initWithFrame:bounds]; + DWKWebView *dwebview = [[DWKWebView alloc] initWithFrame:bounds]; // register api object without namespace [dwebview addJavascriptObject:[[JsApiTest alloc] init] namespace:nil]; ``` @@ -197,21 +197,21 @@ Normally, when a API is called to end, it returns a result, which corresponds on In Object-c ```objective-c -- ( void )callProgress:(NSDictionary *) args :(JSCallback)completionHandler -{ - value=10; - hanlder=completionHandler; - timer = [NSTimer scheduledTimerWithTimeInterval:1.0 - target:self - selector:@selector(onTimer:) - userInfo:nil - repeats:YES]; +- (void)callProgress:(NSDictionary *)args callback:(JSCallback)completionHandler { + value = 10; + hanlder = completionHandler; + timer = [NSTimer scheduledTimerWithTimeInterval:1.0 + target:self + selector:@selector(onTimer:) + userInfo:nil + repeats:YES]; } --(void)onTimer:t{ - if(value!=-1){ - hanlder([NSNumber numberWithInt:value--],NO); - }else{ - hanlder(@"",YES); + +- (void)onTimer:t { + if (value != -1) { + hanlder([NSNumber numberWithInt:value--], NO); + } else { + hanlder(@"", YES); [timer invalidate]; } } @@ -261,14 +261,14 @@ Example: ```objective-c @implementation JsEchoApi -- (id) syn:(id) arg -{ +- (id)syn:(id)arg { return arg; } -- (void) asyn: (id) arg :(JSCallback)completionHandler -{ - completionHandler(arg,YES); + +- (void)asyn:(id)arg callback:(JSCallback)completionHandler { + completionHandler(arg, YES); } + @end // register api object with namespace "echo" [dwebview addJavascriptObject:[[JsEchoApi alloc] init] namespace:@"echo"]; @@ -282,7 +282,7 @@ var ret=dsBridge.call("echo.syn",{msg:" I am echoSyn call", tag:1}) alert(JSON.stringify(ret)) // call echo.asyn dsBridge.call("echo.asyn",{msg:" I am echoAsyn call",tag:2},function (ret) { - alert(JSON.stringify(ret)); + alert(JSON.stringify(ret)); }) ``` @@ -294,11 +294,11 @@ Remove the Object-c API object with supplied namespace. -##### `callHandler:(NSString *) methodName arguments:(NSArray *) args` +##### `callHandler:(NSString *)methodName arguments:(NSArray *)args` -##### `callHandler:(NSString *) methodName completionHandler:(void (^)(id value))completionHandler` +##### `callHandler:(NSString *)methodName completionHandler:(void (^)(id value))completionHandler` -##### `callHandler:(NSString *) methodName arguments:(NSArray *) args completionHandler:(void (^ )(id value))completionHandler` +##### `callHandler:(NSString *)methodName arguments:(NSArray *)args completionHandler:(void (^ )(id value))completionHandler` Call the javascript API. If a `completionHandler` is given, the javascript handler can respond. the `methodName` can contain the namespace. **The completionHandler will be called in main thread**. @@ -307,11 +307,11 @@ Example: ```objective-c [dwebview callHandler:@"append" arguments:@[@"I",@"love",@"you"] completionHandler:^(NSString * _Nullable value) { - NSLog(@"call succeed, append string is: %@",value); + NSLog(@"call succeed, append string is: %@",value); }]; // call with namespace 'syn', More details to see the Demo project [dwebview callHandler:@"syn.getInfo" completionHandler:^(NSDictionary * _Nullable value) { - NSLog(@"Namespace syn.getInfo: %@",value); + NSLog(@"Namespace syn.getInfo: %@",value); }]; ``` @@ -324,7 +324,7 @@ BE CAREFUL to use. if you call any of the javascript popup box functions (`alert Example: ```objective-c -[dwebview disableJavascriptDialogBlock: true] +[dwebview disableJavascriptDialogBlock:true] ``` if you want to enable the block, just calling this method with the argument value `false` . @@ -339,7 +339,7 @@ Example: ```objective-c [dwebview setJavascriptCloseWindowListener:^{ - NSLog(@"window.close called"); + NSLog(@"window.close called"); }]; ``` @@ -354,7 +354,7 @@ Example: ```objective-c // test if javascript method exists. [dwebview hasJavascriptMethod:@"addValue" methodExistCallback:^(bool exist) { - NSLog(@"method 'addValue' exist : %d",exist); + NSLog(@"method 'addValue' exist : %d",exist); }]; ``` @@ -430,7 +430,7 @@ Register javascript synchronous and asynchronous API for Native invocation. The ```objective-c // call javascript method [dwebview callHandler:@"addValue" arguments:@[@3,@4] completionHandler:^(NSNumber * value){ - NSLog(@"%@",value); + NSLog(@"%@",value); }]; [dwebview callHandler:@"append" arguments:@[@"I",@"love",@"you"] completionHandler:^(NSString * _Nullable value) { diff --git a/dsBridge.podspec b/dsBridge.podspec index 27d5839..2744f2d 100644 --- a/dsBridge.podspec +++ b/dsBridge.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| # s.name = "dsBridge" - s.version = "3.0.6" + s.version = "3.0.7" s.summary = "An ios bridge for calling functions synchronously and asynchronously between JavaScript and Object-C in WKWebView/UIWebView" # This description is used to generate tags and improve search results. diff --git a/dsbridge.xcodeproj/project.pbxproj b/dsbridge.xcodeproj/project.pbxproj index b9da3f3..e2e4abd 100644 --- a/dsbridge.xcodeproj/project.pbxproj +++ b/dsbridge.xcodeproj/project.pbxproj @@ -253,6 +253,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -466,7 +467,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "dsbridgedemo/dsbridgedemo-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -483,7 +484,7 @@ PRODUCT_BUNDLE_IDENTIFIER = wendu.dsbridgedemo.xx; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "dsbridgedemo/dsbridgedemo-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/dsbridge/DSCallInfo.h b/dsbridge/DSCallInfo.h index f847d96..bc3ac7c 100644 --- a/dsbridge/DSCallInfo.h +++ b/dsbridge/DSCallInfo.h @@ -2,7 +2,7 @@ #import @interface DSCallInfo : NSObject -@property (nullable, nonatomic) NSString* method; -@property (nullable, nonatomic) NSNumber* id; -@property (nullable,nonatomic) NSArray * args; +@property (nullable, nonatomic) NSString *method; +@property (nullable, nonatomic) NSNumber *id; +@property (nullable, nonatomic) NSArray *args; @end diff --git a/dsbridge/DWKWebView.h b/dsbridge/DWKWebView.h index 365f526..1fab9ae 100644 --- a/dsbridge/DWKWebView.h +++ b/dsbridge/DWKWebView.h @@ -8,21 +8,38 @@ #import -typedef void (^JSCallback)(NSString * _Nullable result,BOOL complete); +typedef void (^JSCallback)(NSString *_Nullable result, BOOL complete); @interface DWKWebView : WKWebView -@property (nullable, nonatomic, weak) id DSUIDelegate; +/// Delegate +@property (nullable, nonatomic, weak) id DSUIDelegate; -- (void)loadUrl: (NSString * _Nonnull) url; +/// Load web use the url. +/// @param url the url of the web page. +- (void)loadUrl:(NSString *_Nonnull)url; -// Call javascript handler --(void) callHandler:(NSString * _Nonnull) methodName arguments:(NSArray * _Nullable) args; --(void) callHandler:(NSString * _Nonnull) methodName completionHandler:(void (^ _Nullable)(id _Nullable value))completionHandler; --(void) callHandler:(NSString * _Nonnull) methodName arguments:(NSArray * _Nullable) args completionHandler:(void (^ _Nullable)(id _Nullable value))completionHandler; +/// Call javascript method +/// @param methodName js called method name. +/// @param args the method's args. +- (void)callHandler:(NSString *_Nonnull)methodName arguments:(NSArray *_Nullable)args; + +/// Call javascript method +/// @param methodName js called method name. +/// @param completionHandler completion handler block. +- (void)callHandler:(NSString *_Nonnull)methodName completionHandler:(void (^_Nullable)(id _Nullable value))completionHandler; + + +/// Call javascript method +/// @param methodName js called method name. +/// @param args the method's args. +/// @param completionHandler completion handler block. +- (void)callHandler:(NSString *_Nonnull)methodName + arguments:(NSArray *_Nullable)args + completionHandler:(void (^_Nullable)(id _Nullable value))completionHandler; // set a listener for javascript closing the current page. -- (void)setJavascriptCloseWindowListener:(void(^_Nullable)(void))callback; +- (void)setJavascriptCloseWindowListener:(void (^_Nullable)(void))callback; /** * Add a Javascript Object to dsBridge with namespace. @@ -31,24 +48,24 @@ typedef void (^JSCallback)(NSString * _Nullable result,BOOL complete); * @param namespace * if empty, the object have no namespace. **/ -- (void)addJavascriptObject:(id _Nullable ) object namespace:(NSString * _Nullable) namespace; +- (void)addJavascriptObject:(id _Nullable)object namespace:(NSString *_Nullable)namespace; // Remove the Javascript Object with the supplied namespace -- (void)removeJavascriptObject:(NSString * _Nullable) namespace; +- (void)removeJavascriptObject:(NSString *_Nullable)namespace; // Test whether the handler exist in javascript -- (void) hasJavascriptMethod:(NSString * _Nonnull) handlerName methodExistCallback:(void(^ _Nullable)(bool exist))callback; +- (void)hasJavascriptMethod:(NSString *_Nonnull)handlerName methodExistCallback:(void (^_Nullable)(bool exist))callback; // Set debug mode. if in debug mode, some errors will be prompted by a dialog // and the exception caused by the native handlers will not be captured. -- (void) setDebugMode:(bool) debug; +- (void)setDebugMode:(bool)debug; -- (void) disableJavascriptDialogBlock:(bool) disable; +- (void)disableJavascriptDialogBlock:(bool)disable; // custom the label text of javascript dialog that includes alert/confirm/prompt -- (void) customJavascriptDialogLabelTitles:(NSDictionary*_Nullable) dic; +- (void)customJavascriptDialogLabelTitles:(NSDictionary *_Nullable)dic; // private method, the developer shoudn't call this method -- (id _Nullable ) onMessage:(NSDictionary *_Nonnull) msg type:(int) type; +- (id _Nullable)onMessage:(NSDictionary *_Nonnull)msg type:(int)type; @end diff --git a/dsbridge/DWKWebView.m b/dsbridge/DWKWebView.m index 1bfbbff..275e291 100644 --- a/dsbridge/DWKWebView.m +++ b/dsbridge/DWKWebView.m @@ -1,419 +1,401 @@ #import "DWKWebView.h" -#import "JSBUtil.h" #import "DSCallInfo.h" #import "InternalApis.h" +#import "JSBUtil.h" #import -@implementation DWKWebView -{ +@implementation DWKWebView { void (^alertHandler)(void); void (^confirmHandler)(BOOL); void (^promptHandler)(NSString *); - void(^javascriptCloseWindowListener)(void); + void (^javascriptCloseWindowListener)(void); int dialogType; int callId; bool jsDialogBlock; - NSMutableDictionary *javaScriptNamespaceInterfaces; + NSMutableDictionary *javaScriptNamespaceInterfaces; NSMutableDictionary *handerMap; - NSMutableArray * callInfoList; - NSDictionary *dialogTextDic; + NSMutableArray *callInfoList; + NSDictionary *dialogTextDic; UITextField *txtName; - UInt64 lastCallTime ; + UInt64 lastCallTime; NSString *jsCache; bool isPending; bool isDebug; } - --(instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration -{ - txtName=nil; - dialogType=0; - callId=0; - alertHandler=nil; - confirmHandler=nil; - promptHandler=nil; - jsDialogBlock=true; - callInfoList=[NSMutableArray array]; - javaScriptNamespaceInterfaces=[NSMutableDictionary dictionary]; - handerMap=[NSMutableDictionary dictionary]; +- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration { + txtName = nil; + dialogType = 0; + callId = 0; + alertHandler = nil; + confirmHandler = nil; + promptHandler = nil; + jsDialogBlock = true; + callInfoList = [NSMutableArray array]; + javaScriptNamespaceInterfaces = [NSMutableDictionary dictionary]; + handerMap = [NSMutableDictionary dictionary]; lastCallTime = 0; - jsCache=@""; - isPending=false; - isDebug=false; - dialogTextDic=@{}; - + jsCache = @""; + isPending = false; + isDebug = false; + dialogTextDic = @{}; + WKUserScript *script = [[WKUserScript alloc] initWithSource:@"window._dswk=true;" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]; [configuration.userContentController addUserScript:script]; - self = [super initWithFrame:frame configuration: configuration]; + self = [super initWithFrame:frame configuration:configuration]; if (self) { - super.UIDelegate=self; + super.UIDelegate = self; } // add internal Javascript Object - InternalApis * interalApis= [[InternalApis alloc] init]; - interalApis.webview=self; + InternalApis *interalApis = [[InternalApis alloc] init]; + interalApis.webview = self; [self addJavascriptObject:interalApis namespace:@"_dsb"]; return self; } - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt - defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame -completionHandler:(void (^)(NSString * _Nullable result))completionHandler -{ - NSString * prefix=@"_dsbridge="; - if ([prompt hasPrefix:prefix]) - { - NSString *method= [prompt substringFromIndex:[prefix length]]; - NSString *result=nil; - if(isDebug){ - result =[self call:method :defaultText ]; - }else{ + defaultText:(nullable NSString *)defaultText + initiatedByFrame:(WKFrameInfo *)frame + completionHandler:(void (^)(NSString *_Nullable result))completionHandler { + NSString *prefix = @"_dsbridge="; + if ([prompt hasPrefix:prefix]) { + NSString *method = [prompt substringFromIndex:[prefix length]]; + NSString *result = nil; + if (isDebug) { + result = [self call:method argStr:defaultText]; + } else { @try { - result =[self call:method :defaultText ]; - }@catch(NSException *exception){ + result = [self call:method argStr:defaultText]; + } @catch (NSException *exception) { NSLog(@"%@", exception); } } completionHandler(result); - - }else { - if(!jsDialogBlock){ + + } else { + if (!jsDialogBlock) { completionHandler(nil); } - if(self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: - @selector(webView:runJavaScriptTextInputPanelWithPrompt - :defaultText:initiatedByFrame - :completionHandler:)]) - { - return [self.DSUIDelegate webView:webView runJavaScriptTextInputPanelWithPrompt:prompt - defaultText:defaultText - initiatedByFrame:frame - completionHandler:completionHandler]; - }else{ - dialogType=3; - if(jsDialogBlock){ - promptHandler=completionHandler; + if (self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: + @selector(webView: + runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame + :completionHandler:)]) { + return [self.DSUIDelegate webView:webView + runJavaScriptTextInputPanelWithPrompt:prompt + defaultText:defaultText + initiatedByFrame:frame + completionHandler:completionHandler]; + } else { + dialogType = 3; + if (jsDialogBlock) { + promptHandler = completionHandler; } UIAlertView *alert = [[UIAlertView alloc] - initWithTitle:prompt - message:@"" - delegate:self - cancelButtonTitle:dialogTextDic[@"promptCancelBtn"]?dialogTextDic[@"promptCancelBtn"]:@"取消" - otherButtonTitles:dialogTextDic[@"promptOkBtn"]?dialogTextDic[@"promptOkBtn"]:@"确定", + initWithTitle:prompt + message:@"" + delegate:self + cancelButtonTitle:dialogTextDic[@"promptCancelBtn"] ? dialogTextDic[@"promptCancelBtn"] : @"取消" + otherButtonTitles:dialogTextDic[@"promptOkBtn"] ? dialogTextDic[@"promptOkBtn"] : @"确定", nil]; [alert setAlertViewStyle:UIAlertViewStylePlainTextInput]; txtName = [alert textFieldAtIndex:0]; - txtName.text=defaultText; + txtName.text = defaultText; [alert show]; } } } - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message -initiatedByFrame:(WKFrameInfo *)frame -completionHandler:(void (^)(void))completionHandler -{ - if(!jsDialogBlock){ + initiatedByFrame:(WKFrameInfo *)frame + completionHandler:(void (^)(void))completionHandler { + if (!jsDialogBlock) { completionHandler(); } - if( self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: - @selector(webView:runJavaScriptAlertPanelWithMessage - :initiatedByFrame:completionHandler:)]) - { - return [self.DSUIDelegate webView:webView runJavaScriptAlertPanelWithMessage:message - initiatedByFrame:frame - completionHandler:completionHandler]; - }else{ - dialogType=1; - if(jsDialogBlock){ - alertHandler=completionHandler; + if (self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: + @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)]) { + return [self.DSUIDelegate webView:webView + runJavaScriptAlertPanelWithMessage:message + initiatedByFrame:frame + completionHandler:completionHandler]; + } else { + dialogType = 1; + if (jsDialogBlock) { + alertHandler = completionHandler; } UIAlertView *alertView = - [[UIAlertView alloc] initWithTitle:dialogTextDic[@"alertTitle"]?dialogTextDic[@"alertTitle"]:@"提示" - message:message - delegate:self - cancelButtonTitle:dialogTextDic[@"alertBtn"]?dialogTextDic[@"alertBtn"]:@"确定" - otherButtonTitles:nil,nil]; + [[UIAlertView alloc] initWithTitle:dialogTextDic[@"alertTitle"] ? dialogTextDic[@"alertTitle"] : @"提示" + message:message + delegate:self + cancelButtonTitle:dialogTextDic[@"alertBtn"] ? dialogTextDic[@"alertBtn"] : @"确定" + otherButtonTitles:nil, nil]; [alertView show]; } } --(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message -initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler -{ - if(!jsDialogBlock){ +- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message + initiatedByFrame:(WKFrameInfo *)frame + completionHandler:(void (^)(BOOL))completionHandler { + if (!jsDialogBlock) { completionHandler(YES); } - if( self.DSUIDelegate&& [self.DSUIDelegate respondsToSelector: - @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]) - { - return[self.DSUIDelegate webView:webView runJavaScriptConfirmPanelWithMessage:message - initiatedByFrame:frame - completionHandler:completionHandler]; - }else{ - dialogType=2; - if(jsDialogBlock){ - confirmHandler=completionHandler; + if (self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: + @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]) { + return [self.DSUIDelegate webView:webView + runJavaScriptConfirmPanelWithMessage:message + initiatedByFrame:frame + completionHandler:completionHandler]; + } else { + dialogType = 2; + if (jsDialogBlock) { + confirmHandler = completionHandler; } UIAlertView *alertView = - [[UIAlertView alloc] initWithTitle:dialogTextDic[@"confirmTitle"]?dialogTextDic[@"confirmTitle"]:@"提示" - message:message - delegate:self - cancelButtonTitle:dialogTextDic[@"confirmCancelBtn"]?dialogTextDic[@"confirmCancelBtn"]:@"取消" - otherButtonTitles:dialogTextDic[@"confirmOkBtn"]?dialogTextDic[@"confirmOkBtn"]:@"确定", nil]; + [[UIAlertView alloc] initWithTitle:dialogTextDic[@"confirmTitle"] ? dialogTextDic[@"confirmTitle"] : @"提示" + message:message + delegate:self + cancelButtonTitle:dialogTextDic[@"confirmCancelBtn"] ? dialogTextDic[@"confirmCancelBtn"] : @"取消" + otherButtonTitles:dialogTextDic[@"confirmOkBtn"] ? dialogTextDic[@"confirmOkBtn"] : @"确定", nil]; [alertView show]; } } -- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{ - if( self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: - @selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)]){ +- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { + if (self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: + @selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)]) { return [self.DSUIDelegate webView:webView createWebViewWithConfiguration:configuration forNavigationAction:navigationAction windowFeatures:windowFeatures]; } - return nil; + return nil; } -- (void)webViewDidClose:(WKWebView *)webView{ - if( self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: - @selector(webViewDidClose:)]){ +- (void)webViewDidClose:(WKWebView *)webView { + if (self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: + @selector(webViewDidClose:)]) { [self.DSUIDelegate webViewDidClose:webView]; } } -- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo{ - if( self.DSUIDelegate - && [self.DSUIDelegate respondsToSelector: - @selector(webView:shouldPreviewElement:)]){ - return [self.DSUIDelegate webView:webView shouldPreviewElement:elementInfo]; - } +- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo { + if (self.DSUIDelegate && [self.DSUIDelegate respondsToSelector: + @selector(webView:shouldPreviewElement:)]) { + return [self.DSUIDelegate webView:webView shouldPreviewElement:elementInfo]; + } return NO; } -- (UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray> *)previewActions{ - if( self.DSUIDelegate && - [self.DSUIDelegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]){ +- (UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray> *)previewActions { + if (self.DSUIDelegate && + [self.DSUIDelegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]) { return [self.DSUIDelegate - webView:webView - previewingViewControllerForElement:elementInfo - defaultActions:previewActions - ]; + webView:webView + previewingViewControllerForElement:elementInfo + defaultActions:previewActions]; } - return nil; + return nil; } - -- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController{ - if( self.DSUIDelegate - && [self.DSUIDelegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]){ +- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController { + if (self.DSUIDelegate && [self.DSUIDelegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]) { return [self.DSUIDelegate webView:webView commitPreviewingViewController:previewingViewController]; } } -- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex -{ - if(dialogType==1 && alertHandler){ +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + if (dialogType == 1 && alertHandler) { alertHandler(); - alertHandler=nil; - }else if(dialogType==2 && confirmHandler){ - confirmHandler(buttonIndex==1?YES:NO); - confirmHandler=nil; - }else if(dialogType==3 && promptHandler && txtName) { - if(buttonIndex==1){ + alertHandler = nil; + } else if (dialogType == 2 && confirmHandler) { + confirmHandler(buttonIndex == 1 ? YES : NO); + confirmHandler = nil; + } else if (dialogType == 3 && promptHandler && txtName) { + if (buttonIndex == 1) { promptHandler([txtName text]); - }else{ + } else { promptHandler(@""); } - promptHandler=nil; - txtName=nil; + promptHandler = nil; + txtName = nil; } } -- (void) evalJavascript:(int) delay{ +- (void)evalJavascript:(int)delay { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{ - @synchronized(self){ - if([jsCache length]!=0){ - [self evaluateJavaScript :jsCache completionHandler:nil]; - isPending=false; - jsCache=@""; - lastCallTime=[[NSDate date] timeIntervalSince1970]*1000; + @synchronized(self) { + if ([jsCache length] != 0) { + [self evaluateJavaScript:jsCache completionHandler:nil]; + isPending = false; + jsCache = @""; + lastCallTime = [[NSDate date] timeIntervalSince1970] * 1000; } } }); } --(NSString *)call:(NSString*) method :(NSString*) argStr -{ - NSArray *nameStr=[JSBUtil parseNamespace:[method stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]]; +- (NSString *)call:(NSString *)method argStr:(NSString *)argStr { + NSArray *nameStr = [JSBUtil parseNamespace:[method stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]]; - id JavascriptInterfaceObject=javaScriptNamespaceInterfaces[nameStr[0]]; - NSString *error=[NSString stringWithFormat:@"Error! \n Method %@ is not invoked, since there is not a implementation for it",method]; - NSMutableDictionary*result =[NSMutableDictionary dictionaryWithDictionary:@{@"code":@-1,@"data":@""}]; - if(!JavascriptInterfaceObject){ + id JavascriptInterfaceObject = javaScriptNamespaceInterfaces[nameStr[0]]; + NSString *error = [NSString stringWithFormat:@"Error! \n Method %@ is not invoked, since there is not a implementation for it", method]; + NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:@{@"code" : @-1, @"data" : @""}]; + if (!JavascriptInterfaceObject) { NSLog(@"Js bridge called, but can't find a corresponded JavascriptObject , please check your code!"); - }else{ - method=nameStr[1]; - NSString *methodOne = [JSBUtil methodByNameArg:1 selName:method class:[JavascriptInterfaceObject class]]; - NSString *methodTwo = [JSBUtil methodByNameArg:2 selName:method class:[JavascriptInterfaceObject class]]; - SEL sel=NSSelectorFromString(methodOne); - SEL selasyn=NSSelectorFromString(methodTwo); - NSDictionary * args=[JSBUtil jsonStringToObject:argStr]; - id arg=args[@"data"]; - if(arg==[NSNull null]){ - arg=nil; + } else { + method = nameStr[1]; + NSString *methodOne = [JSBUtil methodByNameArg:1 selName:method objClass:[JavascriptInterfaceObject class]]; + NSString *methodTwo = [JSBUtil methodByNameArg:2 selName:method objClass:[JavascriptInterfaceObject class]]; + SEL sel = NSSelectorFromString(methodOne); + SEL selasyn = NSSelectorFromString(methodTwo); + NSDictionary *args = [JSBUtil jsonStringToObject:argStr]; + id arg = args[@"data"]; + if (arg == [NSNull null]) { + arg = nil; } - NSString * cb; - do{ - if(args && (cb= args[@"_dscbstub"])){ - if([JavascriptInterfaceObject respondsToSelector:selasyn]){ + NSString *cb; + do { + if (args && (cb = args[@"_dscbstub"])) { + if ([JavascriptInterfaceObject respondsToSelector:selasyn]) { __weak typeof(self) weakSelf = self; - void (^completionHandler)(id,BOOL) = ^(id value,BOOL complete){ - NSString *del=@""; - result[@"code"]=@0; - if(value!=nil){ - result[@"data"]=value; + void (^completionHandler)(id, BOOL) = ^(id value, BOOL complete) { + NSString *del = @""; + result[@"code"] = @0; + if (value != nil) { + result[@"data"] = value; } - value=[JSBUtil objToJsonString:result]; - value=[value stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; - - if(complete){ - del=[@"delete window." stringByAppendingString:cb]; + value = [JSBUtil objToJsonString:result]; + value = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + if (complete) { + del = [@"delete window." stringByAppendingString:cb]; } - NSString*js=[NSString stringWithFormat:@"try {%@(JSON.parse(decodeURIComponent(\"%@\")).data);%@; } catch(e){};",cb,(value == nil) ? @"" : value,del]; + NSString *js = [NSString stringWithFormat:@"try {%@(JSON.parse(decodeURIComponent(\"%@\")).data);%@; } catch(e){};", cb, (value == nil) ? @"" : value, del]; __strong typeof(self) strongSelf = weakSelf; - @synchronized(self) - { - UInt64 t=[[NSDate date] timeIntervalSince1970]*1000; - jsCache=[jsCache stringByAppendingString:js]; - if(t-lastCallTime<50){ - if(!isPending){ + @synchronized(self) { + UInt64 t = [[NSDate date] timeIntervalSince1970] * 1000; + jsCache = [jsCache stringByAppendingString:js]; + if (t - lastCallTime < 50) { + if (!isPending) { [strongSelf evalJavascript:50]; - isPending=true; + isPending = true; } - }else{ + } else { [strongSelf evalJavascript:0]; } } - }; - - void(*action)(id,SEL,id,id) = (void(*)(id,SEL,id,id))objc_msgSend; - action(JavascriptInterfaceObject,selasyn,arg,completionHandler); + + void (*action)(id, SEL, id, id) = (void (*)(id, SEL, id, id))objc_msgSend; + action(JavascriptInterfaceObject, selasyn, arg, completionHandler); break; } - }else if([JavascriptInterfaceObject respondsToSelector:sel]){ + } else if ([JavascriptInterfaceObject respondsToSelector:sel]) { id ret; - id(*action)(id,SEL,id) = (id(*)(id,SEL,id))objc_msgSend; - ret=action(JavascriptInterfaceObject,sel,arg); + id (*action)(id, SEL, id) = (id(*)(id, SEL, id))objc_msgSend; + ret = action(JavascriptInterfaceObject, sel, arg); [result setValue:@0 forKey:@"code"]; - if(ret!=nil){ + if (ret != nil) { [result setValue:ret forKey:@"data"]; } break; } - NSString*js=[error stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; - if(isDebug){ - js=[NSString stringWithFormat:@"window.alert(decodeURIComponent(\"%@\"));",js]; - [self evaluateJavaScript :js completionHandler:nil]; + NSString *js = [error stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + if (isDebug) { + js = [NSString stringWithFormat:@"window.alert(decodeURIComponent(\"%@\"));", js]; + [self evaluateJavaScript:js completionHandler:nil]; } - NSLog(@"%@",error); - }while (0); + NSLog(@"%@", error); + } while (0); } return [JSBUtil objToJsonString:result]; } -- (void)setJavascriptCloseWindowListener:(void (^)(void))callback -{ - javascriptCloseWindowListener=callback; +- (void)setJavascriptCloseWindowListener:(void (^)(void))callback { + javascriptCloseWindowListener = callback; } -- (void)setDebugMode:(bool)debug{ - isDebug=debug; +- (void)setDebugMode:(bool)debug { + isDebug = debug; } -- (void)loadUrl: (NSString *)url -{ - NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; +- (void)loadUrl:(NSString *)url { + NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; [self loadRequest:request]; } - -- (void)callHandler:(NSString *)methodName arguments:(NSArray *)args{ +- (void)callHandler:(NSString *)methodName arguments:(NSArray *)args { [self callHandler:methodName arguments:args completionHandler:nil]; } -- (void)callHandler:(NSString *)methodName completionHandler:(void (^)(id _Nullable))completionHandler{ +- (void)callHandler:(NSString *)methodName completionHandler:(void (^)(id _Nullable))completionHandler { [self callHandler:methodName arguments:nil completionHandler:completionHandler]; } --(void)callHandler:(NSString *)methodName arguments:(NSArray *)args completionHandler:(void (^)(id _Nullable value))completionHandler -{ - DSCallInfo *callInfo=[[DSCallInfo alloc] init]; - callInfo.id=[NSNumber numberWithInt: callId++]; - callInfo.args=args==nil?@[]:args; - callInfo.method=methodName; - if(completionHandler){ +- (void)callHandler:(NSString *)methodName arguments:(NSArray *)args completionHandler:(void (^)(id _Nullable value))completionHandler { + DSCallInfo *callInfo = [[DSCallInfo alloc] init]; + callInfo.id = [NSNumber numberWithInt:callId++]; + callInfo.args = args == nil ? @[] : args; + callInfo.method = methodName; + if (completionHandler) { [handerMap setObject:completionHandler forKey:callInfo.id]; } - if(callInfoList!=nil){ + if (callInfoList != nil) { [callInfoList addObject:callInfo]; - }else{ + } else { [self dispatchJavascriptCall:callInfo]; } } -- (void)dispatchStartupQueue{ - if(callInfoList==nil) return; - for (DSCallInfo * callInfo in callInfoList) { +- (void)dispatchStartupQueue { + if (callInfoList == nil) + return; + for (DSCallInfo *callInfo in callInfoList) { [self dispatchJavascriptCall:callInfo]; } - callInfoList=nil; + callInfoList = nil; } -- (void) dispatchJavascriptCall:(DSCallInfo*) info{ - NSString * json=[JSBUtil objToJsonString:@{@"method":info.method,@"callbackId":info.id, - @"data":[JSBUtil objToJsonString: info.args]}]; - [self evaluateJavaScript:[NSString stringWithFormat:@"window._handleMessageFromNative(%@)",json] +- (void)dispatchJavascriptCall:(DSCallInfo *)info { + NSString *json = [JSBUtil objToJsonString:@{@"method" : info.method, @"callbackId" : info.id, @"data" : [JSBUtil objToJsonString:info.args]}]; + [self evaluateJavaScript:[NSString stringWithFormat:@"window._handleMessageFromNative(%@)", json] completionHandler:nil]; } -- (void) addJavascriptObject:(id)object namespace:(NSString *)namespace{ - if(namespace==nil){ - namespace=@""; +- (void)addJavascriptObject:(id)object namespace:(NSString *)namespace { + if (namespace == nil) { + namespace = @""; } - if(object!=NULL){ + if (object != NULL) { [javaScriptNamespaceInterfaces setObject:object forKey:namespace]; } } -- (void) removeJavascriptObject:(NSString *)namespace { - if(namespace==nil){ - namespace=@""; +- (void)removeJavascriptObject:(NSString *)namespace { + if (namespace == nil) { + namespace = @""; } [javaScriptNamespaceInterfaces removeObjectForKey:namespace]; } -- (void)customJavascriptDialogLabelTitles:(NSDictionary *)dic{ - if(dic){ - dialogTextDic=dic; +- (void)customJavascriptDialogLabelTitles:(NSDictionary *)dic { + if (dic) { + dialogTextDic = dic; } } -- (id)onMessage:(NSDictionary *)msg type:(int)type{ - id ret=nil; +- (id)onMessage:(NSDictionary *)msg type:(int)type { + id ret = nil; switch (type) { case DSB_API_HASNATIVEMETHOD: - ret= [self hasNativeMethod:msg]?@1:@0; + ret = [self hasNativeMethod:msg] ? @1 : @0; break; case DSB_API_CLOSEPAGE: [self closePage:msg]; break; case DSB_API_RETURNVALUE: - ret=[self returnValue:msg]; + ret = [self returnValue:msg]; break; case DSB_API_DSINIT: - ret=[self dsinit:msg]; + ret = [self dsinit:msg]; break; case DSB_API_DISABLESAFETYALERTBOX: [self disableJavascriptDialogBlock:[msg[@"disable"] boolValue]]; @@ -424,65 +406,61 @@ - (id)onMessage:(NSDictionary *)msg type:(int)type{ return ret; } -- (bool) hasNativeMethod:(NSDictionary *) args -{ - NSArray *nameStr=[JSBUtil parseNamespace:[args[@"name"]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]]; - NSString * type= [args[@"type"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - id JavascriptInterfaceObject= [javaScriptNamespaceInterfaces objectForKey:nameStr[0]]; - if(JavascriptInterfaceObject){ - bool syn=[JSBUtil methodByNameArg:1 selName:nameStr[1] class:[JavascriptInterfaceObject class]]!=nil; - bool asyn=[JSBUtil methodByNameArg:2 selName:nameStr[1] class:[JavascriptInterfaceObject class]]!=nil; - if(([@"all" isEqualToString:type]&&(syn||asyn)) - ||([@"asyn" isEqualToString:type]&&asyn) - ||([@"syn" isEqualToString:type]&&syn) - ){ +- (bool)hasNativeMethod:(NSDictionary *)args { + NSArray *nameStr = [JSBUtil parseNamespace:[args[@"name"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]]; + NSString *type = [args[@"type"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + id JavascriptInterfaceObject = [javaScriptNamespaceInterfaces objectForKey:nameStr[0]]; + if (JavascriptInterfaceObject) { + bool syn = [JSBUtil methodByNameArg:1 selName:nameStr[1] objClass:[JavascriptInterfaceObject class]] != nil; + bool asyn = [JSBUtil methodByNameArg:2 selName:nameStr[1] objClass:[JavascriptInterfaceObject class]] != nil; + if (([@"all" isEqualToString:type] && (syn || asyn)) || ([@"asyn" isEqualToString:type] && asyn) || ([@"syn" isEqualToString:type] && syn)) { return true; } } return false; } -- (id) closePage:(NSDictionary *) args{ - if(javascriptCloseWindowListener){ +- (id)closePage:(NSDictionary *)args { + if (javascriptCloseWindowListener) { javascriptCloseWindowListener(); } return nil; } -- (id) returnValue:(NSDictionary *) args{ - void (^ completionHandler)(NSString * _Nullable)= handerMap[args[@"id"]]; - if(completionHandler){ - if(isDebug){ +- (id)returnValue:(NSDictionary *)args { + void (^completionHandler)(NSString *_Nullable) = handerMap[args[@"id"]]; + if (completionHandler) { + if (isDebug) { completionHandler(args[@"data"]); - }else{ - @try{ + } else { + @try { completionHandler(args[@"data"]); - }@catch (NSException *e){ - NSLog(@"%@",e); + } @catch (NSException *e) { + NSLog(@"%@", e); } } - if([args[@"complete"] boolValue]){ + if ([args[@"complete"] boolValue]) { [handerMap removeObjectForKey:args[@"id"]]; } } return nil; } -- (id) dsinit:(NSDictionary *) args{ +- (id)dsinit:(NSDictionary *)args { [self dispatchStartupQueue]; return nil; } -- (void) disableJavascriptDialogBlock:(bool) disable{ - jsDialogBlock=!disable; +- (void)disableJavascriptDialogBlock:(bool)disable { + jsDialogBlock = !disable; } -- (void)hasJavascriptMethod:(NSString *)handlerName methodExistCallback:(void (^)(bool exist))callback{ - [self callHandler:@"_hasJavascriptMethod" arguments:@[handlerName] completionHandler:^(NSNumber* _Nullable value) { - callback([value boolValue]); - }]; +- (void)hasJavascriptMethod:(NSString *)handlerName methodExistCallback:(void (^)(bool exist))callback { + [self callHandler:@"_hasJavascriptMethod" + arguments:@[ handlerName ] + completionHandler:^(NSNumber *_Nullable value) { + callback([value boolValue]); + }]; } @end - - diff --git a/dsbridge/InternalApis.h b/dsbridge/InternalApis.h index 688d55c..14dbc26 100644 --- a/dsbridge/InternalApis.h +++ b/dsbridge/InternalApis.h @@ -1,8 +1,6 @@ -#import #import "DWKWebView.h" +#import @interface InternalApis : NSObject -@property (nullable, nonatomic, weak) DWKWebView* webview; +@property (nullable, nonatomic, weak) DWKWebView *webview; @end - - diff --git a/dsbridge/InternalApis.m b/dsbridge/InternalApis.m index 528b3c3..4b0adbb 100644 --- a/dsbridge/InternalApis.m +++ b/dsbridge/InternalApis.m @@ -2,24 +2,24 @@ #import "JSBUtil.h" @implementation InternalApis -- (id) hasNativeMethod:(id) args -{ - return [self.webview onMessage:args type: DSB_API_HASNATIVEMETHOD]; +- (id)hasNativeMethod:(id)args { + return [self.webview onMessage:args type:DSB_API_HASNATIVEMETHOD]; } -- (id) closePage:(id) args{ +- (id)closePage:(id)args { return [self.webview onMessage:args type:DSB_API_CLOSEPAGE]; } -- (id) returnValue:(NSDictionary *) args{ +- (id)returnValue:(NSDictionary *)args { return [self.webview onMessage:args type:DSB_API_RETURNVALUE]; } -- (id) dsinit:(id) args{ +- (id)dsinit:(id)args { return [self.webview onMessage:args type:DSB_API_DSINIT]; } -- (id) disableJavascriptDialogBlock:(id) args{ +- (id)disableJavascriptDialogBlock:(id)args { return [self.webview onMessage:args type:DSB_API_DISABLESAFETYALERTBOX]; } + @end diff --git a/dsbridge/JSBUtil.h b/dsbridge/JSBUtil.h index c2a6b6f..fe0197d 100644 --- a/dsbridge/JSBUtil.h +++ b/dsbridge/JSBUtil.h @@ -1,17 +1,31 @@ #import -enum{ - DSB_API_HASNATIVEMETHOD, - DSB_API_CLOSEPAGE, - DSB_API_RETURNVALUE, - DSB_API_DSINIT, - DSB_API_DISABLESAFETYALERTBOX +enum { + DSB_API_HASNATIVEMETHOD, + DSB_API_CLOSEPAGE, + DSB_API_RETURNVALUE, + DSB_API_DSINIT, + DSB_API_DISABLESAFETYALERTBOX }; @interface JSBUtil : NSObject -+ (NSString * _Nullable)objToJsonString:(id _Nonnull)dict; -+ (id _Nullable)jsonStringToObject:(NSString * _Nonnull)jsonString; -+(NSString *_Nullable)methodByNameArg:(NSInteger)argNum - selName:( NSString * _Nullable)selName class:(Class _Nonnull )class; -+ (NSArray *_Nonnull)parseNamespace: (NSString *_Nonnull) method; + +/// Objct are converted to JSON strings +/// @param dict An object that needs to be converted to a JSON string, usually is dictionary. ++ (NSString *_Nullable)objToJsonString:(id _Nonnull)dict; + +/// Json strings are converted to dictionaries +/// @param jsonString Json string that needs to be converted into a dictionary. ++ (id _Nullable)jsonStringToObject:(NSString *_Nonnull)jsonString; + +/// Combine method names based on supplied parameters +/// @param argNum argment count. +/// @param selName selector name. +/// @param objClass objc's class. ++ (NSString *_Nullable)methodByNameArg:(NSInteger)argNum selName:(NSString *_Nullable)selName objClass:(Class _Nonnull)objClass; + +/// Parse the namespace +/// @param method namespace of method ++ (NSArray *_Nonnull)parseNamespace:(NSString *_Nonnull)method; + @end diff --git a/dsbridge/JSBUtil.m b/dsbridge/JSBUtil.m index 21f8f65..5c98afb 100644 --- a/dsbridge/JSBUtil.m +++ b/dsbridge/JSBUtil.m @@ -5,22 +5,20 @@ // #import "JSBUtil.h" -#import #import "DWKWebView.h" - +#import @implementation JSBUtil -+ (NSString *)objToJsonString:(id)dict -{ ++ (NSString *)objToJsonString:(id)dict { NSString *jsonString = nil; NSError *error; - + if (![NSJSONSerialization isValidJSONObject:dict]) { return @"{}"; } - + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error]; - if (! jsonData) { + if (!jsonData) { return @"{}"; } else { jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; @@ -29,33 +27,32 @@ + (NSString *)objToJsonString:(id)dict } //get this class all method -+ (NSArray *)allMethodFromClass:(Class)class { ++ (NSArray *)allMethodFromClass:(Class)objClass { NSMutableArray *methods = [NSMutableArray array]; - while (class) { + while (objClass) { unsigned int count = 0; - Method *method = class_copyMethodList(class, &count); + Method *method = class_copyMethodList(objClass, &count); for (unsigned int i = 0; i < count; i++) { SEL name1 = method_getName(method[i]); - const char *selName= sel_getName(name1); + const char *selName = sel_getName(name1); NSString *strName = [NSString stringWithCString:selName encoding:NSUTF8StringEncoding]; [methods addObject:strName]; } free(method); - - Class cls = class_getSuperclass(class); - class = [NSStringFromClass(cls) isEqualToString:NSStringFromClass([NSObject class])] ? nil : cls; + + Class cls = class_getSuperclass(objClass); + objClass = [NSStringFromClass(cls) isEqualToString:NSStringFromClass([NSObject class])] ? nil : cls; } - + return [NSArray arrayWithArray:methods]; } //return method name for xxx: or xxx:handle: -+(NSString *)methodByNameArg:(NSInteger)argNum selName:(NSString *)selName class:(Class)class -{ ++ (NSString *)methodByNameArg:(NSInteger)argNum selName:(NSString *)selName objClass:(Class)objClass { NSString *result = nil; - if(class){ - NSArray *arr = [JSBUtil allMethodFromClass:class]; - for (int i=0; i -#import "JSBUtil.h" #import "DWKWebView.h" - +#import "JSBUtil.h" +#import diff --git a/dsbridgedemo/AppDelegate.h b/dsbridgedemo/AppDelegate.h index aeeec49..aea55c9 100644 --- a/dsbridgedemo/AppDelegate.h +++ b/dsbridgedemo/AppDelegate.h @@ -12,6 +12,4 @@ @property (strong, nonatomic) UIWindow *window; - @end - diff --git a/dsbridgedemo/AppDelegate.m b/dsbridgedemo/AppDelegate.m index a9b2d05..85fee7f 100644 --- a/dsbridgedemo/AppDelegate.m +++ b/dsbridgedemo/AppDelegate.m @@ -8,44 +8,37 @@ #import "AppDelegate.h" -@interface AppDelegate () +@interface AppDelegate() @end @implementation AppDelegate - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } - - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } - - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } - - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - @end diff --git a/dsbridgedemo/JsApiTest.h b/dsbridgedemo/JsApiTest.h index 498829a..5b17dff 100644 --- a/dsbridgedemo/JsApiTest.h +++ b/dsbridgedemo/JsApiTest.h @@ -6,8 +6,8 @@ // Copyright © 2016年 杜文. All rights reserved. // -#import #import "dsbridge.h" +#import @interface JsApiTest : NSObject diff --git a/dsbridgedemo/JsApiTest.m b/dsbridgedemo/JsApiTest.m index d1da4e6..ed16b79 100644 --- a/dsbridgedemo/JsApiTest.m +++ b/dsbridgedemo/JsApiTest.m @@ -7,51 +7,47 @@ #import "JsApiTest.h" -@interface JsApiTest(){ - NSTimer * timer ; - void(^hanlder)(id value,BOOL isComplete); - int value; +@interface JsApiTest() { + NSTimer *timer; + void (^hanlder)(id value, BOOL isComplete); + int value; } + @end @implementation JsApiTest -- (NSString *) testSyn: (NSString *) msg -{ +- (NSString *)testSyn:(NSString *)msg { return [msg stringByAppendingString:@"[ syn call]"]; } -- (void) testAsyn:(NSString *) msg :(JSCallback) completionHandler -{ - completionHandler([msg stringByAppendingString:@" [ asyn call]"],YES); +- (void)testAsyn:(NSString *)msg callback:(JSCallback)completionHandler { + completionHandler([msg stringByAppendingString:@" [ asyn call]"], YES); } -- (NSString *)testNoArgSyn:(NSDictionary *) args -{ - return @"testNoArgSyn called [ syn call]"; +- (NSString *)testNoArgSyn:(NSDictionary *)args { + return @"testNoArgSyn called [ syn call]"; } -- ( void )testNoArgAsyn:(NSDictionary *) args :(JSCallback)completionHandler -{ - completionHandler(@"testNoArgAsyn called [ asyn call]",YES); +- (void)testNoArgAsyn:(NSDictionary *)args callback:(JSCallback)completionHandler { + completionHandler(@"testNoArgAsyn called [ asyn call]", YES); } -- ( void )callProgress:(NSDictionary *) args :(JSCallback)completionHandler -{ - value=10; - hanlder=completionHandler; - timer = [NSTimer scheduledTimerWithTimeInterval:1.0 - target:self - selector:@selector(onTimer:) - userInfo:nil - repeats:YES]; +- (void)callProgress:(NSDictionary *)args callback:(JSCallback)completionHandler { + value = 10; + hanlder = completionHandler; + timer = [NSTimer scheduledTimerWithTimeInterval:1.0 + target:self + selector:@selector(onTimer:) + userInfo:nil + repeats:YES]; } --(void)onTimer:t{ - if(value!=-1){ - hanlder([NSNumber numberWithInt:value--],NO); - }else{ - hanlder(0,YES); +- (void)onTimer:t { + if (value != -1) { + hanlder([NSNumber numberWithInt:value--], NO); + } else { + hanlder(0, YES); [timer invalidate]; } } @@ -62,8 +58,7 @@ -(void)onTimer:t{ * redirect requests to native, more about Fly see https://github.com/wendux/fly * @param requestInfo passed by fly.js, more detail reference https://wendux.github.io/dist/#/doc/flyio-en/native */ --(void)onAjaxRequest:(NSDictionary *) requestInfo :(JSCallback)completionHandler{ - +- (void)onAjaxRequest:(NSDictionary *)requestInfo callback:(JSCallback)completionHandler { } @end diff --git a/dsbridgedemo/JsEchoApi.m b/dsbridgedemo/JsEchoApi.m index 005e52b..8128b0d 100644 --- a/dsbridgedemo/JsEchoApi.m +++ b/dsbridgedemo/JsEchoApi.m @@ -11,14 +11,12 @@ @implementation JsEchoApi -- (id) syn:(id) arg -{ +- (id)syn:(id)arg { return arg; } -- (void) asyn: (id) arg :(JSCallback)completionHandler -{ - completionHandler(arg,YES); +- (void)asyn:(id)arg callback:(JSCallback)completionHandler { + completionHandler(arg, YES); } @end diff --git a/dsbridgedemo/ViewController.h b/dsbridgedemo/ViewController.h index a4526f3..b96dd36 100644 --- a/dsbridgedemo/ViewController.h +++ b/dsbridgedemo/ViewController.h @@ -6,13 +6,12 @@ // Copyright © 2017年 杜文. All rights reserved. // -#import -#import "dsbridge.h" #import "JsApiTest.h" +#import "dsbridge.h" +#import -@interface ViewController : UIViewController -{ +@interface ViewController : UIViewController { JsApiTest *jsApi; } -@end +@end diff --git a/dsbridgedemo/ViewController.m b/dsbridgedemo/ViewController.m index 4b8f12b..e9b1c3a 100644 --- a/dsbridgedemo/ViewController.m +++ b/dsbridgedemo/ViewController.m @@ -7,105 +7,117 @@ // #import "ViewController.h" -#import #import "JsEchoApi.h" #import "dsbridgedemo-Swift.h" -@interface ViewController () +#import +@interface ViewController() @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; - CGRect bounds=self.view.bounds; - DWKWebView * dwebview=[[DWKWebView alloc] initWithFrame:CGRectMake(0, 25, bounds.size.width, bounds.size.height-25)]; + CGRect bounds = self.view.bounds; + DWKWebView *dwebview = [[DWKWebView alloc] initWithFrame:CGRectMake(0, 25, bounds.size.width, bounds.size.height - 25)]; [self.view addSubview:dwebview]; - + // register api object without namespace [dwebview addJavascriptObject:[[JsApiTest alloc] init] namespace:nil]; - + // register api object without namespace - [dwebview addJavascriptObject:[[ JsApiTestSwift alloc] init] namespace:@"swift"]; - + [dwebview addJavascriptObject:[[JsApiTestSwift alloc] init] namespace:@"swift"]; + // register api object with namespace "echo" [dwebview addJavascriptObject:[[JsEchoApi alloc] init] namespace:@"echo"]; - + // open debug mode, Release mode should disable this. [dwebview setDebugMode:true]; - - [dwebview customJavascriptDialogLabelTitles:@{@"alertTitle":@"Notification",@"alertBtn":@"OK"}]; - - dwebview.navigationDelegate=self; - + + [dwebview customJavascriptDialogLabelTitles:@{@"alertTitle" : @"Notification", @"alertBtn" : @"OK"}]; + + dwebview.navigationDelegate = self; + // load test.html NSString *path = [[NSBundle mainBundle] bundlePath]; NSURL *baseURL = [NSURL fileURLWithPath:path]; - NSString * htmlPath = [[NSBundle mainBundle] pathForResource:@"test" - ofType:@"html"]; - NSString * htmlContent = [NSString stringWithContentsOfFile:htmlPath - encoding:NSUTF8StringEncoding - error:nil]; + NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"test" + ofType:@"html"]; + NSString *htmlContent = [NSString stringWithContentsOfFile:htmlPath + encoding:NSUTF8StringEncoding + error:nil]; [dwebview loadHTMLString:htmlContent baseURL:baseURL]; - + // call javascript method - [dwebview callHandler:@"addValue" arguments:@[@3,@4] completionHandler:^(NSNumber * value){ - NSLog(@"%@",value); - }]; + [dwebview callHandler:@"addValue" + arguments:@[ @3, @4 ] + completionHandler:^(NSNumber *value) { + NSLog(@"%@", value); + }]; - [dwebview callHandler:@"append" arguments:@[@"I",@"love",@"you"] completionHandler:^(NSString * _Nullable value) { - NSLog(@"call succeed, append string is: %@",value); - }]; + [dwebview callHandler:@"append" + arguments:@[ @"I", @"love", @"you" ] + completionHandler:^(NSString *_Nullable value) { + NSLog(@"call succeed, append string is: %@", value); + }]; // this invocation will be return 5 times - [dwebview callHandler:@"startTimer" completionHandler:^(NSNumber * _Nullable value) { - NSLog(@"Timer: %@",value); - }]; + [dwebview callHandler:@"startTimer" + completionHandler:^(NSNumber *_Nullable value) { + NSLog(@"Timer: %@", value); + }]; // namespace syn test - [dwebview callHandler:@"syn.addValue" arguments:@[@5,@6] completionHandler:^(NSDictionary * _Nullable value) { - NSLog(@"Namespace syn.addValue(5,6): %@",value); - }]; - - [dwebview callHandler:@"syn.getInfo" completionHandler:^(NSDictionary * _Nullable value) { - NSLog(@"Namespace syn.getInfo: %@",value); - }]; - + [dwebview callHandler:@"syn.addValue" + arguments:@[ @5, @6 ] + completionHandler:^(NSDictionary *_Nullable value) { + NSLog(@"Namespace syn.addValue(5,6): %@", value); + }]; + + [dwebview callHandler:@"syn.getInfo" + completionHandler:^(NSDictionary *_Nullable value) { + NSLog(@"Namespace syn.getInfo: %@", value); + }]; + // namespace asyn test - [dwebview callHandler:@"asyn.addValue" arguments:@[@5,@6] completionHandler:^(NSDictionary * _Nullable value) { - NSLog(@"Namespace asyn.addValue(5,6): %@",value); - }]; - - [dwebview callHandler:@"asyn.getInfo" completionHandler:^(NSDictionary * _Nullable value) { - NSLog(@"Namespace asyn.getInfo: %@",value); - }]; - + [dwebview callHandler:@"asyn.addValue" + arguments:@[ @5, @6 ] + completionHandler:^(NSDictionary *_Nullable value) { + NSLog(@"Namespace asyn.addValue(5,6): %@", value); + }]; + + [dwebview callHandler:@"asyn.getInfo" + completionHandler:^(NSDictionary *_Nullable value) { + NSLog(@"Namespace asyn.getInfo: %@", value); + }]; + // test if javascript method exists. - [dwebview hasJavascriptMethod:@"addValue" methodExistCallback:^(bool exist) { - NSLog(@"method 'addValue' exist : %d",exist); - }]; - - [dwebview hasJavascriptMethod:@"XX" methodExistCallback:^(bool exist) { - NSLog(@"method 'XX' exist : %d",exist); - }]; - - [dwebview hasJavascriptMethod:@"asyn.addValue" methodExistCallback:^(bool exist) { - NSLog(@"method 'asyn.addValue' exist : %d",exist); - }]; - - [dwebview hasJavascriptMethod:@"asyn.XX" methodExistCallback:^(bool exist) { - NSLog(@"method 'asyn.XX' exist : %d",exist); - }]; - + [dwebview hasJavascriptMethod:@"addValue" + methodExistCallback:^(bool exist) { + NSLog(@"method 'addValue' exist : %d", exist); + }]; + + [dwebview hasJavascriptMethod:@"XX" + methodExistCallback:^(bool exist) { + NSLog(@"method 'XX' exist : %d", exist); + }]; + + [dwebview hasJavascriptMethod:@"asyn.addValue" + methodExistCallback:^(bool exist) { + NSLog(@"method 'asyn.addValue' exist : %d", exist); + }]; + + [dwebview hasJavascriptMethod:@"asyn.XX" + methodExistCallback:^(bool exist) { + NSLog(@"method 'asyn.XX' exist : %d", exist); + }]; + // set javascript close listener [dwebview setJavascriptCloseWindowListener:^{ NSLog(@"window.close called"); - } ]; - + }]; } - - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - @end diff --git a/dsbridgedemo/dsbridgedemo-Bridging-Header.h b/dsbridgedemo/dsbridgedemo-Bridging-Header.h index 1b2cb5d..e11d920 100644 --- a/dsbridgedemo/dsbridgedemo-Bridging-Header.h +++ b/dsbridgedemo/dsbridgedemo-Bridging-Header.h @@ -1,4 +1,3 @@ // // Use this file to import your target's public headers that you would like to expose to Swift. // - diff --git a/dsbridgedemo/main.m b/dsbridgedemo/main.m index 66299ba..fe988af 100644 --- a/dsbridgedemo/main.m +++ b/dsbridgedemo/main.m @@ -6,10 +6,10 @@ // Copyright © 2017年 杜文. All rights reserved. // -#import #import "AppDelegate.h" +#import -int main(int argc, char * argv[]) { +int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } diff --git a/readme-chs.md b/readme-chs.md index c5fa783..aa31893 100644 --- a/readme-chs.md +++ b/readme-chs.md @@ -48,15 +48,15 @@ pod "dsBridge" ... @implementation JsApiTest //同步API - - (NSString *) testSyn:(NSString *) msg - { - return [msg stringByAppendingString:@"[ syn call]"]; + - (NSString *)testSyn:(NSString *)msg { + return [msg stringByAppendingString:@"[ syn call]"]; } + //异步API - - (void) testAsyn:(NSString *) msg :(JSCallback)completionHandler - { - completionHandler([msg stringByAppendingString:@" [ asyn call]"],YES); + - (void)testAsyn:(NSString *)msg callback:(JSCallback)completionHandler { + completionHandler([msg stringByAppendingString:@" [ asyn call]"], YES); } + @end ``` 可以看到,DSBridge正式通过API类的方式集中、统一地管理API。 @@ -103,7 +103,7 @@ pod "dsBridge" ```objective-c [dwebview callHandler:@"addValue" arguments:@[@3,@4] completionHandler:^(NSNumber* value){ - NSLog(@"%@",value); + NSLog(@"%@",value); }]; ``` @@ -114,14 +114,14 @@ pod "dsBridge" 1. 同步API. - **`(id) handler:(id) msg`** + **`(id)handler:(id)msg`** 参数可以是任何类型, 但是返回值类型不能为 **void。** **如果不需要参数,也必须声明**,声明后不使用就行。 > 如果同步API返回值类型为void,调用时则会导致Crash,请务必遵守签名规范。 2. 异步 API. - **` (void) handler:(id)arg :(void (^)( id result,BOOL complete))completionHandler)`** + **` (void)handler:(id)arg handler:(void (^)( id result,BOOL complete))completionHandler)`** `JSCallback` 是一个block类型: @@ -180,21 +180,21 @@ pod "dsBridge" In Object-c ```objective-c -- ( void )callProgress:(NSDictionary *) args :(JSCallback)completionHandler -{ - value=10; - hanlder=completionHandler; - timer = [NSTimer scheduledTimerWithTimeInterval:1.0 - target:self - selector:@selector(onTimer:) - userInfo:nil - repeats:YES]; +- (void)callProgress:(NSDictionary *)args callback:(JSCallback)completionHandler { + value = 10; + hanlder = completionHandler; + timer = [NSTimer scheduledTimerWithTimeInterval:1.0 + target:self + selector:@selector(onTimer:) + userInfo:nil + repeats:YES]; } --(void)onTimer:t{ - if(value!=-1){ - hanlder([NSNumber numberWithInt:value--],NO); - }else{ - hanlder(@"",YES); + +- (void)onTimer:t { + if (value != -1) { + hanlder([NSNumber numberWithInt:value--], NO); + } else { + hanlder(0, YES); [timer invalidate]; } } @@ -244,15 +244,15 @@ DSBridge已经实现了 Javascript的弹出框函数(alert/confirm/prompt),这 ```objective-c @implementation JsEchoApi -- (id) syn:(id) arg -{ +- (id)syn:(id)arg { return arg; } -- (void) asyn: (id) arg :(JSCallback)completionHandler -{ - completionHandler(arg,YES); + +- (void)asyn:(id)arg callback:(JSCallback)completionHandler { + completionHandler(arg, YES); } @end + // register api object with namespace "echo" [dwebview addJavascriptObject:[[JsEchoApi alloc] init] namespace:@"echo"]; ``` @@ -265,7 +265,7 @@ var ret=dsBridge.call("echo.syn",{msg:" I am echoSyn call", tag:1}) alert(JSON.stringify(ret)) // call echo.asyn dsBridge.call("echo.asyn",{msg:" I am echoAsyn call",tag:2},function (ret) { - alert(JSON.stringify(ret)); + alert(JSON.stringify(ret)); }) ``` @@ -277,11 +277,11 @@ dsBridge.call("echo.asyn",{msg:" I am echoAsyn call",tag:2},function (ret) { -##### `callHandler:(NSString *) methodName arguments:(NSArray *) args` +##### `callHandler:(NSString *)methodName arguments:(NSArray *)args` -##### `callHandler:(NSString *) methodName completionHandler:(void (^)(id value))completionHandler` +##### `callHandler:(NSString *)methodName completionHandler:(void (^)(id value))completionHandler` -##### `callHandler:(NSString *) methodName arguments:(NSArray *) args completionHandler:(void (^ )(id value))completionHandler` +##### `callHandler:(NSString *)methodName arguments:(NSArray *)args completionHandler:(void (^ )(id value))completionHandler` 调用 javascript API.`methodName` 为javascript API 的名称,可以包含命名空间;参数以数组传递,`argumentss`数组中的元素依次对应javascript API的形参; `completionHandler` 用于接收javascript API的返回值,**注意: `completionHandler`将在主线程中被执行**。 @@ -294,7 +294,7 @@ dsBridge.call("echo.asyn",{msg:" I am echoAsyn call",tag:2},function (ret) { }]; // call with namespace 'syn', More details to see the Demo project [dwebview callHandler:@"syn.getInfo" completionHandler:^(NSDictionary * _Nullable value) { - NSLog(@"Namespace syn.getInfo: %@",value); + NSLog(@"Namespace syn.getInfo: %@",value); }]; ``` @@ -322,7 +322,7 @@ Example: ```objective-c [dwebview setJavascriptCloseWindowListener:^{ - NSLog(@"window.close called"); + NSLog(@"window.close called"); }]; ``` @@ -337,7 +337,7 @@ Example: ```objective-c // test if javascript method exists. [dwebview hasJavascriptMethod:@"addValue" methodExistCallback:^(bool exist) { - NSLog(@"method 'addValue' exist : %d",exist); + NSLog(@"method 'addValue' exist : %d",exist); }]; ``` @@ -411,7 +411,7 @@ custom the label text of javascript dialog that includes alert/confirm/prompt, ```objective-c // call javascript method [dwebview callHandler:@"addValue" arguments:@[@3,@4] completionHandler:^(NSNumber * value){ - NSLog(@"%@",value); + NSLog(@"%@",value); }]; [dwebview callHandler:@"append" arguments:@[@"I",@"love",@"you"] completionHandler:^(NSString * _Nullable value) { @@ -455,11 +455,11 @@ custom the label text of javascript dialog that includes alert/confirm/prompt, ```objective-c [dwebview callHandler:@"test.test1" completionHandler:^(NSString * _Nullable value) { - NSLog(@"Namespace test.test1: %@",value); + NSLog(@"Namespace test.test1: %@",value); }]; [dwebview callHandler:@"test1.test1" completionHandler:^(NSString * _Nullable value) { - NSLog(@"Namespace test1.test1: %@",value); + NSLog(@"Namespace test1.test1: %@",value); }]; ```