現在軟體市場上有很多可以改變手機地理位置的軟體,更改後開啟就可以隨意定位,甚至前幾年有依靠這個技術打廣告為生的小型公司。
一擷取地理位置的方法
擷取地理位置的方法一般分為兩種。
1)GPS
24顆衛星定位全球(圖片來自維基百科)給出詳解地址:http://zh.wikipedia.org/wiki/GPS;
但是向衛星對請求訊號強度的要求比較高,很多專門的硬體裝置有時都達不到,所以手機使用GPS這種方法百分之九十的可能擷取的是null。
2)network
這種方法其實又分為兩種情況。一種是有線一種為無線。
1,有線
因為是有線網路位置固定,每個存取點的ip為又是固定的,網路的ip和位置就產生一一對應關係。根據存取點的ip既可得到地理位置。不過這些工作似乎是系統或者網路供應商要做的,不用android的開發人員解析。
2,無線
無線使用的是基站定位。實際上也就是數學上的三點定位。例如移動公司,其基站遍布全國,如果一台裝置想要連無線網,附近的三個基站會根據訊號強度判斷出訪問者的相對距離,畫出三個半徑為距離的園,根據三個圓的交點得知大致地理座標。(圖片來著百度百科)
3,wifi
例如某些平板電腦,不能插入網卡,不能插入手機卡,它們訪問網路就都是走的wifi,那麼它的地理位置擷取就是根據wifi共用裝置的地理位置來大致確定的。wifi共用裝置的地理位置的確定參看以上1,2;
二:擷取地理位置
android 提供了
locationmanager 類來管理地理位置資訊,其中提供了添加,刪除,篩選等很方便的功能。
public classLocationManagerextends Object
| java.lang.Object |
| ? |
android.location.LocationManager |
這個對象不能new ,只能從系統擷取
Class Overview
This class provides access to the system location services. These services allow applications to obtain periodic updates of the device's geographical location, or to fire an application-specified Intentwhen the device enters the proximity of a given geographical location.
You do not instantiate this class directly; instead, retrieve it through Context.getSystemService(Context.LOCATION_SERVICE).
Unless noted, all Location API methods require the ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permissions. If your application only has the coarse permission then it will not have access to the GPS or passive location providers. Other providers will still return location results, but the update rate will be throttled and the exact location will be obfuscated to a coarse level of accuracy.
另外,這個對象擷取所有的位置提供者,並且進行刪除,添加,等操作。
太多了,不複製,直接給出api連結好了:http://developer.android.com/reference/android/location/LocationManager.html
在瞭解這個類之後再擷取當前的地理位置就簡單多了。網上有很多代碼。
大致是擷取位置提供者,迴圈像每個提供者索要地理資訊,資訊被系統封裝成了Location這個類。
擷取Location對象後可以調用
public Location getLocation(Context context) {LocationManager locMan = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);Location location = locMan.getLastKnownLocation(LocationManager.GPS_PROVIDER);if (location == null) {location = locMan.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);}return location;}
為什麼要擷取兩次,因為剛才所說,一般擷取GPS擷取不到,不過其實擷取兩次應該也是null。
對於getLastKownLocation()
| Location |
getLastKnownLocation(String provider) Returns a Location indicating the data from the last known location fix obtained from the given provider. |
他接受一個提供者名字的參數,一般如果調用系統的話有:
GPS_PROVIDER, NETWORK_PROVIDER, 這兩個容易理解,一個是網路一個是gps 另外,還有一個PASSIVE_PROVIDER
public static final String PASSIVE_PROVIDERAdded in API level 8
A special location provider for receiving locations without actually initiating a location fix.
This provider can be used to passively receive location updates when other applications or services request them without actually requesting the locations yourself. This provider will return locations generated by other providers. You can query the getProvider() method to determine the origin of the location update. Requires the permission ACCESS_FINE_LOCATION, although if the GPS is not enabled this provider might only return coarse fixes.
Constant Value: passive 這個究竟是什麼暫時還沒搞懂。
不過你也可以手動擷取所有提供者,因為有可能原生裝置已經添加了某些位置提供者(下一部分分析添加位置給系統,即 虛擬地理位置),我想大多數軟體都是這麼寫的或者說應該這麼寫,擷取所有位置提供者,然後迴圈索要location:
| List |
getProviders(boolean enabledOnly) Returns a list of the names of location providers. |
| List |
getProviders(Criteria criteria, boolean enabledOnly) Returns a list of the names of LocationProviders that satisfy the given criteria, or null if none do. |
用到這兩個方法,對於第二個重載的方法的第一個參數,意思是限制條件類,即根據所提供的對位置提供者的限制返回符合要求的名稱。
擷取String數組後就可以迴圈擷取位置:
private Location getLocation(){for(int i = 0; i < locProvider.length, i ++){Location location = locationManager.getLocation(locProvider.get(i));if(location!=null)return location;}return null;}
另外,也可以對現有的位置提供者進行修改(系統原有的三個修改不了),不過需要
1,擷取LocationProvider 類
| LocationProvider |
getProvider(String name) Returns the information associated with the location provider of the given name, or null if no provider exists by that name. |
2,修改
3刪除原有的
| void |
removeTestProvider(String provider) Removes the mock location provider with the given name. |
4添加修改後的。
| void |
addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) Creates a mock location provider and adds it to the set of active providers. |
當然要加入相應的許可權:
三 虛擬地理位置
其實google play 上就有現成的程式:https://play.google.com/store/apps/details?id=com.lexa.fakegps&hl=zh_TW,
而且github上有託管的原始碼.
具體方法是添加位置提供者,不斷向位置提供者傳遞locaiton資訊。
public void setTestProviderEnabled (String provider, boolean enabled)Added in API level 3
Sets a mock enabled value for the given provider. This value will be used in place of any actual value from the provider.
Parameters
| provider |
the provider name |
| enabled |
the mock enabled value |
Throws
| SecurityException |
if the ACCESS_MOCK_LOCATION permission is not present or the Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled |
| IllegalArgumentException |
if no provider with the given name exists |
這個也是需要加入特殊許可權的:
另外,經過測試發現,不如直接給“gps”傳位置,其他軟體更容易接受,不過需要使用者把虛擬地理位置選項開啟。