You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于CMAltimeter实现海拔升降通知及起降检测技术问询

嘿,看起来你已经迈出了第一步,我来帮你把剩下的功能补全!针对用CMAltimeter实现海拔升降通知和起降状态检测,咱们一步步来:

1. 先修正现有代码的小问题

你在altimeter getter方法里重复创建了新的CMAltimeter实例,这会导致之前初始化的_altimeter被覆盖,改成这样更合理:

- (CMAltimeter *)altimeter {
    if (!_altimeter) {
        _altimeter = [[CMAltimeter alloc] init];
    }
    return _altimeter;
}
2. 完善海拔更新回调,实现升降通知

首先需要记录历史海拔值,用来对比判断升降趋势。先添加两个实例变量:

@property (nonatomic, strong) NSNumber *lastRelativeAltitude;
@property (nonatomic, assign) CGFloat altitudeChangeThreshold; // 避免微小波动触发通知,比如设为0.5米

然后补全startRelativeAltitudeUpdatesToQueue的回调逻辑:

- (void)startAltitudeMonitoring {
    if (![CMAltimeter isRelativeAltitudeAvailable]) {
        NSLog(@"当前设备不支持海拔检测");
        return;
    }
    
    self.altitudeChangeThreshold = 0.5;
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    [self.altimeter startRelativeAltitudeUpdatesToQueue:queue withHandler:^(CMAltitudeData * _Nullable altitudeData, NSError * _Nullable error) {
        if (error) {
            NSLog(@"海拔更新失败: %@", error.localizedDescription);
            return;
        }
        
        NSNumber *currentAlt = altitudeData.relativeAltitude;
        if (!self.lastRelativeAltitude) {
            // 第一次获取数据,初始化历史值
            self.lastRelativeAltitude = currentAlt;
            return;
        }
        
        // 计算海拔差值
        CGFloat diff = [currentAlt floatValue] - [self.lastRelativeAltitude floatValue];
        
        if (diff > self.altitudeChangeThreshold) {
            // 海拔上升,触发通知
            [self sendAltitudeNotificationWithType:@"上升"];
        } else if (diff < -self.altitudeChangeThreshold) {
            // 海拔下降,触发通知
            [self sendAltitudeNotificationWithType:@"下降"];
        }
        
        // 更新历史海拔值
        self.lastRelativeAltitude = currentAlt;
    }];
}
3. 实现通知发送逻辑

这里用iOS的本地通知框架UNUserNotificationCenter来发送通知,记得先申请权限:

- (void)sendAltitudeNotificationWithType:(NSString *)changeType {
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    
    // 申请通知权限
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (!granted || error) {
            NSLog(@"通知权限获取失败: %@", error?.localizedDescription);
            return;
        }
        
        // 构建通知内容
        UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
        content.title = [NSString stringWithFormat:@"海拔%@", changeType];
        content.body = [NSString stringWithFormat:@"当前海拔发生%@变化", changeType];
        content.sound = [UNNotificationSound defaultSound];
        
        // 创建通知请求
        UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[NSString stringWithFormat:@"altitude_%@", changeType]
                                                                              content:content
                                                                              trigger:nil];
        
        // 发送通知
        [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
            if (error) {
                NSLog(@"发送通知失败: %@", error.localizedDescription);
            }
        }];
    }];
}
4. 起降状态检测逻辑

起降是持续的海拔趋势变化,我们可以通过记录一段时间内的海拔数据来判断:
先添加历史数据存储的变量:

@property (nonatomic, strong) NSMutableArray *altitudeHistory;
@property (nonatomic, assign) NSInteger maxHistoryCount; // 比如存最近15条数据

初始化并在回调里补充趋势判断:

// 在startAltitudeMonitoring里初始化
self.altitudeHistory = [[NSMutableArray alloc] init];
self.maxHistoryCount = 15;

// 把这段代码加到海拔更新的回调里(在更新lastRelativeAltitude之前)
[self.altitudeHistory addObject:currentAlt];
if (self.altitudeHistory.count > self.maxHistoryCount) {
    [self.altitudeHistory removeObjectAtIndex:0];
}

// 当历史数据足够时判断趋势
if (self.altitudeHistory.count == self.maxHistoryCount) {
    CGFloat totalDiff = 0;
    for (NSInteger i = 1; i < self.maxHistoryCount; i++) {
        CGFloat prev = [self.altitudeHistory[i-1] floatValue];
        CGFloat curr = [self.altitudeHistory[i] floatValue];
        totalDiff += (curr - prev);
    }
    
    // 设定阈值:比如总变化大于8米判断为起飞,小于-8米判断为降落
    if (totalDiff > 8.0) {
        [self sendAltitudeNotificationWithType:@"起飞"];
        NSLog(@"检测到起飞状态");
    } else if (totalDiff < -8.0) {
        [self sendAltitudeNotificationWithType:@"降落"];
        NSLog(@"检测到降落状态");
    }
}
5. 收尾注意事项
  • 权限配置:一定要在Info.plist中添加NSMotionUsageDescription键,填写使用运动数据的原因(比如"需要检测海拔变化以提供相关通知"),否则会触发权限错误。
  • 资源释放:当不需要监测时,调用[self.altimeter stopRelativeAltitudeUpdates];停止更新,避免不必要的耗电。
  • 硬件兼容:虽然代码里判断了isRelativeAltitudeAvailable,但还是要给不支持的设备显示友好提示。

内容的提问来源于stack exchange,提问作者pilou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:11:24