CoreLocation框架详细解析(十九) —— 基于UNLo

2021-05-08  本文已影响0人  刀客传奇

版本记录

版本号 时间
V1.0 2021.05.08 星期六

前言

很多的app都有定位功能,比如说滴滴,美团等,他们都需要获取客户所在的位置,并且根据位置推送不同的模块数据以及服务,可以说,定位方便了我们的生活,接下来这几篇我们就说一下定位框架CoreLocation。感兴趣的可以看我写的上面几篇。
1. CoreLocation框架详细解析 —— 基本概览(一)
2. CoreLocation框架详细解析 —— 选择定位服务的授权级别(二)
3. CoreLocation框架详细解析 —— 确定定位服务的可用性(三)
4. CoreLocation框架详细解析 —— 获取用户位置(四)
5. CoreLocation框架详细解析 —— 监控用户与地理区域的距离(五)
6. CoreLocation框架详细解析 —— 确定接近iBeacon(六)
7. CoreLocation框架详细解析 —— 将iOS设备转换为iBeacon(七)
8. CoreLocation框架详细解析 —— 获取指向和路线信息(八)
9. CoreLocation框架详细解析 —— 在坐标和用户友好的地名之间转换(九)
10. CoreLocation框架详细解析(十) —— 跟踪访问位置简单示例(一)
11. CoreLocation框架详细解析(十一) —— 跟踪访问位置简单示例(二)
12. CoreLocation框架详细解析(十二) —— 仿Runkeeper的简单实现(一)
13. CoreLocation框架详细解析(十三) —— 仿Runkeeper的简单实现(二)
14. CoreLocation框架详细解析(十四) —— 仿Runkeeper的简单实现(三)
15. CoreLocation框架详细解析(十五) —— 仿Runkeeper的简单实现(四)
16. CoreLocation框架详细解析(十六) —— 基于Core Location地理围栏的实现(一)
17. CoreLocation框架详细解析(十七) —— 基于Core Location地理围栏的实现(二)
18. CoreLocation框架详细解析(十八) —— 基于UNLocationNotificationTrigger的位置通知(一)

源码

1. Swift

首先看下工程组织结构

下面就是源码了

1. AppMain.swift
import SwiftUI

@main
struct AppMain: App {
  @StateObject private var locationManager = LocationManager()

  var body: some Scene {
    WindowGroup {
      ContentView()
        .environmentObject(locationManager)
    }
  }
}
2. ContentView.swift
import SwiftUI

struct ContentView: View {
  let takeOut = TakeOutStore()
  @EnvironmentObject private var locationManager: LocationManager

  var body: some View {
    NavigationView {
      MenuListView(takeOut: takeOut)
    }
    .navigationViewStyle(StackNavigationViewStyle())
    .alert(isPresented: $locationManager.didArriveAtTakeout) {
      Alert(
        title: Text("Check In"),
        message:
          Text("""
            You have arrived to collect your order.
            Do you want to check in?
            """),
        primaryButton: .default(Text("Yes")),
        secondaryButton: .default(Text("No"))
      )
    }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
3. MenuListView.swift
import SwiftUI

struct MenuListView: View {
  var takeOut: TakeOutStore
  var menuItems: [MenuItem] {
    return takeOut.menu
  }

  var body: some View {
    List(menuItems, id: \.id) { item in
      NavigationLink(
        destination: DetailView(menuItem: item)) {
        MenuListRow(menuItem: item)
      }
    }
    .navigationTitle(takeOut.title)
  }
}

struct MenuListView_Previews: PreviewProvider {
  static var previews: some View {
    MenuListView(takeOut: TakeOutStore())
  }
}
4. MenuListRow.swift
import SwiftUI

struct MenuListRow: View {
  var menuItem: MenuItem

  var body: some View {
    HStack {
      Image(menuItem.imageName)
        .resizable()
        .frame(width: 50, height: 50)
      Text(menuItem.name)

      Spacer()
    }
  }
}

struct MenuListRow_Previews: PreviewProvider {
  static var previews: some View {
    MenuListRow(menuItem: menuItems[0])
      .previewLayout(.fixed(width: 300, height: 50))
  }
}
5. DetailView.swift
import SwiftUI

struct DetailView: View {
  @EnvironmentObject private var locationManager: LocationManager
  @State private var orderPlaced = false
  let menuItem: MenuItem
  var price: String {
    return "$" + String(format: "%.2f", menuItem.price)
  }

  var body: some View {
    VStack {
      Image(menuItem.imageName)
        .resizable()
        .frame(maxWidth: 300, maxHeight: 600)
        .aspectRatio(contentMode: .fit)
      Text(menuItem.name)
        .font(.headline)
      Divider()
      Text("Price: \(price)")
        .font(.subheadline)
        .padding(15)
      Button(action: placeOrder) {
        Text("Place Order: \(price)")
          .foregroundColor(.white)
          .frame(minWidth: 100, maxWidth: .infinity)
          .frame(height: 45)
      }
      .background(Color("rw-green"))
      .cornerRadius(3.0)
    }
    .alert(isPresented: $orderPlaced) {
      Alert(
        title: Text("Food Ordered"),
        message:
          Text("""
            Your food has been ordered.
            Would you like to be notified on arrival?
            """),
        primaryButton: .default(Text("Yes")) {
          requestNotification()
        },
        secondaryButton: .default(Text("No"))
      )
    }
    .padding()
    .navigationBarTitle(Text(menuItem.name), displayMode: .inline)
  }

  func placeOrder() {
    orderPlaced = true
  }

  func requestNotification() {
    locationManager.validateLocationAuthorizationStatus()
  }
}

struct DetailView_Previews: PreviewProvider {
  static var previews: some View {
    DetailView(menuItem: menuItems[0])
  }
}
6. SimulatedLocations.gpx
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode">
  <wpt lat="37.422155" lon="-122.134751">
    <name>Apple Park</name>
    <time>2021-01-23T14:00:00Z</time>
  </wpt>
  <wpt lat="37.33182000" lon="-122.03118000">
    <name>Apple Campus</name>
    <time>2021-01-23T14:00:05Z</time>
  </wpt>
</gpx>
7. LocationManager.swift
import CoreLocation
import UserNotifications

class LocationManager: NSObject, ObservableObject {
  let location = CLLocationCoordinate2D(latitude: 37.33182, longitude: -122.03118)
  let notificationCenter = UNUserNotificationCenter.current()
  lazy var storeRegion = makeStoreRegion()
  @Published var didArriveAtTakeout = false
  // 1
  lazy var locationManager = makeLocationManager()
  // 2
  private func makeLocationManager() -> CLLocationManager {
    // 3
    let manager = CLLocationManager()
    manager.allowsBackgroundLocationUpdates = true
    // 4
    return manager
  }

  // 1
  private func makeStoreRegion() -> CLCircularRegion {
    // 2
    let region = CLCircularRegion(
      center: location,
      radius: 2,
      identifier: UUID().uuidString)
    // 3
    region.notifyOnEntry = true
    // 4
    return region
  }

  // 1
  func validateLocationAuthorizationStatus() {
    // 2
    switch locationManager.authorizationStatus {
    // 3
    case .notDetermined, .denied, .restricted:
      // 4
      print("Location Services Not Authorized")
      locationManager.requestWhenInUseAuthorization()
      requestNotificationAuthorization()

    // 5
    case .authorizedWhenInUse, .authorizedAlways:
      // 6
      print("Location Services Authorized")
      requestNotificationAuthorization()

    default:
      break
    }
  }

  // 1
  private func requestNotificationAuthorization() {
    // 2
    let options: UNAuthorizationOptions = [.sound, .alert]
    // 3
    notificationCenter
      .requestAuthorization(options: options) { [weak self] result, _ in
        // 4
        print("Auth Request result: \(result)")
        if result {
          self?.registerNotification()
        }
      }
  }

  // 1
  private func registerNotification() {
    // 2
    let notificationContent = UNMutableNotificationContent()
    notificationContent.title = "Welcome to Swifty TakeOut"
    notificationContent.body = "Your order will be ready shortly."
    notificationContent.sound = .default

    // 3
    let trigger = UNLocationNotificationTrigger(region: storeRegion, repeats: false)

    // 4
    let request = UNNotificationRequest(
      identifier: UUID().uuidString,
      content: notificationContent,
      trigger: trigger)

    // 5
    notificationCenter
      .add(request) { error in
        if error != nil {
          print("Error: \(String(describing: error))")
        }
      }
  }

  // 1
  override init() {
    super.init()
    // 2
    notificationCenter.delegate = self
  }
}
extension LocationManager: UNUserNotificationCenterDelegate {
  // 1
  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
  ) {
    // 2
    print("Received Notification")
    didArriveAtTakeout = true
    // 3
    completionHandler()
  }

  // 4
  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    willPresent notification: UNNotification,
    withCompletionHandler completionHandler:
      @escaping (UNNotificationPresentationOptions) -> Void
  ) {
    // 5
    print("Received Notification in Foreground")
    didArriveAtTakeout = true
    // 6
    completionHandler(.sound)
  }
}
8. TakeOutStore.swift
import Foundation

struct TakeOutStore {
  let menu = menuItems
  var title = "Swifty TakeOut"
}
9. MenuItem.swift
import Foundation

struct MenuItem {
  let id = UUID()
  var name: String
  var imageName: String
  var price: Double
}

// MARK: - Menu Items
let menuItems: [MenuItem] = [
  MenuItem(name: "Margherita Pizza SE", imageName: "cheese-pizza-small", price: 7.00),
  MenuItem(name: "Margherita Pizza Max", imageName: "cheese-pizza", price: 10.00),
  MenuItem(name: "Margherita Pizza Max Pro", imageName: "cheese-pizza", price: 12.00),
  MenuItem(name: "Chicken Pizza SE", imageName: "chicken-pizza-small", price: 8.00),
  MenuItem(name: "Chicken Pizza Max", imageName: "chicken-pizza", price: 11.00),
  MenuItem(name: "Chicken Pizza Max Pro", imageName: "chicken-pizza", price: 14.00),
  MenuItem(name: "Pepperoni Pizza SE", imageName: "pep-pizza-small", price: 7.00),
  MenuItem(name: "Pepperoni Pizza Max", imageName: "pep-pizza", price: 11.00),
  MenuItem(name: "Pepperoni Pizza Max Pro", imageName: "pep-pizza", price: 14.00),
  MenuItem(name: "Swifty Shake Series 6", imageName: "shake", price: 3.50),
  MenuItem(name: "Swifty Shake SE", imageName: "shake", price: 2.00),
  MenuItem(name: "Swifty Shake Series 3", imageName: "shake", price: 2.75)
]

后记

本篇主要讲述了基于UNLocationNotificationTrigger的位置通知,感兴趣的给个赞或者关注~~~

上一篇下一篇

猜你喜欢

热点阅读