现在的位置: 首页 > 综合 > 正文

手机定位技术概述

2012年07月21日 ⁄ 综合 ⁄ 共 18391字 ⁄ 字号 评论关闭

目前主流定位技术分为3种:GPS定位、基站定位和Wifi定位。

GPS

GPS是英文Global Positioning System全球定位系统)的简称,而其中文简称为“球位系”。GPS20世纪70年代由美国陆海空三军联合研制的新一代空间卫星导航定位系统 。其主要目的是为陆、海、空三大领域提供实时、 全天候和全球性的导航服务,并用于情报收集、核爆监测和应急通讯等一些军事目的,经过20余年的研究实验,耗资300亿美元,到19943月,全球覆盖率高达98%24GPS卫星星座己布设完成。GPS功能必须具备GPS终端、传输网络和监控平台三个要素;这三个要素缺一不可;通过这三个要素,可以提供车辆防盗、反劫、行驶路线监控及呼叫指挥等功能。最初的GPS计划在联合计划局的领导下诞生了,该方案将24颗卫星放置在互成120度的三个轨道上。每个轨道上有8颗卫星,地球上任何一点均能观测到69颗卫星。这样,粗码精度可达100m,精码精度为10m。由于预算压缩,GPS计划不得不减少卫星发射数量,改为将18颗卫星分布在互成60度的6个轨道上。然而这一方案使得卫星可靠性得不到保障。1988年又进行了最后一次修改:21颗工作星和所3颗备用星工作在互成30度的6条轨道上。这也是现在GPS卫星使用的工作方式。

Android定位功能

Android系统下面,对GPS的支持还是很好的。废话不多说,直接看看与实现Android定位有关的API吧。这些API都在android.location包下,一共有三个接口和八个类。它们配合使用即可实现定位功能。

  三个接口:

  GpsStatus.Listener: 这是一个当GPS状态发生改变时,用来接收通知的接口。

  GpsStatus.NmeaListener:这是一个用来从GPS里接收Nmea-0183(为海用电子设备制定的标准格式)信息的接口。

  LocationListener:位置监听器,用于接收当位置信息发生改变时从LocationManager接收通知的接口。

  八个类:

  Address:描述地址的类,比如:北京天安门

  Criteria:用于描述Location Provider标准的类,标准包括位置精度水平,电量消耗水平,是否获取海拔、方位信息,是否允许接收付费服务。

  GeoCoder:用于处理地理位置的编码。

  GpsSatellite:GpsStatus联合使用,用于描述当前GPS卫星的状态。

  GpsStatus:GpsStatus.Listener联合使用,用于描述当前GPS卫星的状态。

  Location:用于描述位置信息。

  LocationManager:通过此类获取和调用系统位置服务

  LocationProvider:用于描述Location Provider的抽象超类,一个LocationProvider应该能够周期性的报告当前设备的位置信息。

  这里通过一个代码示例,演示一下如何实现定位。

  首先,在AndroidManifest.xml清单文件里需要加入ACCESS_FINE_LOCATION权限

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>

  其次,实现代码如下:

package com.veer;

import android.app.Activity;

import android.content.Context;

import android.location.Location;

import android.location.LocationListener;

import android.location.LocationManager;

import android.os.Bundle;

import android.util.Log;

import android.widget.TextView;

public class LocationGPSActivity extends Activity {

    private String tag = "LocationGPSActivity";

  

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        LocationManager loctionManager;

        String contextService = Context.LOCATION_SERVICE;

        // 通过系统服务,取得LocationManager对象

        loctionManager = (LocationManager) getSystemService(contextService);

        // 得到位置提供器,通过位置提供器,得到位置信息,可以指定具体的位置提供器,也可以提供一个标准集合,让系统根据

        // 标准匹配最适合的位置提供器,位置信息是由位置提供其提供的。

        // a. 通过GPS位置提供器获得位置(指定具体的位置提供器)

        String provider = LocationManager.GPS_PROVIDER;

        Location location = loctionManager.getLastKnownLocation(provider);

        // b. 使用标准集合,让系统自动选择可用的最佳位置提供器,提供位置

        // Criteria criteria = new Criteria();

        // criteria.setAccuracy(Criteria.ACCURACY_FINE);// 高精度

        // criteria.setAltitudeRequired(false);// 不要求海拔

        // criteria.setBearingRequired(false);// 不要求方位

        // criteria.setCostAllowed(true);// 允许有花费

        // criteria.setPowerRequirement(Criteria.POWER_HIGH);//高功耗

        // // 从可用的位置提供器中,匹配以上标准的最佳提供器

        // String provider = loctionManager.getBestProvider(criteria, true);

        // // 获得最后一次变化的位置

        // Location location = loctionManager.getLastKnownLocation(provider);

        Log.v(tag, "location===" + location);

        // 使用新的location更新TextView显示

        updateWithNewLocation(location);

        // 监听位置变化,2秒一次,距离1000米以上

        loctionManager.requestLocationUpdates(provider, 2 * 1000, 1000,

                locationListener);

    }

    // 位置监听器

    private final LocationListener locationListener = new LocationListener() {

        @Override

        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override

        public void onProviderEnabled(String provider) {

        }

        @Override

        public void onProviderDisabled(String provider) {

        }

        // 当位置变化时触发

        @Override

        public void onLocationChanged(Location location) {

            // 使用新的location更新TextView显示

            updateWithNewLocation(location);

        }

    };

    // 通过改变位置经纬度,程序会自动更新TextView显示的位置信息

    private void updateWithNewLocation(Location location) {

        String latLongString;

        TextView myLoctionText;

        myLoctionText = (TextView) findViewById(R.id.myLoctionText);

        if (location != null) {

            double lat = location.getLatitude();

            double lng = location.getLongitude();

            latLongString = "Lat(纬度): " + lat + "\nLong(经度): " + lng;

        } else {

            latLongString = "没有获取到经纬度,悲剧啊。";

        }

        myLoctionText.setText("我当前的位置是:\n" + latLongString);

    }

}

基站篇

基站定位一般应用于手机用户,手机基站定位服务又叫做移动位置服务(LBS——Location Based Service),它是通过电信移动运营商的网络(如GSM网)获取移动终端用户的位置信息(经纬度坐标),在电子地图平台的支持下,为用户提供相应服务的一种增值业务,例如目前中国移动动感地带提供的动感位置查询服务等。其大致原理为:移动电话测量不同基站的下行导频信号,得到不同基站下行导频的TOATime of Arrival,到达时刻)或TDOA(Time Difference of Arrivalm,到达时间差),根据该测量结果并结合基站的坐标,一般采用三角公式估计算法,就能够计算出移动电话的位置。实际的位置估计算法需要考虑多基站(3个或3个以上)定位的情况,因此算法要复杂很多。一般而言,移动台测量的基站数目越多,测量精度越高,定位性能改善越明显。

实现代码如下:

package com.veer;

import java.io.BufferedReader;

import java.io.InputStreamReader;

import org.apache.http.HttpEntity;

import org.apache.http.HttpResponse;

import org.apache.http.client.HttpClient;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.DefaultHttpClient;

import org.json.JSONArray;

import org.json.JSONObject;

import android.app.Activity;

import android.content.Context;

import android.os.Bundle;

import android.telephony.TelephonyManager;

import android.telephony.gsm.GsmCellLocation;

import android.util.Log;

import android.widget.TextView;

public class LocationCellActivity extends Activity {

    private SCell cell = null;

    private SItude itude = null;

    private String userLongitude = "";

    private String userLatitude = "";

    private String tag = "LocationCellActivity";

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        try {

            cell = getCellInfo();

        } catch (Exception e1) {

            Log.v(tag, "获取基站数据 失败 **************************************");

        }

        try {

            itude = getItude(cell);

            Log.v(tag, "itude===" + itude);

        } catch (Exception e1) {

            Log.v(tag, "根据基站数据获取经纬度 失败 **************************************");

        }

        /* 获取用户当前位置信息 */

        if (itude != null) {

            userLongitude = itude.longitude;

            userLatitude = itude.latitude;

        } else {

            userLongitude = "";

            userLatitude = "";

        }

        Log.v(tag, "赋值后的经度====" + userLongitude);

        Log.v(tag, "赋值后到的纬度====" + userLatitude);

        TextView tv = (TextView) findViewById(R.id.info);

        String info = "经度为:" + userLongitude + "\n" + "纬度为:" + userLatitude;

        tv.setText(info);

    }

    /** 基站信息结构体 */

    public class SCell {

        public int MCC;

        public int MNC;

        public int LAC;

        public int CID;

    }

    /** 经纬度信息结构体 */

    public class SItude {

        public String latitude;

        public String longitude;

    }

    /**

     * 获取基站信息

     * 

     * @throws Exception

     */

    private SCell getCellInfo() throws Exception {

        SCell cell = new SCell();

        /** 调用API获取基站信息 */

        TelephonyManager mTelNet = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

        GsmCellLocation location = (GsmCellLocation) mTelNet.getCellLocation();

        if (location == null)

            throw new Exception("获取基站信息失败");

        String operator = mTelNet.getNetworkOperator();

        int mcc = Integer.parseInt(operator.substring(0, 3));

        int mnc = Integer.parseInt(operator.substring(3));

        int cid = location.getCid();

        int lac = location.getLac();

        /** 将获得的数据放到结构体中 */

        cell.MCC = mcc;

        cell.MNC = mnc;

        cell.LAC = lac;

        cell.CID = cid;

        return cell;

    }

    /**

     * 获取经纬度

     * 

     * @throws Exception

     */

    private SItude getItude(SCell cell) throws Exception {

        SItude itude = new SItude();

        /** 采用Android默认的HttpClient */

        HttpClient client = new DefaultHttpClient();

        /** 采用POST方法 */

        HttpPost post = new HttpPost("http://www.google.com/loc/json");

        try {

            /** 构造POSTJSON数据 */

            JSONObject holder = new JSONObject();

            holder.put("version", "1.1.0");

            holder.put("host", "maps.google.com");

            holder.put("address_language", "zh_CN");

            holder.put("request_address", true);

            holder.put("radio_type", "gsm");

            holder.put("carrier", "HTC");

            JSONObject tower = new JSONObject();

            tower.put("mobile_country_code", cell.MCC);

            tower.put("mobile_network_code", cell.MNC);

            tower.put("cell_id", cell.CID);

            tower.put("location_area_code", cell.LAC);

            JSONArray towerarray = new JSONArray();

            towerarray.put(tower);

            holder.put("cell_towers", towerarray);

            StringEntity query = new StringEntity(holder.toString());

            post.setEntity(query);

            /** 发出POST数据并获取返回数据 */

            HttpResponse response = client.execute(post);

            HttpEntity entity = response.getEntity();

            BufferedReader buffReader = new BufferedReader(

                    new InputStreamReader(entity.getContent()));

            StringBuffer strBuff = new StringBuffer();

            String result = null;

            while ((result = buffReader.readLine()) != null) {

                strBuff.append(result);

            }

            /** 解析返回的JSON数据获得经纬度 */

            JSONObject json = new JSONObject(strBuff.toString());

            JSONObject subjosn = new JSONObject(json.getString("location"));

            itude.latitude = subjosn.getString("latitude");

            itude.longitude = subjosn.getString("longitude");

            Log.v(tag, "刚刚获取到的经度====" + itude.longitude);

            Log.v(tag, "刚刚获取到的纬度====" + itude.latitude);

        } catch (Exception e) {

            throw new Exception("获取经纬度出现错误:" + e.getMessage());

        } finally {

            post.abort();

            client = null;

        }

        Log.v(tag, "方法返回的经度====" + itude.longitude);

        Log.v(tag, "方法返回的纬度====" + itude.latitude);

        return itude;

    }

}

Wifi

与手机基站定位方式类似,都需要采集wifi接入点的位置信息。

最早开发这个技术的是Skyhook公司。这个技术的原理是利用下面三条事实:wifi热点(也就是AP,或者无线路由器)越来越多,在城市中更趋向于空间任何一点都能接收到至少一个AP的信号。(在美国,每个点收到35AP信号的情况相当多见。中国也会越来越多的) 热点只要通电,不管它怎么加密的,都一定会向周围发射信号。信号中包含此热点的唯一全球ID。即使距离此热点比较远,无法建立连接,但还是可以侦听到它的存在。 热点一般都是很少变位置的,比较固定。这样,定位端只要侦听一下附近都有哪些热点,检测一下每个热点的信号强弱,然后把这些信息发送给Skyhook的服务器。服务器根据这些信息,查询每个热点在数据库里记录的坐标,进行运算,就能知道客户端的具体位置了,再把坐标告诉客户端。可以想想,只要收到的AP信号越多,定位就会越准。原理就是这么简单。

不过,一次成功的定位还需要两个先决条件:第二,客户端能上网。侦听到的热点的坐标在Skyhook的数据库里有第一条不用说了,不管是wifi还是edge,只要能连上Skyhook的服务器就行。第三条是Skyhook的金矿所在。它怎么知道每个AP的坐标信息的呢?有一种说法是靠网友自己搜集,然后发给SkyhookSkyhook会付钱。不过官方网站上的说法是开着车满大街转悠,边走边采集AP信号,并用GPS定位,从而就有了坐标信息。

package com.veer;

import java.io.IOException;

import java.util.List;

import org.apache.http.HttpResponse;

import org.apache.http.client.ClientProtocolException;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.DefaultHttpClient;

import org.apache.http.util.EntityUtils;

import org.json.JSONArray;

import org.json.JSONException;

import org.json.JSONObject;

import android.app.Activity;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import android.net.wifi.ScanResult;

import android.net.wifi.WifiManager;

import android.os.Bundle;

import android.util.Log;

import android.view.KeyEvent;

import android.widget.TextView;

public class LocationWifiActivity extends Activity {

    /** Called when the activity is first created. */

    WifiManager mainWifi;

    WifiReceiver receiverWifi;

    List<ScanResult> wifiList;

    TextView textview;

    StringBuilder sb = new StringBuilder();

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        textview = (TextView) findViewById(R.id.textView1);

        mainWifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);

        receiverWifi = new WifiReceiver();

        registerReceiver(receiverWifi, new IntentFilter(

                WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

        mainWifi.startScan();

    }

    public boolean onKeyUp(int KeyCode, KeyEvent envent) {

        if (KeyCode == KeyEvent.KEYCODE_0)

            onDestroy();

        else

            super.onKeyUp(KeyCode, envent);

        return true;

    }

    public void onDestroy() {

        Log.e("wifi", "onDestroy");

        super.onDestroy();

    }

    class WifiReceiver extends BroadcastReceiver {

        public void onReceive(Context c, Intent intent) {

            wifiList = mainWifi.getScanResults();

            for (int i = 0; i < wifiList.size(); i++) {

                Log.e("wifi", wifiList.get(i).toString());

            }

            HttpPost httpRequest = new HttpPost(

                    "http://www.google.com/loc/json");

            JSONObject holder = new JSONObject();

            JSONArray array = new JSONArray();

            try {

                holder.put("version", "1.1.0");

                holder.put("host", "maps.google.com");

                holder.put("address_language", "zh_CN");

                holder.put("request_address", true);

                for (int i = 0; i < wifiList.size(); i++) {

                    JSONObject current_data = new JSONObject();

                    current_data.put("mac_address", wifiList.get(i).BSSID);

                    current_data.put("ssid", wifiList.get(i).SSID);

                    current_data.put("signal_strength", wifiList.get(i).level);

                    array.put(current_data);

                }

                holder.put("wifi_towers", array);

                Log.e("wifi", holder.toString());

                StringEntity se = new StringEntity(holder.toString());

                httpRequest.setEntity(se);

                HttpResponse resp = new DefaultHttpClient()

                        .execute(httpRequest);

                if (resp.getStatusLine().getStatusCode() == 200) {

                    /* 取出响应字符串 */

                    String strResult = EntityUtils.toString(resp.getEntity());

                    textview.setText(strResult);

                }

            } catch (JSONException e) {

                textview.setText(e.getMessage().toString());

                e.printStackTrace();

            } catch (ClientProtocolException e) {

                textview.setText(e.getMessage().toString());

                e.printStackTrace();

            } catch (IOException e) {

                textview.setText(e.getMessage().toString());

                e.printStackTrace();

            } catch (Exception e) {

                textview.setText(e.getMessage().toString());

                e.printStackTrace();

            }

        }

    }

}

另一个封装类:

package com.veer;

import java.util.List;

import android.content.Context;

import android.net.wifi.ScanResult;

import android.net.wifi.WifiConfiguration;

import android.net.wifi.WifiInfo;

import android.net.wifi.WifiManager;

import android.net.wifi.WifiManager.WifiLock;

public class WifiAdmin {

    // 定义WifiManager对象

    private WifiManager mWifiManager;

    // 定义WifiInfo对象

    private WifiInfo mWifiInfo;

    // 扫描出的网络连接列表

    private List<ScanResult> mWifiList;

    // 网络连接列表

    private List<WifiConfiguration> mWifiConfiguration;

    // 定义一个WifiLock

    WifiLock mWifiLock;

    // 构造器

    public WifiAdmin(Context context) {

        // 取得WifiManager对象

        mWifiManager = (WifiManager) context

                .getSystemService(Context.WIFI_SERVICE);

        // 取得WifiInfo对象

        mWifiInfo = mWifiManager.getConnectionInfo();

    }

    // 打开WIFI

    public void OpenWifi() {

        if (!mWifiManager.isWifiEnabled()) {

            mWifiManager.setWifiEnabled(true);

        }

    }

    // 关闭WIFI

    public void CloseWifi() {

        if (!mWifiManager.isWifiEnabled()) {

            mWifiManager.setWifiEnabled(false);

        }

    }

    // 锁定WifiLock

    public void AcquireWifiLock() {

        mWifiLock.acquire();

    }

    // 解锁WifiLock

    public void ReleaseWifiLock() {

        // 判断时候锁定

        if (mWifiLock.isHeld()) {

            mWifiLock.acquire();

        }

    }

    // 创建一个WifiLock

    public void CreatWifiLock() {

        mWifiLock = mWifiManager.createWifiLock("Test");

    }

    // 得到配置好的网络

    public List<WifiConfiguration> GetConfiguration() {

        return mWifiConfiguration;

    }

    // 指定配置好的网络进行连接

    public void ConnectConfiguration(int index) {

        // 索引大于配置好的网络索引返回

        if (index > mWifiConfiguration.size()) {

            return;

        }

        // 连接配置好的指定ID的网络

        mWifiManager.enableNetwork(mWifiConfiguration.get(index).networkId,

                true);

    }

    public void StartScan() {

        mWifiManager.startScan();

        // 得到扫描结果

        mWifiList = mWifiManager.getScanResults();

        // 得到配置好的网络连接

        mWifiConfiguration = mWifiManager.getConfiguredNetworks();

    }

    // 得到网络列表

    public List<ScanResult> GetWifiList() {

        return mWifiList;

    }

    // 查看扫描结果

    public StringBuilder LookUpScan() {

        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i < mWifiList.size(); i++) {

            stringBuilder

                    .append("Index_" + new Integer(i + 1).toString() + ":");

            // ScanResult信息转换成一个字符串包

            // 其中把包括:BSSIDSSIDcapabilitiesfrequencylevel

            stringBuilder.append((mWifiList.get(i)).toString());

            stringBuilder.append("\n");

        }

        return stringBuilder;

    }

    // 得到MAC地址

    public String GetMacAddress() {

        return (mWifiInfo == null) ? "NULL" : mWifiInfo.getMacAddress();

    }

    // 得到接入点的BSSID

    public String GetBSSID() {

        return (mWifiInfo == null) ? "NULL" : mWifiInfo.getBSSID();

    }

    // 得到IP地址

    public int GetIPAddress() {

        return (mWifiInfo == null) ? 0 : mWifiInfo.getIpAddress();

    }

    // 得到连接的ID

    public int GetNetworkId() {

        return (mWifiInfo == null) ? 0 : mWifiInfo.getNetworkId();

    }

    // 得到WifiInfo的所有信息包

    public String GetWifiInfo() {

        return (mWifiInfo == null) ? "NULL" : mWifiInfo.toString();

    }

    // 添加一个网络并连接

    public void AddNetwork(WifiConfiguration wcg) {

        int wcgID = mWifiManager.addNetwork(wcg);

        mWifiManager.enableNetwork(wcgID, true);

    }

    // 断开指定ID的网络

    public void DisconnectWifi(int netId) {

        mWifiManager.disableNetwork(netId);

        mWifiManager.disconnect();

    }

}

当然这些都只是一些概述,在具体实现的是后还需要注意很多问题,尤其是各种异常的处理,请大家自己注意。

抱歉!评论已关闭.