14 changed files with 346 additions and 151 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