检测iOS手机端时间准确性方法

某些情况下,你的App的运行依赖于手机的系统时间, 或者对系统时间的准确性有要求.然而, 用户是可以任意修改系统时间的,当手机端的系统时间不准确时, 会影响你app的部分功能, 或者你希望在某种情况下检查手机系统时间的准确性. 我最近做的某项目, 依赖于系统时间的准确性, 希望通过某种方法来校验本地时间是否准确.此文分享我使用的办法.

一、思路介绍

原理:通过获取服务端的时间, 来跟手机系统时间进行对比, 来检查本地时间的准确性.

问题进一步转化为:如何方便和相对准确的, 随时获取服务端时间?

(默认服务端时间是准确的, 或者你选择时间准确的服务器来获取时间)

二、实现方法

2.1 如何获取服务器时间?

向被认为时间准确的可信服务器发送请求, 取response中的Date字段作为服务端当前的时间.

Date =     (
        "Thu, 01 Jun 2023 07:10:40 GMT"
    );

2.2 请求如何选取?

可以专门发送一个请求来获取服务端时间, 也可以利用现有app中的任意请求;我选择后者.

从现有app请求中选择一个符合你要求的请求;可以通过domain,path等来过滤请求, 还可以过滤响应时间等.

iOS10.0及以后版本,监听下面delegate方法, 获取metrics, 里面记录了请求操作的各个阶段时间.可以用来估算服务器之于本地相对准确的时间.具体可以根据自己对时间精度的要求进行计算.(metrics也包含response数据, 可以获取response的Date字段)

/*
 * Sent when complete statistics information has been collected for the task.
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

2.3 如何便利且高效的实时获取服务端时间?

首先, 根据2.2中的方法记录相较本地时间误差最小的服务端时间serverTime, 同时记录本地iOS开机时间systemTime; (开机时间[NSProcessInfo processInfo].systemUptime)

其次, 计算任意时间的服务端时间的方法:
比如当前系统开机时间currentSystemTime, 则当前服务端时间为:

currentServerTime = serverTime + (currentSystemTime-systemTime)

此处做个修正

苹果API "[NSProcessInfo processInfo].systemUptime"在统计开机时长时存在漏洞,

当手机锁屏, 且手机电源线断开时, 此API不会统计息屏时间.(深度休眠不会被记录到开机时长)

如果所在的应用程序开启了保活功能, 比如导航, 定位等功能, 会对休眠有影响(此时比较难发现此问题), 但是时间拉长到1小时以上, 还是会发现此API统计的开机时长变短;

可以替换为内核方法可解决此问题:

方法1:

    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    
    struct timeval now;
    struct timezone tz;
    gettimeofday(&now, &tz);
    
    double uptime = -1;
    
    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
    {
        uptime = now.tv_sec - boottime.tv_sec;
        uptime += (double)(now.tv_usec - boottime.tv_usec) / 1000000.0;
    }
    
    return uptime;

方法2:

    if (@available(iOS 10.0, *)) {
        struct timespec timespec;
        int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timespec);
        if (!status) {
            assert(!status);
        }
        
        return timespec.tv_sec + (double)timespec.tv_nsec / NSEC_PER_SEC;
    } else {
//        timespec->tv_sec = 0;
//        timespec->tv_nsec = 0;
    }

2.4 如何减少代码侵入

<1>在网络delegate中发通知,

<2>在单独的时间检查模块比如systemTimeChecker封装类处理时间校验逻辑.

<3>添加监听这个通知, 然后根据条件筛选适合的app内现有的网络请求, 捕获系统时间并记录开机时间. (可以在+load类方法里添加通知)

<4>捕获服务端时间后, 移除通知;

然后根据上述方法计算任意时间点的服务器时间, 对外只需要提供"检查系统时间是否被修改"的一个接口即可.

实现代码最简洁,且,无任何侵入.

完毕.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值