由 Ipodishima 开发和维护,他是在 Wasappli Inc 的创始人兼首席技术官。(如果您需要开发应用程序,请联系我们的团队!}}
那么这个库有什么用呢?好问题。让我们通过提出另一个问题来回答。你有没有在某些时候遇到过以下问题?
所有这些问题都由 WAAppRouting
(以及更多)回答
home/events/3/register
总是很有用的。goto://bookings/bookingFromSearchID
。请参阅使用此库自动索引您的 CoreData
堆栈的路线实现示例 WACoreDataSpotlight。让我们说实话,GitHub 上有几个路由库可以处理某些已描述的行为。但它们都不符合我的所有要求。所以我带着一些想法写了这个库:
如果连返回按钮都没有,或者点击返回按钮会把我带回到打开应用之前的地方,那么打开酒店详情页面的应用就不行了。我只希望应用能打开,这样点击返回时,我能直接回到酒店城市的酒店列表...
如果你想自己提供,你应该能够做到。这个最后一点对我来说非常重要。我使用了太多与特定技术紧密相关的库。此外,它们越依赖其实现方式,可测试性就越低。这就是为什么你会看到许多协议都提供了一个默认实现。
从历史角度来看,我最初使用了HHRouter并实现了自己的栈控制器管理。然后,通过重写代码以支持iOS 9,我发现它只是一些没有错误处理的代码,与控制器层次紧密相连,可读性不高,等等。
我决定放弃它,找到更有趣的事情来做。我发现DeepLinkKit并使用了它,直到我意识到它并不符合我的栈需求。所以我重写了一个自定义路由处理器来处理它,并最终得出结论说DeepLinkKit的80%功能已经不再使用了。这就是我决定放弃它并写自己的库的原因。
所以你可能会在两个库的概念中认出一些东西,特别是在路由处理器中,即使实现与DeepLinkKit无关。
UINavigationController
来处理栈,也可以用于UITabBarController
。:itemID
和*
作为通配符字符。导入#import <WAAppRouting/WAAppRouting.h>
就可以开始了。
你还需要配置一个URL方案(这里我不会详细介绍——外面有大量文档)
导航控制器是一个好的起点
UINavigationController *navigationController = [[UINavigationController alloc] init];
你首先需要分配一个路由匹配器。你可以使用我写的默认实现,或者创建你自己的实现
// Create the default router
self.router = [WAAppRouter defaultRouter];
使用以下语法注册你的路径
url_path_component{ClassName}
url_path_component1{ClassName1}/url_path_component2{ClassName2}
你可以选择使用!
字符触发模态显示。例如:url_path_component{ClassName}/modal{ModalClass}!
当调用appscheme://url_path_component/modal
时,将ModalClass
实例以模态方式显示在导航控制器栈中,并将ClassName
放置在导航控制器栈中。
// Register the path
[self.router.registrar
registerAppRoutePath:
@"list{WAListViewController}/:itemID{WAListDetailViewController}/extra{WAListDetailExtraViewController}"
presentingController:navigationController];
如果有需要,添加一个块处理器
// Register some blocks
[self.router.registrar registerBlockRouteHandler:^(WAAppLink *appLink) {
// Do something every time we are in list/something
}
forRoute:@"list/*"];
最后,将导航控制器设置为根控制器
self.window.rootViewController = navigationController;
现在你可以开始使用了,并用
[self application:(UIApplication *)self openURL:[NSURL URLWithString:@"appscheme://list"] sourceApplication:nil annotation:nil];
不要忘记使用路由器!
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [self.router handleURL:url];
}
您使用的每个控制器都应该实现 WAAppRouterTargetControllerProtocol
(最好有一个基视图控制器)因此实现此方法,就像魔术般
- (void)reloadFromAppLinkRefresh {
// You can do something with self.appLink
// But more important: with self.appLinkRoutingParameters which has merged route|query|default parameters
NSString *articleTitle = self.appLinkRoutingParameters[@"article_title"];
}
从最简单的方法开始,但用创建实体来替换“创建路径”
// Create the entities
WAAppRouteEntity *list1Entity =
[WAAppRouteEntity routeEntityWithName:@"list"
path:@"list"
sourceControllerClass:nil
targetControllerClass:[WAListViewController class]
presentingController:navigationController
prefersModalPresentation:NO
defaultParametersBuilder:nil
allowedParameters:nil];
WAAppRouteEntity *list1DetailEntity =
[WAAppRouteEntity routeEntityWithName:@"listDetail"
path:@"list/:itemID"
sourceControllerClass:[WAListViewController class]
targetControllerClass:[WAListDetailViewController class]
presentingController:navigationController
prefersModalPresentation:NO
defaultParametersBuilder:^id<WAAppRouterParametersProtocol> {
NSMutableDictionary *defaultParameters = [NSMutableDictionary new];
defaultParameters[@"defaultParam"] = @1;
defaultParameters[@"defaultParam2"] = @"Default parameter 2";
return defaultParameters;
}
allowedParameters:nil];
将实体添加到注册器
// Register the entities
[self.router.registrar registerAppRouteEntity:list1Entity];
[self.router.registrar registerAppRouteEntity:list1DetailEntity];
有四个示例可用
SimpleExample
:这是一个样本,处理列表、详情和额外内容。这可以看作是文章列表、其详情和评论。SimpleExampleParameters
:这个样本与SimpleExample
相同,但使用的是WAAppLinkParameters
(这个库的另一个重要部分)。MoreComplexExample
:这个样本演示了如何处理标签栏控制器+如何处理模态窗口。PPRevealSample
:这个样本作为演示,通过一点努力,自定义容器可以适应路由库吗?代码有充分的文档说明,你应该能找到你所有的问题的答案。否则,打开一个问题,我会尽快回答。
您可能希望在控制器被分配时传入值。例如,在我参与的一个项目中,我们有一个图像缓存,控制器需要显示图像。这个图像缓存是由应用委托器分配的(为了避免单例并使代码更易于测试)。为了做到这一点,您需要向路由处理程序添加一个块实现
[routeHandler setControllerPreConfigurationBlock:^(UIViewController *controller, WAAppRouteEntity *routeEntity, WAAppLink *appLink) {
if ([controller isKindOfClass:[WABaseViewController class]]) {
((WABaseViewController *)controller).imageCache = imageCache;
}
}];
您可以通过设置此块来请求在运行时不要处理某些路由(例如,您可能希望在未登录时不要显示某些控制器)
[routeHandler setShouldHandleAppLinkBlock:^BOOL(WAAppRouteEntity *entity) {
// Could return NO if not logged in for example
return YES;
}];
您可以使用通配符URL,例如list/*/extra
,意味着对于任何值,而不是*
,都将执行实体或块。避免与实体一起使用,而应与块一起使用。形式为list/*
的URL将匹配list/path
和list/path/extra
。
以下是一个每当我们在list/
之后时触发的警告示例。
[registrar registerBlockRouteHandler:^(WAAppLink *appLink) {
[RZNotificationView showNotificationOn:RZNotificationContextAboveStatusBar
message:[NSString stringWithFormat:@"You are dealing with item ID %@", appLink[@"articleID"]]
icon:RZNotificationIconInfo
anchor:RZNotificationAnchorNone
position:RZNotificationPositionTop
color:RZNotificationColorYellow
assetColor:RZNotificationContentColorDark
textColor:RZNotificationContentColorDark
withCompletion:^(BOOL touched) {
}];
}
forRoute:@"list/*"];
如前所述,我讨厌那些不能自定义而不分叉和偏离原始源的库。因此,您可以通过两种方式来自定义路由器:自定义路由匹配器和自定义路由处理程序。
我的实现只处理基本用法。这意味着它不会支持查询中的key=value1, value2
等。它也是大小写敏感的。如果您有自己的URL配置,如list/$itemID
实现一个新的路由匹配器是个好主意!
开始时,阅读WAAppRouteMatcherProtocol
类。您需要实现两个方法:matchesURL: fromPathPattern:
和 parametersFromURL: withPathPattern:
。正如您在我的实现中可以看到的那样,我正在使用WARoutePattern
来匹配URL。这在某种程度上受到了SocKit的启发(对于命名约定)。
然后,你可以轻松创建路由器使用
// Allocate your route matcher
MyRouteMatcher *routeMatcher = [MyRouteMatcher new];
// Create the Registrar
WAAppRouteRegistrar *registrar = [WAAppRouteRegistrar registrarWithRouteMatcher:routeMatcher];
// Create the route handler
WAAppRouteHandler *routeHandler = [WAAppRouteHandler routeHandlerWithRouteRegistrar:registrar];
// Create the router
WAAppRouter *router = [WAAppRouter routerWithRegistrar:registrar
routeHandler:routeHandler];
例如,如果你想不处理堆栈,或者使用除 UINavigationController
之外的内容,那么考虑创建你自己的路由处理器。首先采用 WAAppRouteHandlerProtocol
协议。然后阅读 WAAppRouteHandler
获取灵感。
我仍然需要运行一些测试,但是想法是有一个用于经典 URL 方案的路由器,还有一个用于通用链接的路由器。
通过实现 3D Touch,用户可以直接在某些操作上打开您的应用,例如 新推文
、搜索推文
、获取方向
等。您只需遵循 UIApplicationShortcutItem
的文档 (在此处) 并执行以下操作:
- (void)application:(UIApplication * _Nonnull)application
performActionForShortcutItem:(UIApplicationShortcutItem * _Nonnull)shortcutItem
completionHandler:(void (^ _Nonnull)(BOOL succeeded))completionHandler {
if ([shortcutItem.type isEqualToString:@"newTweet"]) {
// goto://home/newTweet
}
}
例如使用 WACoreDataSpotlight(示例使用 WAppRouting
),您可以对 从搜索项目中打开应用
事件做出响应。
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
NSManagedObject *object = [self.mainIndexer objectFromUserActivity:userActivity];
if ([object isKindOfClass:[Company class]]) {
[AppLink goTo:@"companies/%@", ((Company *)object).name];
}
return YES;
}
您绝对应该查看 PPRevealSample
项目,以了解如何完成这项工作。如果您需要帮助,我也在这里。基本思路是尝试分配您需要的所有导航控制器并将它们传递为显示控制器。然后,它将表现得像标签栏(请参阅其类别)。如果没有,那么您处于 PPRevealSideViewController
上下文,其中导航控制器会动态分配。思路是将容器作为 presentingController
属性传递并实现 WAAppRoutingContainerPresentationProtocol
协议(您还需要可用的方法)。
您还不能(尚不能)呈现一个模态控制器然后推送一个详情控制器。就像呈现一个登录视图,但推送到注册控制器上。
因为堆栈检索是以处理控制器类唯一性来实现,所以当源控制器类不为 nil 时,您不能有两个或以上的 WAAppRouteEntity
具有相同的目标类。如果您需要在不同的地方重用控制器,请考虑创建一个主控制器的主子类,该主控制器处理所有行为。
这个库还有一点是 WAAppLinkParameters
类。其背后的想法是避免硬编码值。行为基于对 WAAppRouterParametersProtocol
协议的实现,这意味着您可以提供自己的或从 WAAppLinkParameters
继承,它提供了默认行为并实现所有协议方法。让我们看一下在 SimpleExampleParameters
示例项目中找到的示例。
首先创建一个子类
@interface ArticleAppLinkParameters : WAAppLinkParameters
@property (nonatomic, strong) NSNumber *articleID;
@property (nonatomic, strong) NSString *articleTitle;
@property (nonatomic, strong) NSNumber *displayType;
@end
在这里,您可以看到应该映射到URL键的三个对象。您需要重写mappingKeyProperty
获取器以提供映射url_key: object_property
- (NSDictionary *)mappingKeyProperty {
return @{
@"articleID": @"articleID",
@"article_title": @"articleTitle",
@"display_type": @"displayType"
};
}
我编写了一个关于UIViewController
的类别,用于为您合并对象进行配置。因此,现在您可以直接获取值
self.label.text = [NSString stringWithFormat:@"ArticleID: %@", ((ArticleAppLinkParameters *)self.appLinkRoutingParameters).articleID];`
您可以复制参数,并将值设置为将来使用
ArticleAppLinkParameters *params = [(ArticleAppLinkParameters *)self.appLinkRoutingParameters copy];
params.articleTitle = [NSString stringWithFormat:@"My super article %ld", (long)indexPath.row];
使用白名单获取查询
NSString *query = [params queryStringWithWhiteList:@[@"articleID", @"articleTitle", @"displayType"];
NSString
和NSNumber
参数(例如没有NSDate
)如果您遇到特定于WAAppRouting的问题,请在此处创建新的问题。
鼓励新的功能拉取请求,并且非常感激!请尽最大努力保持与现有代码风格的一致性。如果您正在考虑进行重大更改或添加到项目中,请先通过打开新的问题与我联系,以便有机会进行合并。