RTSession 0.8.0

RTSession 0.8.0

Maintained by Arror.



RTSession 0.8.0

  • By
  • Arror

RTSession

说明

该工程仍处于早期阶段,不建议在工程中直接使用。

该项目为 Target-Action 组件化方案的现代化实现。使用 Thrift 文件定义接口,清晰明确,同时可作为文档。使用代码生成工具,开发者在开发中不在使用硬编码进行调用,避免产生低级错误,提高开发效率。

工具

thrift:Thrift 文件解析工具

swift-gen:Swift 代码生成工具

下载可执行文件或者下载源码编译,使用时将thriftswift-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 --input ./Services/InvoiceService.thrift --clientOutput ../RTServices --serverOutput ../RTInvoiceModule

生成文件: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, completion: @escaping (RTResult<RTInvoice, RTError>) -> Void) {
        struct Parameter: Codable {
            let userID: String
        }
        RTSession.shared.invoke(
            method: "InvoiceService.loadInvoice",
            parameter: Parameter(userID: userID),
            completion: completion
        )
    }
}

生成文件: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: "1234567890") { 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管理。所有的硬编码全部通过代码生成器生成,无需开发者维护,可减少在开发过程中低级错误的出现。文档升级的同时,更新生成的代码,编译器会帮助我们检查可能出现的错误,尽可能的降低开发成本和沟通成本。

更多

在实际开发中一个不可忽略的问题是如何处理URLRTSession允许以method字符串和parameter字典参数发起调用,method必须为InvoiceService.loadInvoice格式,而parameter必须可生成Datamethodparameter必须和服务提供者匹配。RTURLBridge允许开发者处理URL做匹配,详情请看源码。

未来

目前代码生成器可以生成Swift代码,完成Module间的通信,同样可以实现其他语言的代码生成器。例如我们可以实现一个Flutter插件的代码生成器,实现和Flutter的通信等等。