检索最后一个已知的地理位置 - Phonegap

Posted

技术标签:

【中文标题】检索最后一个已知的地理位置 - Phonegap【英文标题】:Retrieving last known geolocation - Phonegap 【发布时间】:2012-06-05 12:12:08 【问题描述】:

以下代码

navigator.geolocation.getCurrentPosition(getGeo_Success, getGeo_Fail, 
    enableHighAccuracy : true,
    maximumAge : Infinity,
    timeout : 15000
);

获取当前 GPS 位置 - 但是 - 必须有有效的 GPS 信号(当然,设备的 GPS 功能应该打开)。

如果我们查看其他应用程序(例如,android 设备上的地图) - 它知道如何检索 最后已知 位置 - 即使我没有使用更新地理位置的应用程序 在打开地图之前 - 它会在地图上显示我的位置,即使我在完全没有 GPS 信号的建筑物内。

澄清一下:我对我的应用程序检索到的最后一个地理位置不感兴趣,因为下次我将启动它时,该地理位置可能无关紧要。

问题是:我们如何使用 html5/Phonegap 实现这一点?似乎navigator.geolocation 只知道检索当前位置,即使maximumAge 设置为Infinity (这意味着,最后缓存位置的年龄无关,所以任何命中都可以(或者,应该是! ))

【问题讨论】:

【参考方案1】:

ANDROID 解决方案(iPhone 解决方案如下):

这很整洁:

我使用了 Android 的原生 LocationManager,它提供了一个 getLastKnownLocation 函数 - 名字就说明了一切

这是相关代码

1) 将以下 java 类添加到您的应用程序中

package your.package.app.app;

import org.apache.cordova.DroidGap;

import android.content.Context;
import android.location.*;
import android.os.Bundle;
import android.webkit.WebView;

public class GetNativeLocation implements LocationListener 
    private WebView mAppView;
    private DroidGap mGap;
    private Location mostRecentLocation;

    public GetNativeLocation(DroidGap gap, WebView view) 
        mAppView = view;
        mGap = gap;
    

    public void onLocationChanged(Location location) 
        // TODO Auto-generated method stub
        getLocation();
    

    public void getLocation() 
        LocationManager lm = 
                        (LocationManager)mGap.
                                        getSystemService(Context.LOCATION_SERVICE);
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        String provider = lm.getBestProvider(criteria, true);

        lm.requestLocationUpdates(provider, 1000, 500, this);
        mostRecentLocation = lm
                .getLastKnownLocation(LocationManager.GPS_PROVIDER);
    

    public void doInit()
        getLocation();
    

    public double getLat() return mostRecentLocation.getLatitude();
    public double getLong()  return mostRecentLocation.getLongitude(); 
    public void onProviderDisabled(String arg0) 
        // TODO Auto-generated method stub  
    

    public void onProviderEnabled(String provider) 
        // TODO Auto-generated method stub  
    

    public void onStatusChanged(String provider, int status, Bundle extras) 
        // TODO Auto-generated method stub
    

2) 确保您的主类如下所示:

public class App extends DroidGap 

    // Hold a private member of the class that calls LocationManager
    private GetNativeLocation gLocation;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        // This line is important, as System Services are not available
        // prior to initialization
        super.init();

        gLocation = new GetNativeLocation(this, appView);

        // Add the interface so we can invoke the java functions from our .js 
        appView.addjavascriptInterface(gLocation, "NativeLocation");

        try 
            super.loadUrl("file:///android_asset/www/index.html");
         catch (Exception e) 
            // TODO: handle exception
            e.printStackTrace();
        
    

    @Override
    public void onDestroy() 
        // TODO Auto-generated method stub
        super.onDestroy();
    

    @Override
    protected void onStop() 
        // TODO Auto-generated method stub
        super.onStop();
    

3) 在您的 JS 代码上,只需使用以下命令调用本机 java:

window.NativeLocation.doInit();
alert(window.NativeLocation.getLat());
alert(window.NativeLocation.getLong());

这就是所有人! :-)

编辑: iPhone 解决方案:

我编写了一个小型 Phonegap 插件,它创建了一个自定义类的接口,该类使用 ios 的原生 CLLocationManager

1) Phonegap 插件 (JS)

var NativeLocation = 
    doInit: function(types, success, fail) 
        return Cordova.exec(success, fail, "NativeLocation", "doInit", types);
    ,

    getLongitude: function(types, success, fail)
        return Cordova.exec(success, fail, "NativeLocation", "getLongitude", types);
    ,

    getLatitude: function(types, success, fail)
        return Cordova.exec(success, fail, "NativeLocation", "getLatitude", types);
    

2) 使我们能够调用'CCLocationManager's 函数的objective-c 类 *NativeLocation.h*

#import <Foundation/Foundation.h>
#import <Cordova/CDVPlugin.h>
#import <CoreLocation/CoreLocation.h>

@protocol NativeLocationDelegate
@required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;

@end

@interface NativeLocation : CDVPlugin <CLLocationManagerDelegate> 
    id delegate;
    NSString* callbackID;
    CLLocationManager *lm;
    Boolean bEnabled;
    double nLat;
    double nLon;


@property (nonatomic, copy) NSString* callbackID;
@property (nonatomic, retain) CLLocationManager *lm;
@property (nonatomic, readonly) Boolean bEnabled;
@property (nonatomic, assign) id delegate;

- (void) doInit:(NSMutableArray*)arguments
                                 withDict:(NSMutableDictionary*)options;
- (void) getLatitude:(NSMutableArray*)arguments 
                                 withDict:(NSMutableDictionary *)options;
- (void) getLongitude:(NSMutableArray*)arguments 
                                 withDict:(NSMutableDictionary *)options;

@end

NativeLocation.m

#import "NativeLocation.h"

@implementation NativeLocation

@synthesize callbackID;
@synthesize lm;
@synthesize bEnabled;
@synthesize delegate;

- (void)doInit:(NSMutableArray *)arguments 
                                 withDict:(NSMutableDictionary *)options
    if (self != nil)
        self.lm = [[[CLLocationManager alloc] init] autorelease];
        self.lm.delegate = self;
        if (self.lm.locationServicesEnabled == NO)
            bEnabled = FALSE;
        else bEnabled = TRUE;
    

    nLat = 0.0;
    nLon = 0.0;

    if (bEnabled == TRUE)
        [self.lm startUpdatingLocation];

    CDVPluginResult* pluginResult = [CDVPluginResult 
                                    resultWithStatus:CDVCommandStatus_OK 
                                    messageAsString[@"OK"
                                    stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

    if (bEnabled == TRUE)
        [self writeJavascript: [pluginResult 
                               toSuccessCallbackString:self.callbackID]];
     else 
        [self writeJavascript: [pluginResult 
                               toErrorCallbackString:self.callbackID]];
    


- (void)locationManager:(CLLocationManager *)manager 
                        didUpdateToLocation:(CLLocation *)newLocation 
                        fromLocation:(CLLocation *)oldLocation 
    if ([self.delegate conformsToProtocol:@protocol(NativeLocationDelegate)])
        [self.delegate locationUpdate:newLocation ];


- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error 
    if ([self.delegate conformsToProtocol:@protocol(NativeLocationDelegate)])
        [self.delegate locationError:error];


- (void)dealloc 
    [self.lm release];
    [super dealloc];


- (void)locationUpdate:(CLLocation *)location 
    CLLocationCoordinate2D cCoord = [location coordinate];
    nLat = cCoord.latitude;
    nLon = cCoord.longitude;



- (void)getLatitude:(NSMutableArray *)arguments 
                                      withDict:(NSMutableDictionary *)options

    self.callbackID = [arguments pop];

    nLat = lm.location.coordinate.latitude;
    nLon = lm.location.coordinate.longitude;

    CDVPluginResult* pluginResult = [CDVPluginResult 
                                    resultWithStatus:CDVCommandStatus_OK 
                                    messageAsDouble:nLat];

    [self writeJavascript: [pluginResult toSuccessCallbackString:self.callbackID]];


- (void)getLongitude:(NSMutableArray *)arguments 
                                       withDict:(NSMutableDictionary *)options

    self.callbackID = [arguments pop];

    nLat = lm.location.coordinate.latitude;
    nLon = lm.location.coordinate.longitude;

    CDVPluginResult* pluginResult = [CDVPluginResult 
                     resultWithStatus:CDVCommandStatus_OK messageAsDouble:nLon];

    [self writeJavascript: [pluginResult toSuccessCallbackString:self.callbackID]];



@end

3) 最后,从主 .js 调用所有内容

function getLongitudeSuccess(result)
    gLongitude = result;


function getLatitudeSuccess(result)
    gLatitude = result;


function runGPSTimer()
    var sTmp = "gps";

    theTime = setTimeout('runGPSTimer()', 1000);

    NativeLocation.getLongitude(
                                ["getLongitude"],
                                getLongitudeSuccess,
                                function(error) alert("error: " + error); 
                                );

    NativeLocation.getLatitude(
                               ["getLatitude"],
                               getLatitudeSuccess,
                               function(error) alert("error: " + error); 
                               );

【讨论】:

请记住,此解决方案仅适用于 android,正如我之前所说 - 您必须为每种设备类型本地找到解决方案。祝你好运【参考方案2】:

在我的 PhoneGap/Sencha Touch 2 应用程序中,我创建了函数

function getLastKnownLocation()
    if(typeof localStorage.lastKnownPosition == "undefined")
        localStorage.lastKnownPosition = JSON.stringify(null);
    

    navigator.geolocation.getCurrentPosition(
        function(position)
            localStorage.lastKnownPosition = JSON.stringify(position);
        
    );

    return JSON.parse(localStorage.lastKnownPosition);

所以每次我调用 getLastKnownLocation() 时,我都会立即得到结果。就我的目的而言,这是一个很好的解决方法。

【讨论】:

【参考方案3】:

我建议在您的getGeo_Success 函数调用setLocation([the_location]) 中将其存储在localStorage。您可以假设每个使用phoneGap 的设备都已经实现了localStorage。 这样,您总是在那里有有效的位置。然后只要你需要就弹出它。

function getLocation() 
  return JSON.parse(localStorage.getItem('location'));

function setLocation(location) 
  localStorage.setItem('vibesList', JSON.stringify(vibes));

编辑:如果你想检索设备知道的最新位置(不是应用程序),你必须通过background从设备中提取当前数据的过程。这是有问题的方法,因为:

    并非所有设备都允许这样做。 您必须编写自己的本地自定义 plugin 才能连接 phonegap。

【讨论】:

以上是关于检索最后一个已知的地理位置 - Phonegap的主要内容,如果未能解决你的问题,请参考以下文章

最后已知位置太旧

phonegap 最后一个位置提供程序被禁用

检索透明UIImage的最后一个非透明像素位置

长时间关闭智能手机时检索上次已知位置

CLLocationManager 最后一个已知位置

在设备位置关闭时从 Google Play 服务获取最后一个已知位置