2017-01-27 3 views
1

Я пытаюсь отправить пользователю локальное уведомление, когда регион введен (на некотором расстоянии), пока приложение закрыто. В настоящее время я работаю, если приложение находится в фоновом режиме, но не может заставить его работать, если приложение закрыто. Я читал другие сообщения, которые говорят, что это возможно, но ни одно из решений не работает, и они устарели. Я оценил бы некоторую помощь в Swift 3.iBeacon Notification Когда приложение закрыто

Вот мой код (все в AppDelegate):

В didFinishLaunchingWithOptions:

locationManager.delegate = self 
locationManager.pausesLocationUpdatesAutomatically = false 
locationManager.allowsBackgroundLocationUpdates = true    
locationManager.requestAlwaysAuthorization() 

let uuid = UUID(uuidString: "someuuid")! 
let beaconRegion = CLBeaconRegion(proximityUUID: uuid, identifier: "SomeBeacon") 
beaconRegion.notifyEntryStateOnDisplay = true 
beaconRegion.notifyOnEntry = true 
beaconRegion.notifyOnExit = true 
locationManager.startMonitoring(for: beaconRegion) 
locationManager.startRangingBeacons(in: beaconRegion) 

Я также didRangeBeacons реализованы.

+0

Можете ли вы показать свой код? Если он работает в фоновом режиме, неясно, почему он не будет работать с закрытым приложением. – davidgyoung

+0

Только что обновленный, был бы признателен за вашу помощь. – abcd123

ответ

2

Код выглядит правильно, чтобы разрешить обнаружение, когда приложение закрыто. Вам не понадобятся:

locationManager.pausesLocationUpdatesAutomatically = false 
locationManager.allowsBackgroundLocationUpdates = true 

Но они не должны ничего болеть.

Вы только упоминаете проблему с закрытым приложением, поэтому я предполагаю, что обнаружение переднего плана работает нормально. Имеет ли это? Если нет, сначала устраните это.

Часто бывает сложно правильно проверить закрытый прецедент приложения, приводящий к сбоям из-за проблем с настройкой теста. Несколько советов могут помочь:

  1. iOS отправит событие регистрации региона только в том случае, если оно считает, что оно вне региона. Часто в тестировании он считает, что он находится в регионе, поэтому вы не получаете события. Чтобы убедиться, что вы находитесь за пределами региона, выключите ваш маяк или выходите из диапазона с приложением на переднем плане и дождитесь, пока вы не получите обратный вызов выхода. Только тогда вы должны убить приложение, чтобы проверить закрытое обнаружение.

  2. Если вы перезагрузите свой телефон, всегда подождите 5 минут после запуска, чтобы убедиться, что CoreLocation полностью инициализирован. И убедитесь, что вы следовали правилу 1.

  3. Убедитесь, что на телефоне не установлено множество других приложений радиомаяка, на которых установлены все аппаратные ускорители для обнаружения Bluetooth. Если вы это сделаете, обнаружение в фоновом режиме может быть отложено до 15 минут. Удалите все приложения маяка, затем удалите и переустановите свои.

Если вы следуете советам выше, вы должны увидеть обратные вызовы обнаружения в течение нескольких секунд от маякового маяка поблизости.

0

UPDATE Как @davidgyoung указал мне на другой вопрос, этот метод использования UNLocationNotificationTrigger не будет сообщать о крупных и мелких идентификаторах к вам, потому что он использует API мониторинга и масштабирования, которое является то, что вы необходимо получить основные и второстепенные числа. Это ограничивает то, что вы можете сделать с этим API-интерфейсом. Конечно, это удобно, но не так полезно, как можно было бы надеяться.


Новые (IOS 10, Swift 3) путь от того, что я могу сказать, чтобы использовать UserNotifications библиотеки и реализовать его с UNNotificationRequest. Вы можете передать ему зону маяка через UNLocationNotificationTrigger. Теперь я знаю, что кажется интуитивно понятным для того, что вы хотите (уведомление, когда приложение закрыто), однако вы хотите добавить ключ NSLocationWhenInUseUsageDescription к Info.plist вместо NSLocationAlwaysUsageDescription.Я не уверен, почему так, но это необходимый шаг. Вот код, я использую для создания (IBeacon) местоположения уведомления на основе:

// Ensure you use a class variable in order to ensure the location 
// manager is retained, otherwise the alert message asking you to 
// authorize it will disappear before you can tap "allow" which 
// will keep it from working 
let locationManager = CLLocationManager() 

// ... 

// Somewhere in your class (e.g. AppDelegate or a ViewController) 
self.locationManager.requestWhenInUseAuthorization() 

let region = CLBeaconRegion(proximityUUID: UUID(uuidString: "YOUR-UNIQUE-UUID-STRING")!, identifier: "com.yourcompany.youridentifier") 
region.notifyOnEntry = true 
region.notifyOnExit = false 

let content = UNMutableNotificationContent() 
content.title = "Notification Title" 
content.body = "Body text goes here" 

// Not sure if repeats needs to be set to true here, but that's 
// how I've implemented it 
let trigger = UNLocationNotificationTrigger(region: region, repeats: true) 

// Use the same identifier each time to ensure it gets overwritten 
// in the notification system 
let identifier = "BeaconLocationIdentifier" 
let request = UNNotificationRequest.init(identifier: identifier, content: content, trigger: trigger) 

// This is probably unnecessary since we're using the same identifier 
// each time this code is called 
UNUserNotificationCenter.current().removeAllPendingNotificationRequests() 

// Make sure you set the notification center's delegate. My 
// containing class is the AppDelegate. I implement the delegate 
// methods there. 
UNUserNotificationCenter.current().delegate = self 
UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in 

}) 

// Not sure if this is required either, but after I added this, everything 
// started working 
self.locationManager.startRangingBeacons(in: region) 

Убедитесь, что вы реализуете методы делегата уведомления центра:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping() -> Void) { 
    // Called when the notification has been swiped or tapped by the user 

    // Do something with the response here 

    // Make sure you call the completion handler 
    completionHandler() 
} 

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { 
    // Called when the app is in the foreground 

    // Do something with the notification here 

    // Make sure you call the completion handler 
    completionHandler([.alert, .sound]) 
} 

Наконец, вы будете нуждаться в сначала авторизуйте уведомления, чтобы все это работало. Вы можете использовать этот код, чтобы сделать это:

let options: UNAuthorizationOptions = [.alert,.sound] 
UNUserNotificationCenter.current().requestAuthorization(options: options) { 
    (granted, error) in 
    if !granted { 
     debugPrint("Something went wrong") 
    } else { 
     debugPrint("Notifications granted") 

    } 
} 

Один последний совет: У меня есть старый металлическое олово, что (вроде) действует как клетка Фарадея для маяка я использую. Я просто закрываю свой маяк там минуту или около того, а затем приложение обнаруживает, что я вышел из диапазона. Это более удобно, чем пытаться пройти достаточно далеко от маяка или вытаскивать аккумулятор (который, кажется, не работает вообще для меня). Некоторые маяки имеют более сильные сигналы, чем другие, и могут все еще проходить через олово, поэтому YMMV.

Смежные вопросы