概述
这是一个关于业务模块与路由权限的管理方案,用于增强在模块化架构场景下,业务模块的健壮性。
通过对App生命周期的转发,来解除App入口与业务模块管理逻辑的耦合。
通过协议来管理API路由,通过注册制实现API的服务发现。
业务模块
重新组织后,业务模块的管理会变得松散,容易实现插拔复用。
协议
public protocol SpaceportModuleProtocol {
var loaded: Bool {
get set}
/// 决定模块的加载顺序,数字越大,优先级越高
/// - Returns: 默认优先级为1000
static func modulePriority() -> Int
/// 加载
func loadModule()
/// 卸载
func unloadModule()
/// UIApplicationDidFinishLaunching
func applicationDidFinishLaunching(notification: Notification)
/// UIApplicationWillResignActive
func applicationWillResignActive(notification: Notification)
/// UIApplicationDidBecomeActive
func applicationDidBecomeActive(notification: Notification)
/// UIApplicationDidEnterBackground
func applicationDidEnterBackground(notification: Notification)
/// UIApplicationWillEnterForeground
func applicationWillEnterForeground(notification: Notification)
/// UIApplicationWillTerminate
func applicationWillTerminate(notification: Notification)
}
特性
- 实现模块加载/卸载保护,模块只会加载/卸载一次。
- 同一个模块的注册是替换制,新模块会替代旧模块。
- 提供模块优先级配置,优先级高的模块会更早加载并响应Application的生命周期回调。
最佳实践
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
setupModules()
// ......
return true
}
func setupModules() {
var modules: [SpaceportModuleProtocol] = [
LoggerModule(), // 4000
NetworkModule(), // 3000
FirebaseModule(), // 2995
RouterModule(), // 2960
DynamicLinkModule(), // 2950
UserEventRecordModule(), // 2900
AppConfigModule(), // 2895
MediaModule(), // 2800
AdModule(), // 2750
PurchaseModule(), // 2700
AppearanceModule(), // 2600
AppstoreModule(), // 2500
MLModule() // 2500
]
#if DEBUG
modules.append(DebugModule()) // 2999
#endif
Spaceport.shared.registerModules(modules)
Spaceport.shared.enableAllModules()
}
}
协议路由
通过路由的协议化管理,实现模块/组件之间通信的权限管理。
服务方
通过Router Manger注册API协议,可以根据场景提供不同的协议版本。业务方
通过Router Manager发现并使用API协议。
最佳实践
实现API协议
protocol ResultVCRouterAPI {
@MainActor func vc(from: ResultVCFromType, project: Project) throws -> ResultVC
@MainActor func vcFromPreview(serviceType: EnhanceServiceType, originalImage: UIImage, enhancedImage: UIImage) async throws -> ResultVC
}
class ResultVCRouter: ResultVCRouterAPI {
@MainActor func vc(from: ResultVCFromType, project: Project) throws -> ResultVC {
let vc = ResultVC()
vc.modalPresentationStyle = .overCurrentContext
try vc.vm.config(project: project)
vc.vm.fromType = from
return vc
}
@MainActor func vcFromPreview(serviceType: EnhanceServiceType, originalImage: UIImage, enhancedImage: UIImage) async throws -> ResultVC {
let vc = ResultVC()
vc.modalPresentationStyle = .overCurrentContext
try await vc.vm.config(serviceType: serviceType, originalImage: originalImage, enhancedImage: enhancedImage)
return vc
}
}
注册API协议
public class RouterManager: SpaceportRouterService {
public static let shared = RouterManager()
private override init() {
}
static func API<T>(_ key: TypeKey<T>) -> T? {
return shared.getRouter(key)
}
}
class RouterModule: SpaceportModuleProtocol {
var loaded = false
static func modulePriority() -> Int {
return 2960 }
func loadModule() {
// 注册API
RouterManager.shared.register(TypeKey(ResultVCRouterAPI.self), router: ResultVC())
}
func unloadModule() {
}
}
使用协议
// 通过 RouterManager 获取可用API
guard let api = RouterManager.API(TypeKey(ResultVCRouterAPI.self)) else {
return }
let vc = try await api.vcFromPreview(serviceType: .colorize, originalImage: originalImage, enhancedImage: enhancedImage)
self.present(vc, animated: false)
总结
我们的业务向模块化、组件化架构演化的过程中,逐步出现跨组件调用依赖嵌套,插拔困难等问题。
通过抽象和简化,设计了这个方案,作为后续业务组件化的规范之一。通过剥离业务模块的生命周期,以及统一通信的方式,可以减缓业务增长带来的代码劣化问题。