在SDK中 无法直接跳App 的界面,这个时候需要使用 路由,或者通过 NSClassFromString 的
presentViewController 来跳转。
直接贴代码:
UIViewController *VC = [NSClassFromString(@"WZFullmotionPagesController") new]; id prepareAction = ^(void (^ _Nonnull success)(void)) { UIViewController *VC1 = [NSClassFromString(@"WZServiceSelectController") new]; id prepareAction1 = ^(void) { if (success) success(); }; [VC1 setValue:prepareAction1 forKey:@"defaultSetCMCCallBack"]; [self.navigationController pushViewController:VC1 animated:YES]; [VC1.view setNeedsDisplay]; }; [VC setValue:prepareAction forKey:@"prepareAction"]; [self presentViewController:VC animated:YES completion:nil];
有时候需要回调,可以再回调里 继续添加跳转
路由的使用:
有的控制器 需要先添加路由的方式,再根据plist 来调用
- (void)router:(WPKRouterAction *)action setParam:(WPKRParamModelBase *)param block:(WPKRouterBlock)block{ //这里可以处理逻辑 NSDictionary *dict = (NSDictionary *)param; WPKNameCamSetingController *VC = [[WPKNameCamSetingController alloc] init]; VC.deviceMac = dict [@"deviceMac"]; VC.deviceModel = dict [@"deviceModel"]; VC.nameCamsSetingType = dict[@"nameCamsSetingType"]; VC.progress = dict[@"progress"]; VC.saveBtnStr = dict[@"saveBtnStr"]; VC.routeAddress = dict[@"routeAddress"]; VC.routeAguments = dict[@"routeAguments"]; WPKRCallbackModel *callbackModel = [[WPKRCallbackModel alloc] init]; VC.NameCamSetingFinishClick = ^(NSString * _Nonnull code){ callbackModel.object = code; block(callbackModel); }; [[WPKUIUtils topViewController].navigationController pushViewController:VC animated:YES];}
路由的具体实现
//// WPKRouter.m// WZPlatformKit//// Created by abc on 2019/4/30.// Copyright © 2019 米家. All rights reserved.//#import "WPKRouter.h"#import "WPKRCallbackModel.h"#import "WPKRParamModelBase.h"#import "WPKRouterAction.h"#import "WPKRouterUtil.h"#import "WPKSerializationHelper.h"#import <objc/runtime.h>#import "WPKRouterPool.h"//router内部存储actionModel时,给参数增加识别码,用于业务结束操作时回传该识别码,注销actionmodelstatic NSString * const WPK_ROUTER_KEY_STRING = @"WPK_ROUTER_KEY_STRING";static NSString * const WPK_ROUTER_CLASS_PREFIX = @"WPK_router_executor_";static NSString * const WPK_ROUTER_FUNC_PREFIX = @"retriveSelectorFor_";typedef void (^WPKRouterH5Block)(WPKRCallbackModel *result, WPKRParamModelBase *modleBase);@interface WPKRouter() @property (atomic, strong) WPKRouterAction *actionModel;/** 存储 WPKRouterAction 对象 */@property (nonatomic,strong)NSMutableArray * actionModelArray;@property (nonatomic,strong)NSMutableDictionary * actionModeKeyDic;@end@implementation WPKRouter#pragma mark - life cycles+ (id)allocWithZone:(struct _NSZone *)zone{ return [WPKRouter sharedInstance];}+ (instancetype)sharedInstance{ static WPKRouter *inst; static dispatch_once_t once_t; dispatch_once(&once_t, ^{ inst = [[super allocWithZone:NULL] init]; }); return inst;}- (instancetype)init{ self = [super init]; if (self) { _util = [[WPKRouterUtil alloc] init]; } return self;}#pragma mark - public- (id)callCls:(NSString *)cls sel:(NSString *)sel params:(NSArray *)params{ // 获取类名 NSString *target = [NSString stringWithFormat:@"%@%@", WPK_ROUTER_CLASS_PREFIX, cls]; Class c = NSClassFromString(target); if (c) {// 获取函数名获取器 NSString *action = [NSString stringWithFormat:@"%@%@", WPK_ROUTER_FUNC_PREFIX, sel]; SEL objSel = NSSelectorFromString(action); NSObject * obj = [[c alloc] init]; if ([obj respondsToSelector:objSel]) { // 警告!!!此处认为router框架增加的方法固定返回SEL类型,util方法返回字符串 SEL realSel = NSSelectorFromString([WPKRouterUtil performObject:obj selector:objSel withArguments:@[sel]]); NSObject *realObj = (NSObject *)[WPKRouterPool excutorForPaths:cls, sel, nil]; // 查看路由池是否有对应的对象 if (realObj && realSel && [realObj respondsToSelector:realSel]) { id res = [WPKRouterUtil performObject:obj selector:realSel withArguments:params]; return res; } else if (realSel && [obj respondsToSelector:realSel]) { //路由池无对象则使用新建的子类对象 id res = [WPKRouterUtil performObject:obj selector:realSel withArguments:params]; return res; } else {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wformat" WPKInfoLog(@"ERROR: router can‘t find selector: %s", realSel);#pragma clang diagnostic pop } } else {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wformat" WPKInfoLog(@"ERROR: router can‘t find selector: %s", objSel);#pragma clang diagnostic pop } } return nil;}#pragma mark - private- (void)pushActionModel:(WPKRouterAction*)model routerKey:(NSString *)routerKey{ @synchronized(self) { if (model.excutor && model.catchCallBack) { [self.actionModelArray addObject:model]; self.actionModeKeyDic[routerKey] = model; } }}- (void)popActionModelWithRouterKey:(NSString *)routerKey{ @synchronized(self) { WPKRouterAction * model = self.actionModeBlockDic[routerKey]; if (model.catchCallBack) { [self.actionModelArray removeObject:model]; [self.actionModeKeyDic removeObjectForKey:routerKey]; } }}#pragma mark - publics/** * H5调用WPK协议入口 * * @param url url */- (void)startUrl:(NSURL *)url{ //通过mwap执行参数回调 WPKRouterH5Block block = ^(WPKRCallbackModel *result, WPKRParamModelBase *modleBase) { if (result.object) { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; result.object != nil ? [dict setObject:result.object forKey:@"content"] : nil; modleBase.flagId != nil ? [dict setObject:modleBase.flagId forKey:@"flagId"] : nil; [[WPKRouter sharedInstance] startModuleSecoupled:@"mwap" path:@"servicecallback" paramDict:dict block:nil]; } }; [self callNativeFromH5Url:url block:block]; }- (void)startUrl:(NSURL *)url callback:(WPKRouterBlock)callback{ WPKRouterH5Block block = ^(WPKRCallbackModel *result, WPKRParamModelBase *modleBase) { callback(result); }; [self callNativeFromH5Url:url block:block];}//H5专用- (void)callNativeFromH5Url:(NSURL *)url block:(WPKRouterH5Block)block{ NSString *module = [_util getModuleStrFromUrl:url];//module NSString *path = [_util getPathStrFromUrl:url]; //path NSString *paramStr = [_util getParamStrFromUrl:url]; //param WPKRouterAction *actionModel = [_util getActionFromModule:module path:path]; if (![actionModel excutor]) { [self handleOldVersionWithUrl:url];//兼容老的WPK协议跳转 return; } if (!module || !path ) { WPKRouterBlock temp = ^(WPKRCallbackModel *result) { block(result, nil); }; if (path) { [_util goto404Error:[module stringByAppendingPathComponent:path] withBlock:temp]; } return; } NSDictionary *paramDic = [_util getParametersDictionaryWithParams:paramStr]; WPKRParamModelBase*param; if ([actionModel.in length] > 0) { Class paramClass = NSClassFromString(actionModel.in); param = [[paramClass alloc] init]; } else { //h5不设置入参,只需要flagID param = [[WPKRParamModelBase alloc] init]; } if ([param isKindOfClass:[WPKRParamModelBase class]]) { param.originURL = url; } [[WPKSerializationHelper sharedInstance] importDictionary:paramDic toObject:param]; WPKRouterBlock blocktemp = ^(WPKRCallbackModel *result) { block(result, param); }; [self startModule:module path:path param:param block:blocktemp];}- (void)startModule:(NSString *)kWPKRouter_M path:(NSString *)kWPKRouter_M_P param:(WPKRParamModelBase *)param block:(WPKRouterBlock)block{ WPKInfoLog(@">> WPKRouter: %@/%@ param: %@",kWPKRouter_M, kWPKRouter_M_P, param ); WPKRouterAction *WPKActionModel = [_util getActionFromModule:kWPKRouter_M path:kWPKRouter_M_P]; if (!param) {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wincompatible-pointer-types" param = [NSObject new];#pragma clang diagnostic pop } param.routerKey = [self getDateNow]; [self pushActionModel:WPKActionModel routerKey:param.routerKey]; [self handleAction:WPKActionModel paramModel:param block:block];}- (void)startModuleSecoupled:(NSString *)kWPKRouter_M path:(NSString *)kWPKRouter_M_P paramDict:(NSDictionary *)paramDict block:(WPKRouterBlock)block{ WPKRouterAction *WPKActionModel = [_util getActionFromModule:kWPKRouter_M path:kWPKRouter_M_P]; WPKActionModel.navigationController = self.navigationController; if (!paramDict) { paramDict = [NSDictionary new]; } paramDict.routerKey = [self getDateNow]; [self pushActionModel:WPKActionModel routerKey:paramDict.routerKey]; WPKRParamModelBase*paramModel; if ([WPKActionModel.in length] > 0) { Class paramClass = NSClassFromString(WPKActionModel.in); paramModel = [[paramClass alloc] init]; } else { //h5不设置入参,只需要flagID paramModel = [[WPKRParamModelBase alloc] init]; } if ([paramModel respondsToSelector:@selector(analyzeWPKRouterModelWithModelInfo:)]) { [paramModel analyzeWPKRouterModelWithModelInfo:paramDict]; } else if ([paramModel isKindOfClass:[NSDictionary class]]) {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wincompatible-pointer-types" paramModel = paramDict;#pragma clang diagnostic pop } else { [[WPKSerializationHelper sharedInstance] importDictionary:paramDict toObject:paramModel]; } /* 由于 mj_setKeyValues 方法不能将动态添加的属性转到相应的模型中所以进行如此修改 */ paramModel.routerKey = paramDict.routerKey; [self handleAction:WPKActionModel paramModel:paramModel block:block];}- (id)readDataModuleSecoupled:(NSString *)kWPKRouter_M path:(NSString *)kWPKRouter_M_P paramDict:(NSDictionary *)paramDict{ WPKRouterAction *WPKActionModel = [_util getActionFromModule:kWPKRouter_M path:kWPKRouter_M_P]; WPKActionModel.navigationController = self.navigationController; if (!paramDict) { paramDict = [NSDictionary new]; } paramDict.routerKey = [self getDateNow]; [self pushActionModel:WPKActionModel routerKey:paramDict.routerKey]; WPKRParamModelBase*paramModel; if ([WPKActionModel.in length] > 0) { Class paramClass = NSClassFromString(WPKActionModel.in); paramModel = [[paramClass alloc] init]; } else { //h5不设置入参,只需要flagID paramModel = [[WPKRParamModelBase alloc] init]; } if ([paramModel respondsToSelector:@selector(analyzeWPKRouterModelWithModelInfo:)]) { [paramModel analyzeWPKRouterModelWithModelInfo:paramDict]; } else if ([paramModel isKindOfClass:[NSDictionary class]]) {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wincompatible-pointer-types" paramModel = paramDict;#pragma clang diagnostic pop } else { [[WPKSerializationHelper sharedInstance] importDictionary:paramDict toObject:paramModel]; } /* 由于 mj_setKeyValues 方法不能将动态添加的属性转到相应的模型中所以进行如此修改 */ paramModel.routerKey = paramDict.routerKey; return [self handleAction:WPKActionModel paramModel:paramModel];}- (NSString *)composeURLForModule:(NSString *)kWPKRouter_M path:(NSString *)kWPKRouter_M_P param:(WPKRParamModelBase *)param iswithScheme:(BOOL)isWithScheme { NSString *json = @""; if (param) { json = [param toJsonString]; } NSString *scheme = [NSString stringWithFormat:@"%@://", kWPKRouter_scheme]; NSString *url = [NSString stringWithFormat:@"%@%@/%@?%@=%@", isWithScheme?scheme:@"", kWPKRouter_M, kWPKRouter_M_P?kWPKRouter_M_P:kWPKRouter_default_path, kWPKRouter_paramName, [json stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]] ]; return url;}/** * 解析url数据 * * @param urlString url * * @return 返回地址中存在的参数数据模型 */- (nullable WPKRParamModelBase *)parseParamModelWithUrl:(NSString *)urlString;{ NSURL *url = [NSURL URLWithString:urlString]; //module NSString *module = [_util getModuleStrFromUrl:url]; if (module == nil) { return nil; } //path NSString *path = [_util getPathStrFromUrl:url]; if (path == nil) { return nil; } //param NSString *paramStr = [_util getParamStrFromUrl:url]; WPKRouterAction *actionModel = [_util getActionFromModule:module path:path]; if (paramStr && actionModel.in) { NSDictionary *paramDic = [_util getParametersDictionaryWithParams:paramStr]; WPKRParamModelBase *model = [(WPKRParamModelBase *) [NSClassFromString(actionModel.in) alloc] init]; [[WPKSerializationHelper sharedInstance] importDictionary:paramDic toObject:model]; return model; } return nil;}-(void)callbackAction:(WPKRouterBlock)block result:(id)obj paramIn:(NSObject *)inModel error:(NSError *)error{ NSString *key=@""; if ([inModel.routerKey length] > 0) { key = inModel.routerKey; } if ([self.actionModeBlockDic.allKeys containsObject:key]) { [self popActionModelWithRouterKey:key]; } WPKRCallbackModel *model = [[WPKRCallbackModel alloc]init]; if ([obj isKindOfClass:[NSString class]]) { model.object = @{@"result":obj}; } else { model.object = obj; } model.code = (int)error.code; model.errorMessage=error.localizedDescription; if (block) { block(model); } }- (void)callbackAction:(WPKRouterBlock)block result:(id)obj{ [self callbackAction:block result:obj paramIn:nil];}- (void)callbackAction:(WPKRouterBlock)block result:(id)obj paramIn:(NSObject *)inModel{ [self callbackAction:block result:obj paramIn:inModel error:nil];}- (BOOL)canCheckModel:(NSString *)kWPKRouter_M path:(NSString *)kWPKRouter_M_P{ return [self canCheckModel:[_util getActionFromModule:kWPKRouter_M path:kWPKRouter_M_P]];}- (BOOL)canCheckUrl:(NSURL *)url{ return [self canCheckModel:[_util getActionFromModule:[_util getModuleStrFromUrl:url] path:[_util getPathStrFromUrl:url]]];}- (BOOL)canCheckModel:(WPKRouterAction *)actionModel{ if (actionModel == nil || actionModel.excutor.length == 0) { return NO; } Class class = NSClassFromString(actionModel.excutor); if (class == nil || class == [NSNull null]) { return NO; } return YES;}#pragma mark - 检测WPK协议是否存在- (BOOL)startCheckSupportURL:(NSURL *)url{ //module NSString *module = [_util getModuleStrFromUrl:url]; //path NSString *path = [_util getPathStrFromUrl:url]; //param NSString *paramStr = [_util getParamStrFromUrl:url]; WPKRouterAction *actionModel = [_util getActionFromModule:module path:path]; WPKRParamModelBase*param; if ([actionModel.in length] > 0) { Class paramClass = NSClassFromString(actionModel.in); param = [[paramClass alloc] init]; } else { //h5不设置入参,只需要flagID param = [[WPKRParamModelBase alloc] init]; } NSDictionary *paramDic = [_util getParametersDictionaryWithParams:paramStr]; [[WPKSerializationHelper sharedInstance] importDictionary:paramDic toObject:param]; return [self startCheckSupportModule:module path:path param:param];}- (BOOL)startCheckSupportURLString:(NSString *)urlString{ if (!urlString || ![urlString isKindOfClass:[NSString class]] || ![urlString hasPrefix:@"WPK://"]) { return NO; } NSURL *url = [NSURL URLWithString:urlString]; if (!url) { urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];// urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; url = [NSURL URLWithString:urlString]; } return [self startCheckSupportURL:url];}- (BOOL)startCheckSupportModule:(NSString *)kWPKRouter_M path:(NSString *)kWPKRouter_M_P param:(WPKRParamModelBase*)param{ WPKRouterAction *WPKActionModel = [_util getActionFromModule:kWPKRouter_M path:kWPKRouter_M_P]; if (![WPKActionModel excutor]) { return NO; } else { //参数判断 if ([WPKActionModel.in length] > 0) { Class paramClass = NSClassFromString(WPKActionModel.in); if (param && ![param isKindOfClass:paramClass]) { return NO; } } return YES; }}#pragma mark - private method- (void)handleAction:(WPKRouterAction *)action paramModel:(NSObject*)paramModel block:(WPKRouterBlock)block{ if (![action excutor]) { [_util goto404Error:[action.moduleName stringByAppendingPathComponent:action.pathName] withBlock:block]; } else { if ([paramModel isKindOfClass:[WPKRParamModelBase class]]) { action.url = [(WPKRParamModelBase*)paramModel originURL]; } if ([action.in length] > 0) { Class paramClass = NSClassFromString(action.in); if (paramModel && ![paramModel isKindOfClass:paramClass]) { [_util goto404Error:[action.moduleName stringByAppendingPathComponent:action.pathName] withBlock:block]; return; } }#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wincompatible-pointer-types" [action doActionWithParam:paramModel block:block];#pragma clang diagnostic pop } self.actionModel = action;}- (id)handleAction:(WPKRouterAction *)action paramModel:(NSObject *)paramModel{ self.actionModel = action; if (![action excutor]) { [_util goto404Error:[action.moduleName stringByAppendingPathComponent:action.pathName] withBlock:nil]; } else { if ([paramModel isKindOfClass:[WPKRParamModelBase class]]) { action.url = [(WPKRParamModelBase*)paramModel originURL]; } if ([action.in length] > 0) { Class paramClass = NSClassFromString(action.in); if (paramModel && ![paramModel isKindOfClass:paramClass]) { [_util goto404Error:[action.moduleName stringByAppendingPathComponent:action.pathName] withBlock:nil]; return nil; } }#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wincompatible-pointer-types" return [action doActionWithParam:paramModel];#pragma clang diagnostic pop } return nil;}#pragma mark - 失败回调- (void)handleOldVersionWithUrl:(NSURL *)url{ /* WPK://qrcode:1#feedId:o_1462533315926565 WPK://c-2345 */ // 浏览器对第二个#进行了混乱解析, NSString *newAbsoluteString = [url.absoluteString stringByReplacingOccurrencesOfString:@"%23" withString:@"#"]; NSDictionary *dict = @{@"WPKUrl":newAbsoluteString.length?newAbsoluteString:@""}; [self startModuleSecoupled:@"qrcode" path:@"qrcodeTool" paramDict:dict block:nil];}- (NSMutableArray *)actionModelArray{ if (!_actionModelArray) { _actionModelArray = [NSMutableArray arrayWithCapacity:0]; } if (_actionModelArray.count >= 19) { NSArray * keyArr = self.actionModeBlockDic.allKeys; for (NSString * key in keyArr) { if ([self.actionModeBlockDic[key] isEqual:_actionModelArray.firstObject]) { [_actionModelArray removeObject:_actionModelArray.firstObject]; [self.actionModeBlockDic removeObjectForKey:key]; break; } } } return _actionModelArray;}- (NSMutableDictionary *)actionModeBlockDic{ if (!_actionModeKeyDic) { _actionModeKeyDic = [NSMutableDictionary dictionary]; } return _actionModeKeyDic;}- (NSString *)getDateNow{ NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0]; NSTimeInterval a=[dat timeIntervalSince1970]*1000; NSString *timeString = [NSString stringWithFormat:@"%f", a]; return timeString;}@end@implementation NSObject(WPKRouterExtension)- (NSString *)routerKey{ return objc_getAssociatedObject(self, (__bridge const void *)(WPK_ROUTER_KEY_STRING));}- (void)setRouterKey:(NSString *)routerKey{ objc_setAssociatedObject(self, (__bridge const void *)(WPK_ROUTER_KEY_STRING), routerKey, OBJC_ASSOCIATION_COPY);}@end
App 调用插件代码 及传参
// [[WPKRouter sharedInstance] startModuleSecoupled:WPK_kPlatformName path:wpk_kNameCamSetting paramDict:@{@"deviceMac":@"2CAA8E21AEC7",@"deviceModel":@"XXXC1-JZ",@"nameCamsSetingType":WPK_Type_bding,@"routeAddress":@"namecamseting",@"progress":@"0.75"} block:^(WPKRCallbackModel *result) {// }];
plist文件 设置
基础架构