【Unity】unity3d 获取手机地理位置

怎么用unity3d 获取手机地理位置呢?unity的某些场景中,如果需要定位地理位置的话,但是unity却没有提供相应的接口。对于安卓(这里举例,IOS暂没研究)这个时候只能用java写个获取地理位置的方法,然后与unity交互。这样就能在unity脚本中获取当前手机的地理位置。 实际开发时,为了方便我直接调用百度的API来获取地理信息。 获取地理位置,有三种方式: 

   1、手机信号塔数据:当移动设备的GPS芯片不能接收到GPS信号时,移动设备就需要与它所连接的手机信号塔通讯和估算它与信号塔之间的距离以不断报告它的地理位置。通过这种方法获得的地理位置数据不如纯粹的GPS数据精确。

     2、WiFi连接:这是一种能够精确获得地理位置数据的方法,但是需要用到有效的WiFi热点。WiFi的地址与GPS坐标是一一对应的。它可以准确地标示出用户所处的位置,因此很多零售商才愿意提供免费的公共WiFi服务,那样它们就能够发布店内移动广告了。

     3、IP地址:地理位置也可以通过与数据连接有关的IP地址来获得。这种方法的准确性会因运营商而异,可靠性也比上述方法要低一些。

     4、GPS:精确,无需连接网络,但是连接时比较耗时。。

    用百度API调用时,首先需要申请一个key。具体的可以去官网试试。根据IP地址调用,比较方便,因为可以直接用http的方式发送请求,然后返回json格式的数据,如下:


public class AddressTool{
                //ip为空,默认为本机ip
                public static IEnumerator GetAddressFromIP(string ipAddress, AddressForQueryIPFromBaidu data)
                {
                        string baiduKey = "42c43828c02a9f6144dd305643ca73b8";
                        //ip:ip地址(可选,ip不出现,或者出现且为空字符串的情况下,会使用当前访问者的IP地址作为定位参数),ak:用户密钥,
                    //coor:输出的坐标格式(可选,coor不出现时,默认为百度墨卡托坐标;coor=bd09ll时,返回为百度经纬度坐标) 
                        string url = "http://api.map.baidu.com/location/ip?ak="+baiduKey+"&coor=bd09ll&ip=202.198.16.3";
                        WWW w = new WWW(url);
                        //超时时间
                        float t = Time.time;
                        while(!w.isDone){
                                if(Time.time - t > 15f){
                                        Debug.Log("server time out!");
                                        w.Dispose();
                                        yield break;
                                }
                                yield return null;
                        }
                        //接收http请求返回的数据(json格式)
                        string jsonData = w.text;
            //解析成对象
                        AddressForQueryIPFromBaidu result =  (AddressForQueryIPFromBaidu)ValueParse.ParseJsonToClass(typeof(AddressForQueryIPFromBaidu), jsonData);
                }
        }
        #region AddressForQueryIPFromBaidu
        public class AddressForQueryIPFromBaidu
        {
                //地址 
                public string address { get; set; }
                //详细内容  
                public Content content { get; set; }
                //返回状态码
                public string status { get; set; }
 
//                public string ToString(){
//                        return string.Format("根据IP获取地理位置 地址:{0}, 详细内容:{1},返回状态码:{2}",address.ToString(),content,status);
//                }
        }
        public class Content
        {
                //简要地址 
                public string address { get; set; }
                //详细地址信息
                public Address_Detail address_Detail { get; set; }
                //百度经纬度坐标值  
                public Point point { get; set; }
        }
        public class Address_Detail
        {
                //城市  
                public string city { get; set; }
                //百度城市代码  
                public string city_Code { get; set; }
                //区县 
                public string district { get; set; }
                //省份
                public string province { get; set; }
                //街道
                public string street { get; set; }
                //门址
                public string street_Number { get; set; }
        }
        public class Point
        {
                public string x { get; set; }
                public string y { get; set; }
        }


IP定位的结果精度较差,主要应用获取省份或者城市的位置信息。百度android定位SDK是利用设备当前的GPS信息(GPS定位),网络信息(基站定位 和 Wi-Fi定位)完成定位的。开发者在应用中成功集成百度定位SDK(包括一个armeabi的文件夹也得放在libs中)以后,既可以方便的通过定位SDK的接口向百度定位服务请求位置信息。下载百度定位的SDK,导入到安卓工程中。相关Android代码,如下:

package com.zs.address;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.LocationClientOption.LocationMode;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
 
@SuppressLint("NewApi")
public class MainActivity extends UnityPlayerActivity{
        public LocationClient mLocationClient = null;
        public BDLocationListener mListener = new MyLocationListener();
 
//        private TextView text;
//        private Button againBtn, clearBtn, startBtn, stopBtn;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                //setContentView(R.layout.activity_main);
                //initView();
                //初始化百度定位SDK
                initLocationService();
        }
         
        @SuppressLint("NewApi")
        public void initLocationService() {
                // 声明LocationClient类
                mLocationClient = new LocationClient(getApplicationContext());
                mLocationClient.registerLocationListener(mListener);//注册监听函数
                 
                LocationClientOption option = new LocationClientOption();
                option.setLocationMode(LocationMode.Hight_Accuracy);// 设置定位模式
                option.setCoorType("gcj02");// 返回的定位结果,默认值gcj02
                option.setScanSpan(5000);// 设置发起定位请求的间隔时间为5000ms
                option.setIsNeedAddress(true);// 返回的定位结果包含地址信息
                option.setNeedDeviceDirect(true);// 返回的定位结果包含手机机头的方向
                option.setOpenGps(true);//
                mLocationClient.setLocOption(option);
                mLocationClient.requestLocation();
        }
         
        //启动定位服务,给unity调用
        public void startLocationService(){
                mLocationClient.start();
        }
        //停止定位服务,给unity调用
        public void stopLocationService(){
                mLocationClient.stop();
        }
 
        class MyLocationListener implements BDLocationListener{
                @Override
                public void onReceiveLocation(BDLocation location) {
                        // public int getLocType ( )返回值:
                        // 61 : GPS定位结果
                        // 62 : 扫描整合定位依据失败。此时定位结果无效。
                        // 63 : 网络异常,没有成功向服务器发起请求。此时定位结果无效。
                        // 65 : 定位缓存的结果。
                        // 66 : 离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果
                        // 67 : 离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果
                        // 68 : 网络连接失败时,查找本地离线定位时对应的返回结果
                        // 161: 表示网络定位结果
                        // 162~167: 服务端定位失败
                        // 502:key参数错误
                        // 505:key不存在或者非法
                        // 601:key服务被开发者自己禁用
                        // 602:key mcode不匹配
                        // 501~700:key验证失败
                        if (location == null)
                                return;
                        JSONObject jo = new JSONObject();
                        try {
                                jo.put("error_code", location.getLocType());
                                jo.put("time", location.getTime());
                                jo.put("latitude", location.getLatitude());//获取维度
                                jo.put("lontitude", location.getLongitude());//获取经度
                                jo.put("radius", location.getRadius());
                                jo.put("direction", location.getDirection());
                                //只有使用GPS定位的情况下,获取移动速度,当前连接的卫星编号
                                if(location.getLocType() == BDLocation.TypeGpsLocation){
                                        JSONObject gpsInfo = new JSONObject();
                                        gpsInfo.put("speed", location.getSpeed());
                                        gpsInfo.put("satellite", location.getSatelliteNumber());
                                        jo.put("gpsInfo", gpsInfo);
                                }else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
                                        // 只有使用网络定位的情况下,才能获取当前位置的反地理编码描述。
                                        // 自定位SDK2.6版本之后,支持获取省/市/区分级地理信息:
                                        JSONObject netWorkInfo = new JSONObject();
                                        netWorkInfo.put("address", location.getAddrStr());//获取反地理编码
                                        netWorkInfo.put("province", location.getProvince());//获取省份信息
                                        netWorkInfo.put("city", location.getCity());//获取城市信息
                                        netWorkInfo.put("city_code", location.getCityCode()); //获取城市编码
                                        netWorkInfo.put("district", location.getDistrict()); //获取区县信息
                                        netWorkInfo.put("street", location.getStreet()); //获取街道地址
                                        netWorkInfo.put("street_number", location.getStreetNumber()); //获取街道门牌号
                                        jo.put("netWorkInfo", netWorkInfo);
                                }
                        } catch (JSONException e1) {
                                Log.i("address", e1.toString());
                        }
                         
                        Log.i("address", jo.toString());
                        //将获取的地理信息返回给unity
                        UnityPlayer.UnitySendMessage("address", "AddressCallback", jo.toString());
                        //text.setText(jo.toString());
                }
        }
         
        private void requestLocation() {
                mLocationClient.requestLocation();
        }
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
                // Inflate the menu; this adds items to the action bar if it is present.
                getMenuInflater().inflate(R.menu.main, menu);
                return true;
        }
 
//        private void initView(){
//                text = (TextView)findViewById(R.id.textView);
//                againBtn = (Button)findViewById(R.id.button1);
//                clearBtn = (Button)findViewById(R.id.button2);
//                startBtn = (Button)findViewById(R.id.button3);
//                stopBtn = (Button)findViewById(R.id.button4);
//                againBtn.setOnClickListener(clickListener);
//                clearBtn.setOnClickListener(clickListener);
//                startBtn.setOnClickListener(clickListener);
//                stopBtn.setOnClickListener(clickListener);
//        }
//        
//        private View.OnClickListener clickListener = new View.OnClickListener() {
//                public void onClick(View v) {
//                        switch (v.getId()) {
//                        case R.id.button1:
//                                requestLocation();
//                                break;
//                        case R.id.button2:
//                                text.setText("");
//                                break;
//                        case R.id.button3:
//                                startLocationService();
//                                break;
//                        case R.id.button4:
//                                stopLocationService();
//                                break;
//                        default:
//                                break;
//                        }
//                }
//        };
}

设置AndroidManifest.xml
在application标签中声明service组件,这是百度SDK的定位service

<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote">
</service>
声明使用权限

<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!-- 用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!—SD卡读取权限,用户写入离线定位数据-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>
<!--允许应用读取低级别的系统日志文件 -->
<uses-permission android:name="android.permission.READ_LOGS"></uses-permission>

把MainActivity的一些注释打开,然后继承Activity,就可以直接做成app在手机上运行了。该项目demo,在本文最后。

       接下来就是把该安卓项目的代码打成jar包,然后放在unity项目资源下的Plugins->Android目录下。再把libs(里面只能放百度的第三方jar包,不要把unity的class.jar,和Android的jar包放在里面)、res文件夹、AndroidManifest,也放在Android目录下。在场景中放上一个空物体,名为‘address’(必须和java代码中“UnityPlayer.UnitySendMessage("address", "AddressCallback", jo.toString());”保持一致),编写一个脚本“AddressTest.cs”,绑在该空对象上面。,该脚本如下:

using UnityEngine;
using System.Collections;
using address;
public class AddressTest : MonoBehaviour {
        //地理信息 
        private string geography = "lala haha wawa";
        private GUIStyle style = new GUIStyle();
 
        private int count = 0;
        private AndroidJavaObject jo;
 
        public void Awake(){
                //GUI样式 
                style.fontSize = 30;
                style.wordWrap = true;
                //初始化安卓的MainActivity。下面两句话是固定的,不能变动
                AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
                jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
        }
 
        //回调函数,接收到地理信息,展示在页面上。 
        public void AddressCallback(string jsonStr){
                Debug.Log("zs : "+jsonStr);
                geography = "第"+ (++count).ToString()+"次接受信息:" + jsonStr;
        }
 
        void OnGUI(){
                GUI.Label(new Rect(0,0,700,300),geography,style);
                //启动地理服务
                if(GUI.Button(new Rect(0, 400,60,30)," 启 动 ")){
                        jo.Call("startLocationService");
                }
                //关闭地理服务
                if(GUI.Button(new Rect(140, 400,60,30)," 停 止 ")){
                        jo.Call("stopLocationService");
                }
        }
}

转载地址:http://www.taikr.com/article/351
展开阅读全文

没有更多推荐了,返回首页