11 changed files with 230 additions and 148 deletions
@ -0,0 +1,131 @@ |
|||||
|
import Foundation |
||||
|
import AMapLocationKit |
||||
|
|
||||
|
extension Notification.Name { |
||||
|
static let locationstartEvent = Notification.Name("locationstartEvent") //启动定位 |
||||
|
static let updatelocationEvent = Notification.Name("updatelocationEvent") //更新位置事件 |
||||
|
} |
||||
|
class LocationService: NSObject { |
||||
|
static let shared = LocationService() |
||||
|
private let TAG = "LocationService" |
||||
|
|
||||
|
private var locationManager: AMapLocationManager! |
||||
|
private var currentLocation: CLLocation? |
||||
|
private var currentReGeocode: AMapLocationReGeocode? |
||||
|
private var initialized = false |
||||
|
|
||||
|
private override init() { |
||||
|
super.init() |
||||
|
} |
||||
|
|
||||
|
// 初始化定位服务 |
||||
|
func initialize() { |
||||
|
if initialized { return } |
||||
|
print("\(TAG)--------- 初始化高德定位服务") |
||||
|
|
||||
|
locationManager = AMapLocationManager() |
||||
|
locationManager.delegate = self |
||||
|
|
||||
|
locationManager.desiredAccuracy = kCLLocationAccuracyBest // 定位精度 |
||||
|
locationManager.distanceFilter = 10.0 // 移动距离阈值(单位:米) |
||||
|
locationManager.locatingWithReGeocode = true // 是否返回逆地理编码信息 |
||||
|
locationManager.allowsBackgroundLocationUpdates = true // 是否允许后台定位 |
||||
|
locationManager.locationTimeout = 10 // 定位超时时间(秒) |
||||
|
locationManager.reGeocodeTimeout = 5 // 逆地理编码超时时间(秒) |
||||
|
|
||||
|
locationManager.startUpdatingLocation() |
||||
|
|
||||
|
initialized = true |
||||
|
} |
||||
|
|
||||
|
// 获取缓存的位置信息 |
||||
|
func getCachedLocation() -> [String: String]? { |
||||
|
guard let location = currentLocation else { return nil } |
||||
|
|
||||
|
var locationInfo: [String: String] = [ |
||||
|
"user_lat": "\(location.coordinate.latitude)", |
||||
|
"user_lng": "\(location.coordinate.longitude)" |
||||
|
] |
||||
|
|
||||
|
if let regeocode = currentReGeocode { |
||||
|
let address = [ |
||||
|
regeocode.province, // 省 |
||||
|
regeocode.city, // 市 |
||||
|
regeocode.district, // 区 |
||||
|
regeocode.street, // 街道 |
||||
|
regeocode.number // 门牌号 |
||||
|
].compactMap { $0 }.joined(separator: "") |
||||
|
|
||||
|
locationInfo["user_location"] = address |
||||
|
} |
||||
|
|
||||
|
return locationInfo |
||||
|
} |
||||
|
|
||||
|
// 获取当前位置(带回调) |
||||
|
func getCurrentLocation(completion: @escaping ([String: String]?, Error?) -> Void) { |
||||
|
if let cached = getCachedLocation() { |
||||
|
completion(cached, nil) |
||||
|
} else { |
||||
|
let error = NSError( |
||||
|
domain: "LocationService", |
||||
|
code: -1, |
||||
|
userInfo: [NSLocalizedDescriptionKey: "当前位置还未获取"] |
||||
|
) |
||||
|
completion(nil, error) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 停止定位服务 |
||||
|
func stop() { |
||||
|
locationManager.stopUpdatingLocation() |
||||
|
locationManager = nil |
||||
|
currentLocation = nil |
||||
|
currentReGeocode = nil |
||||
|
initialized = false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// MARK: - AMapLocationManagerDelegate |
||||
|
extension LocationService: AMapLocationManagerDelegate { |
||||
|
// 定位更新回调 |
||||
|
func amapLocationManager(_ manager: AMapLocationManager!, didUpdate location: CLLocation!, reGeocode: AMapLocationReGeocode!) { |
||||
|
currentLocation = location |
||||
|
currentReGeocode = reGeocode |
||||
|
|
||||
|
print("\(TAG)--------- 定位更新: \(location.coordinate.latitude), \(location.coordinate.longitude)") |
||||
|
|
||||
|
var locationInfo: [String: String] = [ |
||||
|
"user_lat": "\(location.coordinate.latitude)", |
||||
|
"user_lng": "\(location.coordinate.longitude)" |
||||
|
] |
||||
|
if let regeocode = currentReGeocode { |
||||
|
let address = [ |
||||
|
reGeocode.province, // 省 |
||||
|
reGeocode.city, // 市 |
||||
|
reGeocode.district, // 区 |
||||
|
reGeocode.street, // 街道 |
||||
|
reGeocode.number // 门牌号 |
||||
|
].compactMap { $0 }.joined(separator: "") |
||||
|
print("\(TAG)--------- 定位地址: \(address)") |
||||
|
locationInfo["user_location"] = address |
||||
|
} |
||||
|
|
||||
|
|
||||
|
NotificationCenter.default.post( |
||||
|
name: .updatelocationEvent, |
||||
|
object: nil, |
||||
|
userInfo: locationInfo |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
// 定位失败回调 |
||||
|
func amapLocationManager(_ manager: AMapLocationManager!, didFailWithError error: Error!) { |
||||
|
print("\(TAG)--------- 定位失败: \(error.localizedDescription)") |
||||
|
} |
||||
|
|
||||
|
// 权限变更回调 |
||||
|
func amapLocationManager(_ manager: AMapLocationManager!, doRequireLocationAuth locationManager: CLLocationManager!) { |
||||
|
locationManager.requestWhenInUseAuthorization() |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
import Flutter |
||||
|
import UIKit |
||||
|
import AMapLocationKit |
||||
|
|
||||
|
public class LocationServicePlugin: NSObject, FlutterPlugin { |
||||
|
private static var channel: FlutterMethodChannel? |
||||
|
|
||||
|
public static func register(with registrar: FlutterPluginRegistrar) { |
||||
|
let channel = FlutterMethodChannel(name: "com.yunqiinnovation.location_service", binaryMessenger: registrar.messenger()) |
||||
|
let instance = LocationServicePlugin() |
||||
|
// 必须先设置隐私合规 |
||||
|
DispatchQueue.main.async { |
||||
|
// 2. API Key |
||||
|
AMapServices.shared()?.apiKey = "aa60a03be9f6531bcc64029e60f95d03" |
||||
|
AMapServices.shared().enableHTTPS = true |
||||
|
// 3. 打印验证(调试用) |
||||
|
print("高德SDK初始化完成") |
||||
|
} |
||||
|
registrar.addMethodCallDelegate(instance, channel: channel) |
||||
|
self.channel = channel |
||||
|
instance.addstartlocationmonitor() |
||||
|
} |
||||
|
|
||||
|
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
switch call.method { |
||||
|
case "location": |
||||
|
result(nil) |
||||
|
default: |
||||
|
result(FlutterMethodNotImplemented) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private func addstartlocationmonitor(){ |
||||
|
// 通常放在启动后或模块初始化时 |
||||
|
NotificationCenter.default.addObserver( |
||||
|
forName: .locationstartEvent, |
||||
|
object: nil, |
||||
|
queue: .main |
||||
|
) { notification in |
||||
|
print("📥 收到 启动定位服务事件") |
||||
|
LocationService.shared.initialize() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,32 +0,0 @@ |
|||||
// swift-tools-version: 5.9 |
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package. |
|
||||
|
|
||||
import PackageDescription |
|
||||
|
|
||||
let package = Package( |
|
||||
name: "location_service", |
|
||||
platforms: [ |
|
||||
.iOS("12.0") |
|
||||
], |
|
||||
products: [ |
|
||||
.library(name: "location-service", targets: ["location_service"]) |
|
||||
], |
|
||||
dependencies: [], |
|
||||
targets: [ |
|
||||
.target( |
|
||||
name: "location_service", |
|
||||
dependencies: [], |
|
||||
resources: [ |
|
||||
// If your plugin requires a privacy manifest, for example if it uses any required |
|
||||
// reason APIs, update the PrivacyInfo.xcprivacy file to describe your plugin's |
|
||||
// privacy impact, and then uncomment these lines. For more information, see |
|
||||
// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files |
|
||||
// .process("PrivacyInfo.xcprivacy"), |
|
||||
|
|
||||
// If you have other resources that need to be bundled with your plugin, refer to |
|
||||
// the following instructions to add them: |
|
||||
// https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package |
|
||||
] |
|
||||
) |
|
||||
] |
|
||||
) |
|
||||
@ -1,19 +0,0 @@ |
|||||
import Flutter |
|
||||
import UIKit |
|
||||
|
|
||||
public class LocationServicePlugin: NSObject, FlutterPlugin { |
|
||||
public static func register(with registrar: FlutterPluginRegistrar) { |
|
||||
let channel = FlutterMethodChannel(name: "location_service", binaryMessenger: registrar.messenger()) |
|
||||
let instance = LocationServicePlugin() |
|
||||
registrar.addMethodCallDelegate(instance, channel: channel) |
|
||||
} |
|
||||
|
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
|
||||
switch call.method { |
|
||||
case "getPlatformVersion": |
|
||||
result("iOS " + UIDevice.current.systemVersion) |
|
||||
default: |
|
||||
result(FlutterMethodNotImplemented) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
|
||||
<plist version="1.0"> |
|
||||
<dict> |
|
||||
<key>NSPrivacyTrackingDomains</key> |
|
||||
<array/> |
|
||||
<key>NSPrivacyAccessedAPITypes</key> |
|
||||
<array/> |
|
||||
<key>NSPrivacyCollectedDataTypes</key> |
|
||||
<array/> |
|
||||
<key>NSPrivacyTracking</key> |
|
||||
<false/> |
|
||||
</dict> |
|
||||
</plist> |
|
||||
Loading…
Reference in new issue