1. 问题
在 AppHost.framework【注1】(以下简称 AppHost) 的编码中,需要处理很多预先导入到 webview 里的 js 文件,有一些不关键功能是用 .js 的文件读到内存的,还有一些比较短小的 js 源码,如;
1
2
3
4
|
(function(e){
e.setAttribute('src','%@');
document.getElementsByTagName('body')[0].appendChild(e);
})(document.createElement('script'));
|
要写到代码里和 objc 代码一起。还有,在 AppHost 里,有个 ah_doc 模块,在编写注释时,需要输出完整的 js 代码,如
1
2
3
4
5
6
7
8
|
window.appHost.invoke('startNewPage', { 'url': 'http://you.163.com/','title': 'title',
'type': "push",
'backPageParameter': {
'url': 'http://qian.163.com',
'title': 'title',
'type': 'push'
}
})
|
这个字符串里包含了大量的单引号、双引号,而且为了保持可读性、维护性,需要多行输出。
这是非常典型的问题,传统的多行字符串声明有没有方法很好的解决?
2.常见多行声明方式
- 利用@““包裹起来,换行
1
2
3
4
|
NSString *a = @"[AppHost] "
@"It is called \"jsbridge\"."
@"like window.ah('ready') = function(){};"
@"fail to inject javascript";
|
- 利用"“包裹起来,换行
1
2
3
4
|
NSString *b = @"[AppHost] "
"It is called \"jsbridge\"."
"like window.ah('ready') = function(){};"
"fail to inject javascript";
|
-
最最常见的 \ 号分隔,保留缩进(注意观察截图里的 linenum 和代码的距离)
-
最最常见的 \ 号分隔,不保留缩进(注意观察截图里的 linenum 和代码的距离)
-
非多行
1
|
NSString *d = @"[AppHost] It is called \"jsbridge\".like window.ah('ready') = function(){};fail to inject javascript";
|
输出结果
可见,对于 a\b\c1\d 变量的值而言等价的。对 c,有个陷阱:实际上获得的字符串是包含编辑器缩进。我们现在基本都会让编辑器自动缩进代码,所以容易出错。
上面 4 种写法,都需要处理字符"
引号嵌套的问题,或者需要手动加 "
号,或手动写 \
号,要么一行损失掉可读性。
作者一般用 d 方法:在 vscode
里写好 JavaScript 代码,放在 sublime text
里 先replace("\"","\\\"")
,然后command+j
合并行,再贴到Xcode
里。直到我发现无意中创建的一个宏完美的解决了这个问题。
1
2
3
4
5
6
7
8
|
ah_doc_code(window.appHost.invoke('startNewPage', { 'url': 'http://you.163.com/','title': 'title',
'type': "push",
'backPageParameter': {
'url': 'http://qian.163.com',
'title': 'title',
'type': 'push'
}
}))
|
####优点
- 多行,保存源码中的缩进和换行
- 单双引号混排,不需要转义
- 使用简单,只需要包含在对
()
中,甚至都不需要外层加双引号、#号(NSString)
- 神似 ruby 中的多行字符串声明(以下代码是 AppHost 里生成自动测试用例的片段)
3. 那个宏 lei 了
1
|
#define ah_ml(str) @#str
|
🍄简单的令人发指。用例:
1
2
3
4
|
result = [NSString stringWithFormat:ah_ml((function(e){
e.setAttribute("src",'%@');
document.getElementsByTagName('body')[0].appendChild(e);
})(document.createElement('script'));), urlToRequest.absoluteString];
|
查看预处理的代码,代码e.setAttribute("src",'%@');
里的引号自动转义。
1
|
result = [NSString stringWithFormat:@"(function(e){ e.setAttribute(\"src\",'%@'); document.getElementsByTagName('body')[0].appendChild(e); })(document.createElement('script'));", urlToRequest.absoluteString];
|
完美呈现。
4.注
- AppHost.framework 是作者在网易有钱、严选工作中,抽离出来 JSBridge 的库,实现 native 和 h5 之间的通讯,内置诸多常用的功能,在业务简单的情况下可开箱即用,复杂情况允许灵活定制。预计在4月底开源。