Latest 0.4.0
Homepage https://github.com/Arror/RTSession
License MIT
Platforms ios 10.0
Authors

说明

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

该项目为 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 -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) throws -> RTRequest<RTInvoice> {
        struct Parameter: Codable {
            let userID: String
        }
        return try RTRequest(
            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(parameter: Data, completion: RTCompletion) {
        struct Parameter: Codable {
            let userID: String
        }
        let p: Parameter
        do {
            p = try JSONDecoder().decode(Parameter.self, from: parameter)
        } catch {
            completion.c(.failure(RTError(code: .decodeError, errorDescription: error.localizedDescription)))
            return
        }
        self.loadInvoice(userID: p.userID) { result in
            switch result {
            case .success(let value):
                do {
                    completion.c(.success(try JSONEncoder().encode(value)))
                } catch {
                    completion.c(.failure(RTError(code: .encodeError, errorDescription: error.localizedDescription)))
                }
            case .failure(let error):
                completion.c(.failure(error))
            }
        }
    }
}

服务实现

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,发起调用

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

更多

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

未来

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

Latest podspec

{
    "name": "RTSession",
    "version": "0.4.0",
    "summary": "Cross module process call",
    "description": "CMPC for iOS project.",
    "homepage": "https://github.com/Arror/RTSession",
    "license": "MIT",
    "authors": {
        "Arror": "[email protected]"
    },
    "source": {
        "git": "https://github.com/Arror/RTSession.git",
        "tag": "0.4.0"
    },
    "platforms": {
        "ios": "10.0"
    },
    "swift_versions": "5.0",
    "swift_version": "5.0",
    "subspecs": [
        {
            "name": "Core",
            "source_files": "RTSession/Classes/Core/**/*",
            "dependencies": {
                "RTCore": []
            }
        },
        {
            "name": "RTURLBridge",
            "source_files": "RTSession/Classes/URLBridge/**/*"
        }
    ]
}

Pin It on Pinterest

Share This