【问题标题】:Show an alert when iOS app is in the background当 iOS 应用程序在后台时显示警报
【发布时间】:2016-08-08 18:17:25
【问题描述】:

我想在我的 iOS 应用处于后台时显示警报视图(并且它正在使用位置)。

例如,Uber 合作伙伴(司机)应用会显示警报并播放声音,即使在以下情况下:

  • 我已关闭通知!
  • 我的 iPhone 处于静音模式!

我知道本地通知方法,如果用户关闭/更改设置中的通知,它就不起作用。我正在寻找不同的东西。


为达到上述状态而执行的操作:

  • 在 Uber Partner App 上上网(您就是司机!)
  • 在“设置”中禁用应用通知
  • 将应用移至后台并等待乘车请求
  • 一段时间后,会以警报视图的形式弹出乘车请求,并在后台播放声音

当然,即使用户在“设置”中禁用了通知,应用程序也可以使用didReceiveRemoteNotification: fetchCompletionHandler: API 访问静默远程通知。但是,警报是如何弹出的,这就是我想要找出的。

【问题讨论】:

  • 我不是 100% 确定,但我相信 uber 应用程序被配置为“路由”iOS 应用程序,因此获得了一些额外的权限来在后台执行操作。您可以在此处找到更多信息:developer.apple.com/library/ios/documentation/IDEs/Conceptual/…。虽然我想象你实际上并不想创建一个路由应用程序?
  • 非常感谢@George George。我的意图是一样的:不惜一切代价显示警报。让我通过您提供的链接。至少我有一些线索。
  • 基本上,在 iOS 中,您不能只在应用程序处于后台时显示警报,除非用户选择接收通知。如果您提交的应用程序使用路由功能执行此操作并且不是路由应用程序,Apple 将在审核时拒绝它。
  • 是的,我正在制作类似于 Uber Partner 应用程序的东西。任何对我的问题投反对票的人,请告诉我原因。
  • @K.K.非常感谢。这很有趣。我现在非常好奇,我必须找出这里发生了什么。如果我设法找到一些东西并且同时你没有得到任何答案,我会(最终)回帖。

标签: ios uialertcontroller springboard


【解决方案1】:

在对二进制文件进行一些静态分析后,很明显他们没有使用 PKPushRegistry (VOIP)、未记录的 NSNotificationCenter 调用或 SBAlertItem。

花了一点时间才找到它,但他们实际上是使用 CFUserNotification 来发出警报的。对于 Mac,该类是 documented,但对于 iOS 是私有的。

我通过这样做找到了用法:

nm -u ~/Downloads/Payload/UberDriver.app/UberDriver | grep CFUserNotification

输出是:

_CFUserNotificationCancel
_CFUserNotificationCreate
_CFUserNotificationCreateRunLoopSource
_kCFUserNotificationAlertHeaderKey
_kCFUserNotificationAlertMessageKey
_kCFUserNotificationAlertTopMostKey
_kCFUserNotificationAlternateButtonTitleKey
_kCFUserNotificationDefaultButtonTitleKey
_kCFUserNotificationSoundURLKey

如果我对 PKPushRegistry 或 SBAlertItem 进行 grep,则两者均不返回任何结果。

可以通过将this file 导入您的项目来使用该类。

更新

我有“工作”代码,但是它立即调用回调函数(responseFlags 设置为kCFUserNotificationCancelResponse)而不显示警报..

我使用与 Uber 应用程序相同的键和调用(将下面的代码与上面列出的代码进行比较),所以一定有一些额外的东西。会继续寻找。

#import "CFUserNotification.h"

@interface AppDelegate ()
@property (nonatomic) CFRunLoopSourceRef runLoopSource;
@property (nonatomic) CFUserNotificationRef notification;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    SInt32 error;
    NSDictionary *keys = @{(__bridge NSString*)kCFUserNotificationAlertHeaderKey: @"Hello",
                           (__bridge NSString*)kCFUserNotificationAlertMessageKey: @"World",
                           (__bridge NSString*)kCFUserNotificationAlertTopMostKey: @YES,
                           (__bridge NSString*)kCFUserNotificationDefaultButtonTitleKey: @"asdf",
                           (__bridge NSString*)kCFUserNotificationAlternateButtonTitleKey: @"asdf",
                           };

    self.notification = CFUserNotificationCreate(NULL, 10, kCFUserNotificationPlainAlertLevel, &error, (__bridge CFDictionaryRef)keys);
    self.runLoopSource = CFUserNotificationCreateRunLoopSource(NULL, self.notification, NotificationCallback, 0);
    CFRunLoopAddSource(CFRunLoopGetMain(), self.runLoopSource, kCFRunLoopCommonModes);

    return YES;
}

void NotificationCallback(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) {
    NSLog(@"got response: %lu", responseFlags);
}

【讨论】:

  • @Casey 非常感谢您这样做。这真的会帮助很多人。
  • 啊,太酷了。我听说过CFUserNotification,但没想过要提及它。你是如何获得 UberDriver 二进制文件的?你是司机吗?
  • 不是驱动程序,所以 Cycript/theos 没有多大用处...通过谷歌找到它,在您的手机上打开此链接(或通过用户代理)partners.uber.com/drive-now
  • @Casey,如何像最初提出的问题一样显示警报?可以分享一下代码吗?
  • 有使用CFUserNotification API 的权利保护。优步很可能在其配置文件中获得了特殊权利许可。
【解决方案2】:

您的问题错过了关于“优步合作伙伴”应用程序的最重要部分,这将使事情变得更加清晰。 “优步合作伙伴”应用是一款企业应用,不受应用商店指南的限制。

它没有像其他答案建议的那样获得任何特殊权限。

无论声音\通知设置如何,都可以使用SBAlertItem 显示警报视图,但如果您的最终目标是进入应用商店,很遗憾,您的应用将因使用私有 API 而被拒绝。

【讨论】:

  • 只能企业应用使用 SBAlertItem 吗?私有 API 是什么意思?
  • 企业应用程序可以使用私有 API,所以答案是肯定的,您可以使用 SBAlertItem。部署企业应用程序时没有审核流程。 Private API 是一种不向公众开放的 API,Apple 也没有记录。您可以研究类标题以访问它,但就像我在回答中所说的那样,您的应用将被拒绝。
  • “它没有像其他答案建议的那样获得任何特殊权限。”你怎么能这么肯定? Apple 始终为选定的合作伙伴提供专有文档。您认为优步是否会挖掘标题并自己做到这一点?我对此表示怀疑:
  • 我确定,因为它是Enterprise app,您不需要权限即可执行任何操作。我已经部署了我的Enterprise apps 份额,并且没有审核流程,也没有“企业审核指南”。苹果代表有可能帮助 UBER 实现了他们所追求的目标,但这不是重点。
【解决方案3】:

我会想象 Uber 有一些特殊的权限或使用一些私有 API 允许他们在不使用本地通知的情况下实现此行为。虽然我不知道 Uber 是如何在他们的合作伙伴应用中实现这一点的,但我可以稍微谈谈警报在主屏幕上的工作原理。

SpringBoard 是管理 SpringBoard 应用程序 (SpringBoard.app) 的单例类,它是 iPhone 的应用程序启动器。 SpringBoard 不使用标准的 UIAlertView/UIAlertController 类,因为它们不参与 SpringBoard 范围的警报系统。 iOS 5 引入了SBAlertItem,用于在 SpringBoard 上显示 UIAlertViews(电池通知警报、Sim 解锁警报等)。 Apple 使用SBAlertItem 作为他们的锁定和主屏幕警报,我将假设 Uber 使用SBAlertItem 作为这个答案。

SBAlertItem 有一个受保护的 ivar UIAlertView *_alertSheet。假设这是一个普通的UIAlertView,您应该能够更改此警报的属性以满足您的需要。我还会通读 saurik 的 Cydia Substrate 项目,特别是 MobileSafety.mm 以查看一些用例。我还找到了noweibogoodsleep,它提供了在 SpringBoard 上使用 SBAlertItem 的示例。

我还找到了SBUserNotificationAlert,它是SBAlertItem 的子类。与标准的SBAlertItem 相比,这似乎有更多的方法来促进可能更适合您的需求的警报自定义。

我意识到挂钩私有 API 可能不是您在问这个问题时所期望的。由于我不知道 Uber 是如何工作的,我只能根据我使用运行时和越狱设备的个人经验提供答案。

【讨论】:

  • 感谢您的回答。我会尝试并很快接受它。抱歉回复晚了,最近忙于其他事情。如果它确实有效,那么你就是我们的救世主。 :)
猜你喜欢
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 2013-03-12
相关资源
最近更新 更多