前言
其实这两年的更新频次相比21年是下降很多的,主要自22年之后,手上的项目就接连不断,被客户项目整的死去活来,当然在目前这个方式下,有活就说明能持续作业,我应该感到欣喜。
其实,就我自己的认知而言,我觉得自己很难写出十分艰深的技术文章,我也一向为此而感到苦恼与不安,毕竟谁都有一个大神梦,不过我或许只能在此停驻吧。
今天给咱们共享一例用enum处理JS传递给Native侧的事情音讯
,算是在作业中总结的一点小实践,假如能够给咱们一些启发就好了。
JS事情在Native侧的监听
在App开发过程中,咱们会运用到H5页面,而加载H5页面,或许就不可避免需要和Web进行交互。
在iOS侧,咱们一般都会运用到WebKit中,WebView相关的API进行设置与交互,其核心代码如下:
let config = WKWebViewConfiguration()
config.userContentController.add(WeakScriptMessageDelegate(scriptDelegate: self), name:"showNativeAlert")
let preferences = WKPreferences()
preferences.javaScriptCanOpenWindowsAutomatically = true
config.preferences = preferences
let webView = WKWebView(frame: view.bounds, configuration: config)
在初始化WebView的时分,咱们对WebView的配置项里边config.userContentController.add(WeakScriptMessageDelegate(scriptDelegate: self), name:"showNativeAlert")
咱们增加了一个叫"showNativeAlert"
的监听事情,也就是说当JS那边调用下面这个方法的时分,咱们能够在署理的回调中监听到:
JS侧触发事情
window.webkit.messageHandlers.showNativeAlert.postMessage('来个原生弹窗');
Native侧监听事情
extension MyJueJinController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("方法名:\(message.name)")
print("参数:\(message.body)")
if message.name = "showNativeAlert" {
print("监听了JS给Nativ的showNativeAlert方法,触发对应的逻辑方法")
}
}
}
一起,咱们在Controller析构的时分要记住移除"showNativeAlert"
这个句柄:
deinit {
webView.configuration.userContentController.removeScriptMessageHandler(forName: "showNativeAlert")
}
咱们能够看到在整个Native侧,咱们一向都在运用"showNativeAlert"
这个硬编码字符串,假如咱们WebView监听的事情不多,这样写如同也没什么问题,可是假如监听的事情多了,这样写既不高雅,一起持续维护的成本也会特别高。一起,硬编码的字符串也是危险。
你不得不在func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
写更多的if else if
或者switch
:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("方法名:\(message.name)")
print("参数:\(message.body)")
if message.name = "showNativeAlert" {
print("监听了JS给Nativ的showNativeAlert方法,触发对应的逻辑方法")
} else if message.name = "goToNext" {
} else {
}
switch message.name {
case "showNativeAlert":
break
case "goToNext":
break
default:
break
}
}
难道就没有什么好的方法去处理这些JS传递给Native侧的事情音讯的句柄吗?
假如你看过Swift:通过Protocol封装统和入参这篇文章,你一定会有主意的。
这儿,我先说结论,通过enum来处理JS传递给Native侧的事情音讯的句柄。
你们或许会有疑惑,为什么又又又又是enum,且听我娓娓道来。
运用enum的优势
- enum能够很好的处理硬编码字符串
enum ScriptMessageHandlerType: String {
case showNativeAlert
case goToNext
case helloWorld = "hello_world"
}
enum ScriptMessageHandlerType这种”看似“继承String的方式,实际上是给每个枚举值界说了一个rawValue,而且它直接映射的就是其字符串编码,比方这样打印:
print(ScriptMessageHandlerType.showNativeAlert.rawValue)
"showNativeAlert"
一起咱们关于枚举值的rawValue也能够自己进行界说与映射,比方上面代码的case helloWorld = "hello_world"
,咱们对其打印:
print(ScriptMessageHandlerType.helloWorld.rawValue)
"hello_world"
一起咱们也能够容易的将一个匹配的字符串转成枚举值,比方下面:
let type = ScriptMessageHandlerType(rawValue: "showNativeAlert")
type此刻是一个可选类型,因为ScriptMessageHandlerType(rawValue: "")
假如是一个匹配不上的字符串,那么此刻type就nil,在实战运用的时分咱们需要留意。
- enum能够遵守CaseIterable协议,简略容易的将一切的枚举事情转为数组
extension ScriptMessageHandlerType: CaseIterable {}
看见上面这个理由,你或许会觉得,转成数组和监听JS事情有什么关系?
记住这段代码吗:
/// 添加监听句柄
config.userContentController.add(WeakScriptMessageDelegate(scriptDelegate: self), name:"showNativeAlert")
/// 移除监听句柄
webView.configuration.userContentController.removeScriptMessageHandler(forName: "showNativeAlert")
假如咱们有更多的句柄需求,这段代码你或许就多写几回了,
不过假如此刻咱们运用的是enum,那么写起来就不费吹灰之力了:
/// 运用for循序添加句柄
for type in ScriptMessageHandlerType.allCases {
config.userContentController.add(WeakScriptMessageHandlerDelegate(delegate: self), name: type.rawValue)
}
/// 运用for循序移除句柄
for type in ScriptMessageHandlerType.allCases {
webView.configuration.userContentController.removeScriptMessageHandler(forName: type.rawValue)
}
是不是这样看起来,十分简练了呢?
- enum与switch配合运用,不会遗漏逻辑
终究让我来看看怎么处理监听的JS事情,咱们重构了func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
里边代码:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("方法名:\(message.name)")
print("参数:\(message.body)")
guard let type = ScriptMessageHandlerType(rawValue: message.name) else {
return
}
switch type {
case .showNativeAlert:
break
case .goToNext:
break
case .helloWorld:
break
}
}
因为此刻ScriptMessageHandlerType类型是有穷的,所以不用写default这个判断。当你在ScriptMessageHandlerType枚举类型中新增枚举值的时分,假如在switch type
中忘掉增加新增枚举值的代码判断,会直接编译报错,从而下降因为新增句柄而忘掉处理新增句柄逻辑的情况产生。
所以,基于以上几点原因,我用enum处理JS传递给Native侧的事情音讯,各位觉得怎么样?
总结
这篇文章,写了这么多,成果到头来,终究还是在说enum的用法。
讲真的,Swift的enum真的十分强壮,强壮到有的时分我自己在运用的时分也会感叹居然能够这样?
假如持续做Swift开发,咱们无妨这样来反推一下自己代码,这儿可不能够试试enum?或许一个好点子就来了。
参阅文档
Swift:通过Protocol封装统和入参
自己写的项目,欢迎咱们star⭐️
RxStudy:RxSwift/RxCocoa框架,MVVM模式编写wanandroid客户端。
GetXStudy:运用GetX,重构了Flutter wanandroid客户端。
附上WeakScriptMessageDelegate的相关代码
/// 专用WKScriptMessageHandler的署理层
class WeakScriptMessageDelegate: NSObject {
//MARK: - 特点设置 之前这个特点没有用weak润饰,所以一向持有,无法释放
private weak var scriptDelegate: WKScriptMessageHandler!
//MARK: - 初始化
convenience init(scriptDelegate: WKScriptMessageHandler) {
self.init()
self.scriptDelegate = scriptDelegate
}
}
extension WeakScriptMessageDelegate: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
scriptDelegate.userContentController(userContentController, didReceive: message)
}
}