Я разрабатываю собственный веб-браузер, чтобы веб-приложение взаимодействовало с основными функциями (bluetooth, location, micro ...) в Swift.Нативное приложение содержит WKWebview для отображения содержимого веб-приложения, JS связывается через window.webkit.messageHandlers с WKWebview.
Существует функция, при которой веб-приложение запрашивает собственное приложение для получения местоположения пользователя при изменении положения, даже в фоновом режиме.Чтобы упростить процесс, я использую CoreLocation, чтобы получить местоположение и отправить его обратно в WKWebview.Веб-приложение прослушивает эти события через оконные прослушиватели и вызывает сервер, чтобы сохранить местоположение.
Это хорошо работает в симуляторе, но по некоторым причинам, о которых я не знаю, это не работает на реальном iPhone.
Вопросы:
- Может ли это быть связано с жизненным циклом WKWebview?
- Корректна ли конфигурация диспетчера местоположений, чтобы не быть уничтоженным / приостановленным ОС в фоновом состоянии?
- Может ли другое приложение получить приоритет при поиске местоположения и остановить мое приложение, имеющее информацию?
Любые советы приветствуются
Служба веб-приложений:
this.eventManager.addEventListener(window, 'sendLocalisation', (params : CustomEvent) => {
let data = params.detail.data;
let datas = { 'annotations' : data }
this.sendLocalisation(datas).subscribe( (ans : any ) => {
...
});
window.webkit.messageHandlers.JSLocalisation.postMessage("start");
Собственный быстрый код:
// Variables
private var localisationManager : LocalisationManager!
extension JSEventManager : WKScriptMessageHandler {
open func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "JSLocalisation" {
self.handleLocalisationEvents(message: message.body as! String)
}
}
func handleLocalisationEvents(message : String) {
if message == "start" {
localisationManager.startLocalisation()
}
}
class LocalisationManager : NSObject {
// Delegation
weak var delegate : LocalisationManagerDelegate?
// Variables
private var locationManager : CLLocationManager!
private var positions : [[String: Any]] = []
override init() {
super.init()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.activityType = .other
locationManager.pausesLocationUpdatesAutomatically = false
}
func startLocalisation() {
delegate?.didStartLocalisation()
locationManager.requestAlwaysAuthorization()
}
}
extension LocalisationManager : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if CLLocationManager.authorizationStatus() == .authorizedAlways {
startReceivingLocationChanges()
}
}
func startReceivingLocationChanges() {
let authorizationStatus = CLLocationManager.authorizationStatus()
if authorizationStatus != .authorizedWhenInUse && authorizationStatus != .authorizedAlways {
// User has not authorized access to location information.
return
}
// Do not start services that aren't available.
if !CLLocationManager.locationServicesEnabled() {
// Location services is not available.
return
}
// If the user confirms always authorization
if authorizationStatus == .authorizedAlways {
locationManager.allowsBackgroundLocationUpdates = true
}
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.distanceFilter = 40.0 // In meters.
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let timestamp = String(format:"%f", location.timestamp.timeIntervalSince1970*1000)
let longitude = "\(location.coordinate.longitude)"
let latitude = "\(location.coordinate.latitude)"
let position : [String: Any] = ["timestamp" : timestamp, "lon" : longitude, "lat" : latitude, "timezone" : 0 ]
self.positions.append(position)
if self.positions.count == 3 {
sendCoordinates()
}
}
func sendCoordinates(){
let locationsToSend = self.positions
self.positions = []
if let stringToSend = json(from:locationsToSend as Any) {
self.delegate?.shouldSendCoordinates(coordinates: stringToSend)
}
}
func json(from object:Any) -> String? {
guard let data = try? JSONSerialization.data(withJSONObject: object, options: []) else {
return nil
}
return String(data: data, encoding: String.Encoding.utf8)
}
}
// shouldSendCoordinates call this function, shortcut not to display all the delegates trough the app
func sendLocalisation(localisation: String) {
let str = "window.iOSLocalisationAPI.sendPositions('\(localisation)')"
self.evaluateJavaScript(str) { (result, error) in
guard error == nil else {
print(error)
return
}
}
}
Внедренный скрипт в webwiew:
(function () {
"use strict";
let geonative = {
sendPositions : function(positions) {
var evt = new CustomEvent('sendLocalisation', { detail: { data : positions } });
window.dispatchEvent(evt);
}
}
window.iOSLocalisationAPI = geonative;
}());