iOS后台任务检测屏幕打开或关闭

时间:2015-07-26 09:12:29

标签: ios objective-c iphone screen background-service

我正在开发一个记录屏幕开/关事件的应用程序。这是一种智能手机使用分析应用程序。所有的应用程序都是写下这样的日志:

2015 July 25 at 03:54:12 PM - Screen on
2015 July 25 at 03:59:38 PM - Screen off
2015 July 25 at 04:20:52 PM - Screen on
2015 July 25 at 04:22:32 PM - Screen off
...
2015 July 26 at 10:20:32 AM - Screen on
2015 July 26 at 10:22:11 AM - Screen off
2015 July 26 at 11:30:38 AM - Screen on
2015 July 26 at 10:31:02 AM - Screen off
...
  • “屏幕开启”:用户按下主页按钮(或电源按钮)并输入密码/解锁密码(如果有)。
  • “屏幕关闭”:用户按电源按钮关闭屏幕。

我能够在Android上使用广播接收器找到一些方法来捕获系统发送的事件。但是在iOS中似乎存在问题,因为iOS只允许后台服务运行几分钟,我甚至不确定我是否可以在iOS上检测到“屏幕开/关”事件。

我做了一些关于这方面的研究并找到了一些文章,但那些文章并没多大帮助:

我的问题是“是否有可能在iOS中制作这样的应用程序(最新版本 - 8.4)?

感谢。

2 个答案:

答案 0 :(得分:2)

使用后台服务可能无法满足已发布的非监狱iOS设备的所有要求。我可以看到通知发生,我只是不确定背景。

由于其他人一直认为这是不可能的,所以我在这里深入挖掘一下,看看能做多少。

由于iOS目前仅限于少数背景模式(事件在后台传递的情况),或者在用户导航离开应用后几分钟内授予您应用的模式,因此问题是欺骗系统让你的应用程序在需要时在后台获得时间。

Programming Guide to Background Execution中描述了几种背景模式。例如,如果您可以定期发送推送通知以唤醒应用以下载内容",您可以定期获得一些时间,因为系统认为合适

后台Daemon是一种可能的解决方案,但仅供您自己使用,但不能通过App Store。官方对此的看法是在App Store Review Guidelines - 相关部分是2.8(可能是你通过让应用程序安装它来让你的守护进程开启&#34;在幕后&#34;):< / p>

  

2.8安装或启动其他可执行代码的应用程序将被拒绝

iOS可能存在一些系统日志;如果您可以访问这些内容,那么您就拥有了自己的数据。但是,我怀疑这可以通过非监狱破坏的手机以编程方式获得。

我能够测试一些Swift(2.0)代码,该代码使用了原始问题导致的Stack Overflow讨论之一中提到的Darwin Notifications:Lock / Unlock Events for iPhone。我实际上并没有在后台运行,但我确实确认事件是最终,即使应用程序在实际锁定事件发生时没有运行。当我的应用程序被切换时,通知被调用。因此,如果您能够从系统中获得时间,那么当Apple的算法决定给您时间时,您就会收到(延迟)通知。

允许收听的代码片段(我把它塞进一些随机应用程序)如下:

import UIKit
import CoreFoundation

class MainViewController: UIViewController, UIWebViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // CoreFoundation compatible types
        var cfstr: CFString = "com.apple.iokit.hid.displayStatus" as NSString
        var notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()

        CFNotificationCenterAddObserver(notificationCenter, nil,
            { (noti: CFNotificationCenter!, aPtr: UnsafeMutablePointer<Void>, aStr: CFString!, bPtr: UnsafePointer<Void>, aDict: CFDictionary!) -> () in
                print("got notification") }, cfstr, nil, CFNotificationSuspensionBehavior.DeliverImmediately)

    }
    // [... more stuff ...]
}

答案 1 :(得分:0)

如果您可以使用C或目标C代码,我想此代码可能会对您有所帮助。

///Fave model
class Fave(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_faves')
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    fave = models.BooleanField(default=True)

    def get_absolute_url(self):
        return reverse('contact:favorite')

///Contact model
class Contact(models.Model):
    COMPANY = 'C'
    PERSON = 'P'
    TYPE_CHOICES = (
        (COMPANY, 'Company'),
        (PERSON, 'Person'),
    )
    name = models.CharField(max_length=255, blank=True)
    type = models.CharField(max_length=1, blank=False, choices=TYPE_CHOICES) 
    country = models.CharField(max_length=128, blank=True)
    state = models.CharField(max_length=128, blank=True)
    city = models.CharField(max_length=128, blank=True)
    faves = GenericRelation(Fave, related_query_name='faves')
    notes = GenericRelation(Note, related_query_name='notes')

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('contact:contact_detail')


///CBV
class ContactListView(LoginRequiredMixin, ListView):
    """View list of companies"""
    model = Contact
    template_name = 'contact/contact_list'
    context_object_name = 'contacts'

    def get_context_data(self, **kwargs):
        """TODO faves """
        context = super().get_context_data(**kwargs)
        context['filter'] = ContactFilter(self.request.GET, queryset=self.get_queryset())

        return context

提供了您能够在后台模式下运行您的应用程序的功能。 状态将提供屏幕的关闭状态