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

如何用Objective-C实现用户靠近收藏餐厅时触发本地通知?

嘿,刚好做过类似的iOS区域监测+本地通知功能,给你整理了一套可以直接集成到项目里的Objective-C代码方案,分模块来,你直接跟着来就行:

核心思路

我们会用CoreLocation框架的**地理围栏(Region Monitoring)**来监测用户是否进入收藏餐厅的范围,再结合UserNotifications框架发送本地通知。需要先搞定权限申请,再配置区域监测,最后处理进入区域的回调发送通知。

第一步:配置Info.plist权限

首先得在Info.plist里添加必要的权限描述,否则会被系统拒:

  • 新增NSLocationAlwaysAndWhenInUseUsageDescription:填写类似“需要在后台监测你靠近收藏餐厅的位置,以便及时发送通知提醒”
  • 新增NSLocationWhenInUseUsageDescription:备用的前台权限说明,比如“需要获取你的位置来监测是否靠近收藏餐厅”
  • 新增NSNotificationAlertUsageDescription:通知权限说明,比如“当你靠近收藏餐厅时,我们会发送通知提醒你”
第二步:完整代码实现

你可以创建一个专门的LocationMonitoringManager类来管理这些逻辑,这样代码更清晰:

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <UserNotifications/UserNotifications.h>

@interface LocationMonitoringManager : NSObject <CLLocationManagerDelegate, UNUserNotificationCenterDelegate>
// 单例模式,方便全局调用
+ (instancetype)sharedManager;
// 添加收藏餐厅的地理围栏(传入你的餐厅数据数组)
- (void)addFavoriteRestaurantRegionsWithRestaurants:(NSArray *)restaurants;
@end

@implementation LocationMonitoringManager

@property (nonatomic, strong) CLLocationManager *locationManager;

+ (instancetype)sharedManager {
    static LocationMonitoringManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[LocationMonitoringManager alloc] init];
    });
    return manager;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
        _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        // 允许后台位置更新,确保后台也能监测区域
        _locationManager.allowsBackgroundLocationUpdates = YES;
        _locationManager.pausesLocationUpdatesAutomatically = NO;
        
        // 先申请通知权限
        [self requestNotificationAuthorization];
        // 申请位置权限
        [self requestLocationAuthorization];
    }
    return self;
}

#pragma mark - 权限申请
- (void)requestNotificationAuthorization {
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    center.delegate = self;
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (!granted) {
            NSLog(@"用户拒绝了通知权限,无法发送餐厅提醒");
        }
    }];
}

- (void)requestLocationAuthorization {
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
    if (status == kCLAuthorizationStatusNotDetermined) {
        // 必须申请Always权限,后台监测区域需要这个
        [self.locationManager requestAlwaysAuthorization];
    } else if (status == kCLAuthorizationStatusAuthorizedAlways) {
        // 已经有权限,直接添加区域
        // 这里可以根据你的需求,传入收藏餐厅数组
        // [self addFavoriteRestaurantRegionsWithRestaurants:yourFavoriteRestaurants];
    } else {
        NSLog(@"位置权限不足,无法使用区域监测功能");
    }
}

#pragma mark - 添加地理围栏
- (void)addFavoriteRestaurantRegionsWithRestaurants:(NSArray *)restaurants {
    // 先移除已有的监测区域,避免重复添加
    for (CLRegion *region in self.locationManager.monitoredRegions) {
        [self.locationManager stopMonitoringForRegion:region];
    }
    
    // 遍历收藏餐厅,添加对应的地理围栏
    for (NSDictionary *restaurant in restaurants) {
        // 假设你的餐厅数据结构是:name(餐厅名)、lat(纬度)、lon(经度)、radius(监测半径,推荐≥100米)
        NSString *restaurantName = restaurant[@"name"];
        CLLocationDegrees lat = [restaurant[@"lat"] doubleValue];
        CLLocationDegrees lon = [restaurant[@"lon"] doubleValue];
        CLLocationDistance radius = [restaurant[@"radius"] doubleValue];
        
        CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(lat, lon);
        CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:coordinate
                                                                      radius:radius
                                                                 identifier:restaurantName];
        // 只在进入区域时触发通知
        region.notifyOnEntry = YES;
        region.notifyOnExit = NO;
        
        [self.locationManager startMonitoringForRegion:region];
        NSLog(@"已添加餐厅监测:%@", restaurantName);
    }
}

#pragma mark - CLLocationManagerDelegate
// 用户进入监测区域时的回调
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    if ([region isKindOfClass:[CLCircularRegion class]]) {
        // 发送本地通知
        [self sendRestaurantNotificationWithName:region.identifier];
    }
}

// 权限状态变化时的回调
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    if (status == kCLAuthorizationStatusAuthorizedAlways) {
        // 权限通过后,可以在这里调用添加地理围栏的方法
        // 比如从本地缓存读取收藏餐厅,再调用addFavoriteRestaurantRegionsWithRestaurants:
    }
}

#pragma mark - 发送本地通知
- (void)sendRestaurantNotificationWithName:(NSString *)restaurantName {
    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    content.title = @"🎯 靠近收藏餐厅啦";
    content.body = [NSString stringWithFormat:@"你已经来到「%@」附近,快去打卡吧!", restaurantName];
    content.sound = [UNNotificationSound defaultSound];
    content.badge = @1; // 可选,设置角标
    
    // 立即发送通知
    UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.1 repeats:NO];
    NSString *requestID = [NSString stringWithFormat:@"restaurant_notify_%@", [NSDate dateWithTimeIntervalSinceNow:0]];
    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestID
                                                                          content:content
                                                                          trigger:trigger];
    
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
        if (error) {
            NSLog(@"发送通知失败:%@", error.localizedDescription);
        }
    }];
}

#pragma mark - UNUserNotificationCenterDelegate
// 前台收到通知时的处理(可选,让前台也显示通知)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBadge);
}

@end
第三步:使用方式

在你的AppDelegate或者需要的地方,这样调用:

// 假设你从服务器/本地获取到的收藏餐厅数组
NSArray *favoriteRestaurants = @[
    @{@"name": @"老上海面馆", @"lat": @31.2304, @"lon": @121.4737, @"radius": @150},
    @{@"name": @"粤式茶餐厅", @"lat": @31.2057, @"lon": @121.5919, @"radius": @120}
];

[[LocationMonitoringManager sharedManager] addFavoriteRestaurantRegionsWithRestaurants:favoriteRestaurants];
重要注意事项
  • 真实设备测试:模拟器的位置模拟对地理围栏支持不好,一定要用真机测试
  • 地理围栏数量限制:iOS每个App最多允许注册20个地理围栏,如果你的收藏餐厅超过20个,建议只监测用户当前位置附近的几个,或者动态替换
  • 半径设置:推荐半径≥100米,太小的话系统可能不会触发监测(因为GPS精度问题)
  • 重启设备后重新添加:iOS重启后,之前注册的地理围栏会被清除,所以要在App启动时重新调用添加方法
  • 后台权限:必须确保用户授予了「始终允许」的位置权限,否则后台无法监测区域进入事件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:42:25