聊聊iOS開發中的JSBridge
https://www.jianshu.com/p/eff176e220e0
https://www.jianshu.com/p/0026be142442
iOS 上使用jsBridge的方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <button onclick="jsFunc()">打開相冊按鈕</button> <button onclick="jsFunc1()">獲取版本號</button> <script> function jsFunc() { alert('返回參數' + common("openCamera","1234567")) }; function jsFunc1() { alert('返回參數' + common("getCode")) }; function common (){ var args = Array.prototype.slice.call(arguments); alert(args); var type = "JSbridge"; var payload = { "type": type, "arguments": args }; return prompt(JSON.stringify(payload)); }; </script> </body> </html>
iOS 代碼實現
#include <objc/objc.h> #include <objc/runtime.h> #include <objc/message.h> - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{ NSError *err = nil; NSData *dataFromString = [prompt dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:dataFromString options:NSJSONReadingMutableContainers error:&err]; if (!err) { NSString *type = [payload objectForKey:@"type"]; if (type && [type isEqualToString:@"JSbridge"]) { NSString *returnValue = @""; NSArray *args = [payload objectForKey:@"arguments"]; if (args.count < 1) { completionHandler(returnValue); return; } NSString * functionName = [args firstObject]; NSMutableArray * newArrayArgs = [[NSMutableArray alloc]initWithArray:args]; [newArrayArgs removeObjectAtIndex:0]; SEL sel = newArrayArgs.count < 1 ? NSSelectorFromString(functionName) : NSSelectorFromString([NSString stringWithFormat:@"%@:",functionName]); if ([self respondsToSelector:sel]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" returnValue = [self performSelector:sel withObject:newArrayArgs]; #pragma clang diagnostic pop if(![returnValue isKindOfClass:[NSString class]]) { returnValue = @""; } } completionHandler(returnValue); } } } - (NSString *)getAppVersion { NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; NSString *app_Version = [infoDictionary objectForKey:@"CFBundleShortVersionString"]; return app_Version; } -(void)openCamera:(NSArray *)argsArray{ if (argsArray.count > 0) { NSString *orderId = argsArray[0]; // 打開相機 } }
這上面注意點
- var type = "JSbridge"; 是web 和 app上確定好的協議
- web 傳遞的數據是[方法名,參數1,參數2,...]
- 通過方法名字生成方法 sel
- 通過是否有參數來確定使用那種sel,如果有參數那么需要使用帶參數的sel,否則使用沒有參數的sel
- 通過 performSelector 來執行sel,注意在func沒有返回值的時候,那么performSelector返回的就是參數,需要特殊處理一下
- 走過的彎路
Method method = class_getInstanceMethod([self class], sel); const char *types = method_getTypeEncoding(method); NSLog(@"-------- %@",[NSString stringWithUTF8String: types]); // v為 void , i 為 int , f為float // // ? 為 block ( void(^)(void) ) // // 開頭帶v16 v32表示無返回值,其他帶什么表示返回值為什么類型; // // :8 是 SEL標示 // // @28 返回值為 NSString, @16代表參數為 NSString, // // @24 返回值為id, // 通過types來確定返回值是什么 returnValue = ((NSString* (*) (id,SEL))objc_msgSend)(self,sel); ((void (*) (id,SEL))objc_msgSend)(self,sel); returnValue = ((NSString * (*) (id,SEL,id))objc_msgSend)(self,sel,newArrayArgs);
真心的不建議用 objc_msgSend 因為如果要用這個需要更改編譯器,這樣編譯器就不檢測類型了,對app 對安全是一個重大的曲線


image.png
作者:SteveKwok
鏈接:https://www.jianshu.com/p/0026be142442
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。