YMPromptKit 通过提供灵活的可扩展工具来简化您的应用程序代码,以实现软提示。等等,什么让提示变得 软 呢?
在 iOS 中最知名的硬提示是推送通知。这些通知的价值不容低估。应用程序的生存与否取决于其能够在您的移动设备屏幕上弹出高度相关且有即时操作性的警报的能力——或缺乏这种能力。不幸的是,一旦用户拒绝允许您向他们推送通知,您就没有多少选择了(很少有用户会费心手动重新启用该功能)。这一问题已经在 广泛讨论。
最简单的安装方式是使用 CocoaPods。Pod 的名称为 YMPromptKit。
pod 'YMPromptKit', '~> 1.0.0'
如果您不使用 CocoaPods,则需要将 YMPromptKit/
目录中的所有类添加到项目中。
YMPromptKit 默认依赖于 SDCAlertView(参见下一节)。
SDCAlertView 为 YMPromptKit 增加了功能价值及可靠性。但是,如果您无法使用 SDCAlertView 或其依赖项,或者遇到其他问题,您可以选择使用简单的 pod 引用来使用 iOS 本地提示
pod 'YMPromptKit/NativeAlerts', '~> 1.0.0`
请参阅 实现说明
YMPromptKit 支持 iOS 7.0 及更高版本。
由于依赖在 iOS 8.0 中引入的 API,某些功能在 iOS 7.0 下的性能会有所降低。在适用的情况下,这些差异已在 API 注释中注明。
示例应用程序位于 示例
文件夹 中。请查看。
一些 iOS 软提示已预装载,可直接使用。这些包括:
按照需要也可以添加额外的私有提示,例如请求用户登录或邀请朋友。
首先需要包含 YMPromptKit 的头文件,并分配一个 YMPromptManager
实例的空间
#import <YMPromptKit/YMPromptKit.h>
@interface AppDelegate : NSObject <UIApplicationDelegate>
@property (nonatomic, readonly) YMPromptManager *promptManager;
@end
现在获取一个 YMPromptManager
的引用。最简单的方法是创建一个包含所有预配置提示处理程序的提示管理器
_promptManager = [YMPromptManager createPromptManager];
提示管理器需要一个数据源来告诉它要向用户显示什么。在这种情况下,让我们把自己作为数据源。
self.promptManager.dataSource = self;
要实现数据源,我们需要提供一个提供 YMPrompt
实例的方法。对于这个例子,让我们假装我们只关心推送通知。添加以下方法:
- (YMPrompt *)promptManager:(YMPromptManager *)manager
promptForAccessType:(YMPromptAccessType)access
modes:(YMPromptAccessMode)modes {
if (access == kYMPromptAccessTypeNotifications) {
YMPrompt *prompt = [YMPrompt promptWithTitle:@"Stock Alerts"
message:@"Allow Yahoo Finance to send you important alerts"
@"about stocks you follow?"
grantTitle:@"Yes"
denyTitle:nil
contentView:nil];
return prompt;
}
return nil;
}
现在,当您的应用程序中的某些代码请求 YMPromptManager
请求推送通知的权限时,提示管理器将从我们这里获取一个 YMPrompt
实例。我们将提供的提示将有一个自定义标题、消息和授权权限按钮标签。不允许按钮标题将不会指定;它将默认为 "稍后再说"。
在您的应用程序的任何位置触发提示,如下所示
[delegate.promptManager requestAccess:kYMPromptAccessTypeNotifications
modes:YMPromptNotificationOptionTypeAlert
completionHandler:^(BOOL softPromptAccepted, BOOL osPromptAccepted, YMPromptAuthorizationStatus status) {
if (softPromptAccepted) {
if (osPromptAccepted) {
// User accepted the soft prompt and the OS prompt. Win!
} else {
// User accepted the soft prompt, but denied the OS prompt. Lose :(
}
} else {
if (status == YMPromptAuthorizationStatusNotDetermined) {
// The user declined your soft prompt. Not a win, not a loss.
} else if (status == YMPromptAuthorizationStatusDenied) {
// Already denied access by the OS
} else if (status == YMPromptAuthorizationStatusRestricted) {
// Already authorized, but there is some OS restriction
} else if (status == YMPromptAuthorizationStatusAuthorized) {
// Already authorized by the OS
}
}
}];
对于 iOS 8,您必须手动使用提示管理器记录注册结果。在您的应用程序代理中,在 -application: didRegisterUserNotificationSettings:
中记录通知注册结果。这也是您注册远程通知的时机。
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
BOOL success = (notificationSettings.types != UIUserNotificationTypeNone);
[delegate.promptManager recordNotificationRegistrationResult:success];
// Permission was granted, register for remote notifications
[application registerForRemoteNotifications];
}
YMPromptManagerDelegate
强制执行节奏软提示非常棒,但确保避免过于频繁地打扰用户的请求是一个提高用户退出率的方法。YMPromptKit 可以帮您实现合适的提示节奏。让我们确保我们的示例应用程序在 48 小时内不会要求推送通知权限超过一次,或者不超过 3 次。
添加一个代理方法,为提示管理器提供一些特定于应用程序的指导
- (BOOL)promptManager:(YMPromptManager *)manager shouldRequestAccessType:(YMPromptAccessType)accessType
modes:(YMPromptAccessMode)modes {
NSArray *promptLog = [manager.log promptHistory:accessType];
if (promptLog.count > 3) {
return NO; // enforce the request limit
} else if (promptLog.count) {
NSDictionary *dict = promptLog[0]; // data for the most recent history entry
NSDate *lastPromptDate = dict[kYMPromptLogDateKey];
NSTimeInterval interval = -3600 * 48; // 2 days, in seconds
if ([lastPromptDate timeIntervalSinceNow] > interval) {
return NO; // enforce the quiet period
}
}
return YES; // OK to display prompt!
}
上述代码使用提示日志来访问指定访问类型的提示历史记录。每个 YMPromptManager
都可以通过其 log
属性访问 YMPromptLog
。默认的提示管理器——那些由 [YMPromptManager createPromptManager]
返回的——始终使用可在 [YMPromptLog mainLog]
中获取的主提示日志。
在显示提示之前,一个 YMPromptManager
将向其 YMPromptLog
实例添加一个日期项。因此,提示日志代表了软提示的近期历史记录(默认情况下,每种类型的最后 15 次)。历史记录定期刷新到磁盘,并在会话之间持久化。
YMPromptLog
中跟踪自定义参数尽管软提示发生日期足以提供对节奏的粗略控制,但可以想象出无法通过此类有限数据满足的业务要求。为了解决这个问题,YMPromptLog
可以接受任意 NSPropertyListSerialization 兼容的元数据,并将其存储在每个事件条目中。
让我们为示例添加一个要求:五个会话必须在中按推送通知软提示之间进行。为此,实现YMPromptManagerDelegate
方法。
- (NSDictionary *)promptManager:(YMPromptManager *)manager
willRequestAccessType:(YMPromptAccessType)accessType
modes:(YMPromptAccessMode)modes {
NSNumber *sessionNum = self.sessionNumber;
return @{ @"session_number": sessionNum };
}
现在,每个事件都将有一个关联的字典,其中包含它在其中显示的会话编号。我们可以访问此信息,并使用它从-promptManager:shouldRequestAccessType:modes:
代理方法中应用特定于应用程序的逻辑。扩展上面的代理方法示例:
- (BOOL)promptManager:(YMPromptManager *)manager shouldRequestAccessType:(YMPromptAccessType)accessType
modes:(YMPromptAccessMode)modes {
NSArray *promptLog = [manager.log promptHistory:accessType];
if (promptLog.count > 3) {
return NO; // enforce the request limit
} else if (promptLog.count) {
NSDictionary *dict = promptLog[0]; // data for the most recent history entry
NSDate *lastPromptDate = dict[kYMPromptLogDateKey];
NSTimeInterval interval = -3600 * 48; // 2 days, in seconds
if ([lastPromptDate timeIntervalSinceNow] > interval) {
return NO; // enforce the quiet period
} else {
#pragma >>> New example code starts here >>>
NSDictionary *appData = dict[kYMPromptLogUserInfoKey];
NSNumber *lastSessionNum = appData[@"session_number"];
NSNumber *sessionNum = self.sessionNumber;
if ([sessionNum integerValue] < [lastSessionNum integerValue] + 5) {
return NO; // enforce minimum sessions betwen prompting
}
}
}
return YES; // OK to display prompt!
}
YMPromptKit利用SDCAlertView提供灵活的、类似于iOS的原生警报。这种设计带来的一个主要优势是软提示可以包括嵌入的自定义视图——即使在iOS 7上。
让我们在上面的运行示例中使用类似的图像进行添加。
- (YMPrompt *)promptManager:(YMPromptManager *)manager
promptForAccessType:(YMPromptAccessType)access
modes:(YMPromptAccessMode)modes {
UIImage *image = [UIImage imageNamed:@"push-notification.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, 150, 150);
imageView.contentMode = UIViewContentModeScaleAspectFit;
if (access == kYMPromptAccessTypeNotifications) {
YMPrompt *prompt = [YMPrompt promptWithTitle:@"Stock Alerts"
message:@"Allow Yahoo Finance to send you important alerts"
@"about stocks you follow?"
grantTitle:@"Yes"
denyTitle:nil
contentView:imageView];
}
return prompt;
为YMPromptKit提供动力的SDCAlertView是通过呈现模态视图控制器来工作的。当关闭警报时(即通过其按钮),SDCAlertView调用YMPromptKit完成块,然后调用本地应用的完成块。注意:如果手动调用-dismissModalViewController
,则不会触发完成块。
将任何错误报告或发送功能请求到GitHub问题。 Pull requests非常受欢迎。有关详细信息,请参阅CONTRIBUTING。
Apache 2.0许可证。有关详细信息,请参阅LICENSE文件。