解决问题

场景1

从apns推送来的的信息,根据服务端推送过来的数据规则,跳转到对应的控制器。

场景2

点击webview中某链接时,跳转到原生ViewController中继续后续操作。
要实现以上的产品逻辑, 通常都需要前后端约定一些规则实现跳转。
约定的弊端很明显, 需要开发前就约定很多规则, 不一定能覆盖所有逻辑,没有覆盖到的逻辑需要更新客户端才能实现跳转,并且要各种switch判断,肯定会晕乎的。
本项目就是为了解决这种问题,只需要根据后台返回的数据则可实现万能跳转。要怎么跳转后台你们来决定吧,-_-#

简介

这是一个轻量的web view与js交互Demo。
根据dict字典生成对象。 适用webview或push推送时,根据后台传回字典实现动态跳转。ps:webview与js的交互依赖WebViewJavascriptBridge。
后台提供json如下,即会根据className生成TestViewController2控制器,并且把title、comFrom赋值给控制器:

1
2
3
4
5
{
'className': 'TestViewController2',
'title': '页面2',
'comFrom':'web'
}

使用

可以直接根据字典规则跳转

1
[D3Generator createViewControllerWithDictAndPush:data];

可以生成控制器自行跳转

1
UIViewController *vc = [D3Generator createViewControllerWithDict:data];

思路

  1. 后台提供json,信息包括:要生成的控制器名称、跳转到该控制器所需的参数值。
  2. 利用objective-c强大的runtime动态特性,通过NSClassFromString生成控制器对象。
  3. 利用objective-c强大的runtime动态特性,通过setValue设置控制器对象所需的参数值。
  4. 获取window的rootViewcontroller,然后实现界面跳转。

实现代码

动态生成对象:

1
2
Class class = NSClassFromString(dict[@"className"]);
id object = [[class alloc]init];

获取控制器属性值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(NSMutableArray*)getPropertiesWithClass:(Class)cls{
// 获取当前类的所有属性
unsigned int count;// 记录属性个数
objc_property_t *properties = class_copyPropertyList(cls, &count);
// 遍历
NSMutableArray *mArray = [NSMutableArray array];
for (int i = 0; i < count; i++) {
// objc_property_t 属性类型
objc_property_t property = properties[i];
// 获取属性的名称 C语言字符串
const char *cName = property_getName(property);
// 转换为Objective C 字符串
NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
[mArray addObject:name];
}
return mArray.copy;
}

设置属性值:

1
2
3
4
5
6
 NSArray *properties = [self getPropertiesWithClass:class];
for (NSString* key in properties) {
if (dict[key]) {
[object setValue:dict[key] forKey:key];
}
}

实例:

  1. ExampleApp.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!doctype html>
<html><head>
</head><body>
<h1>我是UIWebview</h1>
<script>
function clickButton1(){
var data = {'className': 'TestViewController',
'comFrom':'web'};
window.WebViewJavascriptBridge.send(data);
};

function clickButton2(){
var data = {'className': 'TestViewController1',
'comFrom':'web'};
window.WebViewJavascriptBridge.send(data);
};

function clickButton3(){
var data = {'className': 'TestViewController2',
'storyboard': 'Main',
'comFrom':'web'};
window.WebViewJavascriptBridge.send(data);
};
</script>

<div id='button1' onClick='clickButton1()'>Go VC1, 跳转到纯代码写的vc</div><br>
<div id='button2' onClick='clickButton2()'>Go VC2, 跳转到xib写的vc</div><br>
<div id='button3' onClick='clickButton3()'>Go VC3, 跳转到storyboard写的vc</div>

</body></html>

2.uiwebview所在控制器(依赖WebViewJavascriptBridge)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import "WebViewController.h"
import "WebViewJavascriptBridge.h"
import "D3Generator.h"

@interface WebViewController ()<UIWebViewDelegate>
@property(nonatomic,strong)WebViewJavascriptBridge *bridge;
@property (weak, nonatomic) IBOutlet UIWebView *webView;

@end

@implementation WebViewController

(void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"];
NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
NSURL *baseURL = [NSURL fileURLWithPath:htmlPath];
[_webView loadHTMLString:appHtml baseURL:baseURL];
[self addRoute:_webView];
}

-(void)addRoute:(UIWebView*)webView{
_bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ObjC received message from JS: %@", data);
responseCallback(@"报告: IOS收到!!!");

[D3Generator createViewControllerWithDictAndPush:data];
// 或者:
// UIViewController *vc = [D3Generator createViewControllerWithDict:data];
// [self.navigationController pushViewController:vc animated:YES];
}];
}
@end

完整代码:https://github.com/mozhenhau/D3Generator