iOS组件化
RTSession
说明
该工程仍处于早期阶段,不建议在工程中直接使用。
该项目为 Target-Action
组件化方案的现代化实现。使用 Thrift
文件定义接口,清晰明确,同时可作为文档。使用代码生成工具,开发者在开发中不在使用硬编码进行调用,避免产生低级错误,提高开发效率。
工具
thrift:Thrift 文件解析工具
swift-gen:Swift 代码生成工具
下载可执行文件或者下载源码编译,使用时将thrift
、swift-gen
放置于同一文件夹下。
示例
工程以集成发票组件为例,来展示组件化工程结构,工程中以Target
表示Pod
。
服务定义
定义 thrift
文件:LoginService.thrift
struct Invoice {
0: required i32 id
1: required string name
2: required string email
}
service InvoiceService {
Invoice loadInvoice(1: required string userID)
}
生成代码
终端执行如下命令
./thrift --clientNamespace RT --serverNamespace RTServer -i ./Services/InvoiceService.thrift -o ./
生成文件:InvoiceService.c.swift
,放置在RTService
中提供给替他模块调用
//
// Code generated by thrift & swift-gen.
// Don't edit manually.
//
import Foundation
import RTSession
public struct RTInvoice: Codable {
public let id: Int
public let name: String
public let email: String
public init(id: Int, name: String, email: String) {
self.id = id
self.name = name
self.email = email
}
}
public enum InvoiceService {
public static func loadInvoice(userID: String) -> RTClientRequest<RTInvoice> {
struct Parameter: Codable {
let userID: String
}
return RTClientRequest(
method: "InvoiceService.loadInvoice",
parameter: Parameter(userID: userID),
responseType: RTInvoice.self
)
}
}
生成文件:InvoiceService.s.swift
,该文件放置于RTInvoiceModule
//
// Code generated by thrift & swift-gen.
// Don't edit manually.
//
import Foundation
import RTSession
struct RTServerInvoice: Codable {
let id: Int
let name: String
let email: String
}
protocol __RTInvoiceServiceProtocol: class {
func loadInvoice(userID: String, completion: @escaping (RTResult<RTServerInvoice, RTError>) -> Void)
}
@objc(RTInvoiceService)
class RTInvoiceService: NSObject, __RTInvoiceServiceProtocol {
@objc private func __loadInvoice(request: RTServerRequest) {
struct Parameter: Codable {
let userID: String
}
switch request.parse(parameterType: Parameter.self) {
case .success(let p):
self.loadInvoice(userID: p.userID) { request.completionHandler($0.dataResult()) }
case .failure(let e):
request.completionHandler(.failure(e))
}
}
}
服务实现
RTInvoiceModule
实现__RTInvoiceServiceProtocol
协议
extension RTInvoiceService {
func loadInvoice(userID: String, completion: @escaping (RTResult<RTServerInvoice, RTError>) -> Void) {
let invoiceVC = RTInvoiceViewController.makeViewController(ensureAction: { vc, invoice in
vc.dismiss(animated: true, completion: {
completion(.success(invoice))
})
}, cancelAction: { vc in
vc.dismiss(animated: true, completion: {
completion(.failure(RTError(code: RTError.Code(rawValue: "user_cancel"), errorDescription: "User click cancel button.")))
})
})
UIViewController.current.present(UINavigationController(rootViewController: invoiceVC), animated: true, completion: nil)
}
}
调用方实现
在主工程或其他模块中引入RTServices
,发起调用
InvoiceService.loadInvoice(userID: "Arror").invoked { result in
switch result {
case .success(let invoice):
let alert = UIAlertController(title: "Success", message: "\(invoice.name)\n\(invoice.email)", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
UIViewController.current.present(alert, animated: true, completion: nil)
case .failure(let error):
let alert = UIAlertController(title: "Failure", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
UIViewController.current.present(alert, animated: true, completion: nil)
}
}
小结
至此,组件化开发流程已初见雏形。定义的Thrift
文件可作为文档,清晰明确,更方便使用Git
管理。所有的硬编码全部通过代码生成器生成,无需开发者维护,可减少在开发过程中低级错误的出现。文档升级的同时,更新生成的代码,编译器会帮助我们检查可能出现的错误,尽可能的降低开发成本和沟通成本。
更多
在实际开发中一个不可忽略的问题是如何处理URL
,RTSession
允许以method
字符串和parameter
字典参数发起调用,method
必须为InvoiceService.loadInvoice
格式,而parameter
必须可生成Data
,method
和parameter
必须和服务提供者匹配。RTURLBridge
允许开发者处理URL
做匹配,详情请看源码。
未来
目前代码生成器可以生成Swift
代码,完成Module
间的通信,同样可以实现其他语言的代码生成器。例如我们可以实现一个Flutter
插件的代码生成器,实现和Flutter
的通信等等。