Unity接入高德定位SDK——使用Eclipse
Eclipse部分
- 首先进入Eclipse的官网下载最新版的IDE工具。https://www.eclipse.org/downloads/
- 打开安装软件
然后傻瓜式安装,协议证书什么的同意一下就行。 - 然后如果需要导出Unity 的Jar包的话还需要2个东西,jdk 、Android SDK Tools 和 ADT Plugin。
jdk的话可以从ORACLE官网下载:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 笔者使用的版本是jdk1.8.0_151
Android SDK Tools 和 ADT Plugin都可以从Android Developer Tools下载:http://tools.android-studio.org/
具体的可以进入官网看 详细的使用说明。 - 接下来需要配置jdk的环境变量,具体可以看:http://www.cnblogs.com/mapley/p/7631865.html
- 环境配好后打开Eclipse,导入ADT Plugin:
(1)启动Eclipse,然后选择Help>Install New Software…。
(2)点击右上角的“Add”。在出现的“Add Repository”对话框中,为“名称”输入“ADT Plugin”,并点击“Archive…”选择下载的adt的zip包(不需要解压缩)。
(3)在“可用软件”对话框中,选中“开发工具”旁边的复选框,然后单击“下一步”。
(4)在下一个窗口中,您将看到要下载的工具的列表。 点击下一步。
(5)阅读并接受许可协议,然后单击完成。
(6)等待Eclipse右下角进度条,安装完成后,重新启动Eclipse。
在这一步的时候,如果您收到安全警告,指出软件的真实性或有效性无法建立,请单击“确定”。
假如是第一次使用eclipse的小伙伴,请把Welcome的界面关闭。。。就会弹出正常的界面。 - 创建Android工程。
(1)
如果没有创建Android项目的选项的小伙伴,请检查下ADT是否成功安装。
(2)
傻瓜式的安装下一步,如果需要更改路径的话,自己改一下,到下面那步选择空项目。
(3)将AndriodStudio中的视图层以及“setContentView(R.layout.activity_main);”这段代码删除。
如果一下三个脚本报错的话,可以这么改:
(4)在高德开发者后台中下载好定位的jar文件,解压拷贝到 libs 的根目录下。(具体操作请看下面的高德板块内容)
添加到Libraries中:
(5)将unity的classes.jar加入到项目的的libs文件夹中,目录为
D:\Unity2017.3.0\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Development\Classes
或者D:\Unity2017.3.0\Editor\Data\PlaybackEngines\androidplayer\bin目录下。同样添加到Libraries中: - 编写MainActivity代码:
package com.tspersonal.AMapLocationDemo;
import android.os.Bundle;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.unity3d.player.UnityPlayerActivity;
public class MainActivity extends UnityPlayerActivity
{
public AMapLocationClient mLocationClient = null;
public AMapLocationClientOption mLocationOption = null;
private String LocationInfo = "未找到地址,请开启定位!";
private String Country;
private String Province;
private String City;
private String District;
private String Street;
private String StreetNum;
private String CityCode;
private String AdCode;
private String AoiName;
private int ErrorCode;
private double Latitude;//纬度
private double Longitude;//经度
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
//获取定位信息
public String GetInfo()
{
startLocation();
return this.LocationInfo;
}
public String GetCountry()
{
return this.Country;
}
public String GetProvince()
{
return this.Province;
}
public String GetCity()
{
return this.City;
}
public String GetDistrict()
{
return this.District;
}
public String GetStreet()
{
return this.Street;
}
public String GetStreetNum()
{
return this.StreetNum;
}
public String GetCityCode()
{
return this.CityCode;
}
public String GetAdCode()
{
return this.AdCode;
}
public String GetAoiName()
{
return this.AoiName;
}
public int GetErrorCode()
{
return this.ErrorCode;
}
public double GetLatitude()
{
return this.Latitude;
}
public double GetLongitude()
{
return this.Longitude;
}
protected void onStart()
{
super.onStart();
}
private void startLocation()
{
this.mLocationClient = new AMapLocationClient(getApplicationContext());this.mLocationClient.setLocationListener(this.mLocationListener);
this.mLocationOption = new AMapLocationClientOption();
this.mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
this.mLocationOption.setInterval(2000L);
this.mLocationClient.setLocationOption(this.mLocationOption);
this.mLocationClient.startLocation();
}
//该方位为高德SDK定位的回调方法。
public AMapLocationListener mLocationListener = new AMapLocationListener() {
@Override
public void onLocationChanged(AMapLocation location) {
if (location != null) {
if (location.getErrorCode() == 0) {
ErrorCode = location.getErrorCode();
//获取坐标信息
Latitude = location.getLatitude();
Longitude = location.getLongitude();
StringBuffer sb = new StringBuffer(256);
//sb.append("时间: " + location.getTime());
//sb.append("\n纬度:" + location.getLatitude());
//sb.append("\n经度:" + location.getLongitude());
//sb.append("\n精度:" + location.getAccuracy());
sb.append(location.getAddress());
//sb.append("\n国家信息:" + location.getCountry());
Country = location.getCountry();
//sb.append("\n省信息:" + location.getProvince());
Province = location.getProvince();
//sb.append("\n城市信息:" + location.getCity());
City = location.getCity();
//sb.append("\n城区信息:" + location.getDistrict());
District = location.getDistrict();
//sb.append("\n街道信息:" + location.getStreet());
Street = location.getStreet();
//sb.append("\n街道门牌号信息:" + location.getStreetNum());
StreetNum = location.getStreetNum();
//sb.append("\n城市编码:" + location.getCityCode());
CityCode = location.getCityCode();
//sb.append("\n地区编码:" + location.getAdCode());
AdCode = location.getAdCode();
//sb.append("\n定位点AOI信息:" + location.getAoiName());
AoiName = location.getAoiName();
LocationInfo = sb.toString();
}else {
LocationInfo = location.getErrorInfo();
}
}
}
};
}
- 配置配置AndroidManifest.xml:
贴上代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tspersonal.AMapLocationDemo"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="preferExternal"
android:versionCode="1"
android:versionName="1.0">
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"/>
<application
android:theme="@android:style/Theme.NoTitleBar"
android:label="@string/app_name"
android:icon="@drawable/app_icon">
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="这里注意需要替换成你从高德后台中申请的key"/>
<service android:name="com.amap.api.location.APSService" ></service>
<activity android:name="com.tspersonal.AMapLocationDemo.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-feature android:glEsVersion="0x00020000" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
</manifest>
- 导出jar包。在导出之前还是先刷新下(F5),和Build 下Project.
这里导出纯净的jar包,只选择src文件夹,其他的都不选择。
到这里所有的Eclipse部分都已经完成了。
Unity部分
1. 生成一个unity的空项目,笔者的unity版本是2017.3.0f3。
2. 搭建好测试场景 ,方便显示定位数据。
3. 写调用Android的定位的方法的代码。注意:定位信息不一定是软件开启就会定位成功的,软件开启的时候需要一个同意定位权限的时间,如果在这段时间请求了定位的话,会返回失败的,所以需要在定位权限开启的时候,请求定位。
代码如下,因为是一个单例所以可以在其他绑定了界面的显示类中访问:
结构:
using System;
using UnityEngine;
/// <summary>
/// 错误码对照表
/// </summary>
public enum ErrorCode
{
Error1_ = -1,//异常错误。
Successful = 0,//定位成功。 ====>>>> 可以在定位回调里判断定位返回成功后再进行业务逻辑运算。
Error1,//一些重要参数为空,如context。 ====>>>> 请对定位传递的参数进行非空判断。
Error2,//定位失败,由于仅扫描到单个wifi,且没有基站信息。 ====>>>> 请重新尝试。
Error3,//获取到的请求参数为空,可能获取过程中出现异常。 ====>>>> 请对所连接网络进行全面检查,请求可能被篡改。
Error4,//请求服务器过程中的异常,多为网络情况差,链路不通导致。 ====>>>> 请检查设备网络是否通畅,检查通过接口设置的网络访问超时时间,建议采用默认的30秒。
Error5,//请求被恶意劫持, ====>>>> 定位结果解析失败。您可以稍后再试,或检查网络链路是否存在异常。
Error6,//定位服务返回定位失败。 ====>>>> 请获取errorDetail(通过getLocationDetail()方法获取)信息并参考定位常见问题进行解决。
Error7,//KEY鉴权失败。 ====>>>> 请仔细检查key绑定的sha1值与apk签名sha1值是否对应,或通过高频问题查找相关解决办法。
Error8,//Android exception常规错误。 ====>>>> 请将errordetail(通过getLocationDetail()方法获取)信息通过工单系统反馈给我们。
Error9,//定位初始化时出现异常。 ====>>>> 请重新启动定位。
Error10,//定位客户端启动失败。 ====>>>> 请检查AndroidManifest.xml文件是否配置了APSService定位服务。
Error11,//定位时的基站信息错误。 ====>>>> 请检查是否安装SIM卡,设备很有可能连入了伪基站网络。
Error12,//缺少定位权限。 ====>>>> 请在设备的设置中开启app的定位权限。
Error13,//定位失败,由于未获得WIFI列表和基站信息,且GPS当前不可用。 ====>>>> 建议开启设备的WIFI模块,并将设备中插入一张可以正常工作的SIM卡,或者检查GPS是否开启;如果以上都内容都确认无误,请您检查App是否被授予定位权限。
Error14,//GPS 定位失败,由于设备当前 GPS 状态差。 ====>>>> 建议持设备到相对开阔的露天场所再次尝试。
Error15,//定位结果被模拟导致定位失败。 ====>>>> 如果您希望位置被模拟,请通过setMockEnable(true);方法开启允许位置模拟。
Error16,//当前POI检索条件、行政区划检索条件下,无可用地理围栏。 ====>>>> 建议调整检索条件后重新尝试,例如调整POI关键字,调整POI类型,调整周边搜区域,调整行政区关键字等。
Error17,//定位失败,错误码:17。
Error18,//定位失败,由于手机WIFI功能被关闭同时设置为飞行模式。 ====>>>> 建议手机关闭飞行模式,并打开WIFI开关。
Error19,//定位失败,由于手机没插sim卡且WIFI功能被关闭。 ====>>>> 建议手机插上sim卡,打开WIFI开关。
Error20,//定位失败,错误码:20。
Error21,//IO 操作异常
Error22,//连接异常
Error23,//连接超时
Error24,//无效的参数
Error25,//空指针异常
Error26,//URL异常
Error27,//未知主机
Error28,//连接服务器失败
Error29,//通信协议解析错误
Error30,//http 连接失败
Error31,//未知的错误
Error32,//Key鉴权验证失败,请检查key绑定的sha1值、包名与apk信息是否对应,或通过高频问题查找相关解决办法。
Error33,//没有获取到设备的定位权限
Error34,//无法获取城市信息
Error35,//当前ip请求次数超过配额
}
/// <summary>
/// 错误信息
/// </summary>
public enum ErrorMessage
{
异常错误 = -1,
定位成功 = 0,
一些重要参数为空,
定位失败_由于仅扫描到单个WIFI_且没有基站信息,
获取到的请求参数为空_可能获取过程中出现异常,
请求服务器过程中的异常_多为网络情况差_链路不通导致,
请求被恶意劫持,
定位服务返回定位失败,
Key鉴权失败,
AndroidException常规错误,
定位初始化时出现异常,
定位客户端启动失败,
定位时的基站信息错误,
缺少定位权限,
定位失败_由于未获得WIFI列表和基站信息_且GPS当前不可用,
GPS定位失败_由于设备当前GPS状态差,
定位结果被模拟导致定位失败,
当前POI检索条件_行政区划检索条件下_无可用地理围栏,
定位失败_错误码_17,
定位失败_由于手机WIFI功能被关闭同时设置为飞行模式,
定位失败_由于手机没插sim卡且WIFI功能被关闭,
定位失败_错误码_20,
IO操作异常,
连接异常,
连接超时,
无效的参数,
空指针异常,
URL异常,
未知主机,
连接服务器失败,
通信协议解析错误,
Http连接失败,
未知的错误,
Key鉴权验证失败_请检查Key绑定的sha1值_包名与Apk信息是否对应_或通过高频问题查找相关解决办法,
没有获取到设备的定位权限,
无法获取城市信息,
当前IP请求次数超过配额,
}
/// <summary>
/// 安卓返回数据组成的地址结构
/// </summary>
public struct AMapLocationInfo
{
public int NErrorCode;//错误码
public string SErrorCode;//错误码
public string SIdAddr;//地址
public string SCountry;//国家
public string SProvince;//省份为
public string SCity;//城市为
public string SDistrict;//城区为
public string SStreet;//街道为
public string SStreetNum;//街道牌号为
public string SCityCode;//城市编码为
public string SAdCode;//地区编码为
public string SAoiInfo;//定位AOI信息为
public double Longitude;//经度
public double Latitude;//纬度
}
调用安卓代码:
/// <summary>
/// 调用Android的获取地址的代码
/// </summary>
public class AMapLocation
{
private AndroidJavaClass _jc;
private AndroidJavaObject _jo;
// 定义一个静态变量来保存类的实例
private static AMapLocation _instance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private AMapLocation()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static AMapLocation Instance
{
get
{
// 当第一个线程运行到这里时,此时会对locker对象 "加锁",
// 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
// lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
if (_instance == null)
{
lock (locker)
{
// 如果类的实例不存在则创建,否则直接返回
if (_instance == null)
{
_instance = new AMapLocation();
}
}
}
return _instance;
}
}
/// <summary>
/// 返回地址结构
/// </summary>
/// <returns></returns>
public AMapLocationInfo GetAmapLocationInfo()
{
_jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
_jo = _jc.GetStatic<AndroidJavaObject>("currentActivity");
AMapLocationInfo amap = new AMapLocationInfo();
try
{
amap.NErrorCode = GetErrorCode();
amap.SErrorCode = ((ErrorMessage)amap.NErrorCode).ToString();
amap.SIdAddr = GetLocationInfo();
amap.SCountry = GetCountry();
amap.SProvince = GetProvince();
amap.SCity = GetCity();
amap.SDistrict = GetDistrict();
amap.SStreet = GetStreet();
amap.SStreetNum = GetStreetNum();
amap.SCityCode = GetCityCode();
amap.SAdCode = GetAdCode();
amap.SAoiInfo = GetAoiInfo();
amap.Longitude = GetLongitude();
amap.Latitude = GetLatitude();
return amap;
}
catch (Exception e)
{
Debug.Log(e.Message);
amap.NErrorCode = (int)ErrorCode.Error1_;
amap.SErrorCode = ((ErrorMessage) (int) ErrorCode.Error1_).ToString();
return amap;
}
}
//在调用其他之前应该先调用该方法,因为在android中该方法会实例化定位SDK,而其他方法不会
public int GetErrorCode()
{
return _jo.Call<int>("GetErrorCode");
}
//获取纬度
public double GetLatitude()
{
return _jo.Call<double>("GetLatitude");
}
//获取经度
public double GetLongitude()
{
return _jo.Call<double>("GetLongitude");
}
//获取精度
public double GetAccuracys()
{
return _jo.Call<double>("GetAccuracys");
}
//获取具体地址
public string GetLocationInfo()
{
string s = _jo.Call<string>("GetInfo");
//if (s.Length > 32)
//{
// string sNew = s.Substring(0, 32);
// return sNew;
//}
//else
//{
// return s;
//}
return s;
}
//获得国家信息
public string GetCountry()
{
return _jo.Call<string>("GetCountry");
}
//获取省信息
public string GetProvince()
{
return _jo.Call<string>("GetProvince");
}
//获取城市信息
public string GetCity()
{
return _jo.Call<string>("GetCity");
}
//获取城区信息
public string GetDistrict()
{
return _jo.Call<string>("GetDistrict");
}
//获取街道信息
public string GetStreet()
{
return _jo.Call<string>("GetStreet");
}
//获取街道牌号信息
public string GetStreetNum()
{
return _jo.Call<string>("GetStreetNum");
}
//获取城市编码
public string GetCityCode()
{
return _jo.Call<string>("GetCityCode");
}
//获取地区编码
public string GetAdCode()
{
return _jo.Call<string>("GetAdCode");
}
//获取定位AOI信息
public string GetAoiInfo()
{
return _jo.Call<string>("GetAoiName");
}
}
外部请求定位代码:
using System.Text;
using UnityEngine;
using UnityEngine.UI;
namespace Assets.AMapLocation_Demo.Scripts
{
public class PrintAmapLocation : MonoBehaviour
{
[SerializeField]
private Text _txtPos;//定位信息
[SerializeField]
private InputField _inpError;//(Read Only)
[SerializeField]
private Button _btnReqPos;//请求定位按钮
private void Start()
{
_btnReqPos.onClick.AddListener(delegate
{
GetLocationInfo();
});
}
private void GetLocationInfo()
{
AMapLocationInfo amap = AMapLocation.Instance.GetAmapLocationInfo();
if (amap.NErrorCode == 0)
{
StringBuilder sb = new StringBuilder();
string sErrorCode = "错误码为:" + amap.NErrorCode + "\n";
Debug.Log("错误码为:" + sErrorCode);
string sIdAddr = "地址为:" + amap.SIdAddr + "\n";
Debug.Log("地址为:" + sIdAddr);
string sCountry = "国家为:" + amap.SCountry + "\n";
Debug.Log("国家为:" + sCountry);
string sProvince = "省份为:" + amap.SProvince + "\n";
Debug.Log("省份为:" + sProvince);
string sCity = "城市为:" + amap.SCity + "\n";
Debug.Log("城市为:" + sCity);
string sDistrict = "城区为:" + amap.SDistrict + "\n";
Debug.Log("城区为:" + sDistrict);
string sStreet = "街道为:" + amap.SStreet + "\n";
Debug.Log("街道为:" + sStreet);
string sStreetNum = "街道牌号为:" + amap.SStreetNum + "\n";
Debug.Log("街道牌号为:" + sStreetNum);
string sCityCode = "城市编码为:" + amap.SCityCode + "\n";
Debug.Log("城市编码为:" + sCityCode);
string sAdCode = "地区编码为:" + amap.SAdCode + "\n";
Debug.Log("地区编码为:" + sAdCode);
string sAoiInfo = "定位AOI信息为:" + amap.SAoiInfo + "\n";
Debug.Log("定位AOI信息为:" + sAoiInfo);
string sLongitudes = "经度为:" + amap.Longitude + "\n";
Debug.Log("经度为:" + sLongitudes);
string sLatitudes = "纬度为:" + amap.Latitude + "\n";
Debug.Log("纬度为:" + sLatitudes);
sb.Append(sIdAddr);
sb.Append(sCountry);
sb.Append(sProvince);
sb.Append(sCity);
sb.Append(sDistrict);
sb.Append(sStreet);
sb.Append(sStreetNum);
sb.Append(sCityCode);
sb.Append(sAdCode);
sb.Append(sAoiInfo);
sb.Append(sLongitudes);
sb.Append(sLatitudes);
_txtPos.text = sb.ToString();
}
else
{
_txtPos.text = ((ErrorMessage) amap.NErrorCode).ToString();
}
}
}
}
- 在此之前可以先把之前导出的jar包导入到unity中,否则安卓中找不到这些方法。
- 在 unity中,我们新建一个Plugins文件夹,Plugins下面又建Android文件夹,Android文件夹下再建一个bin文件夹,我们将我们导出的jar包放进这个文件夹下,然后我们在eclipse中的res文件复制一份放入Android,libs文件中的高德定位包复制一份放入Android。也要把AndroidManifest.xml 放进Android目录下。详细情况如下:
- unity创建keystore(打包时请带上keystore,高德后台中需要用到):
- 打包出Apk,至此unity部分完成,但是定位仍然不会成功,因为我们还需要在高德后台中配置匹配的应用。
高德部分
- 申请高德开着后台账号,然后创建应用。
创建Key。
高德会要你提供发布版SHA1,调试版SHA1。调试版可要可不要,网上提供的大多方法都是获取的调试版安全码SHA1,包括高德平台提供的教程
这里主要讲如何获取自己应用的发布版SHA1.
注意发布版SHA1与PackageName别填错
PackageName与你的项目包名一致
填写发布版的安全码以及包名,跟unity中相匹配:https://lbs.amap.com/faq/top/hot-questions/249
sha1获取方法:
(1)首先需要刚刚unity创建的keystore。
(2)打开cmd,cd 到自己存放keystore的目录下,
例如我是放在D盘下, 然后 keytool -list -v –keystore + 你自己的Keystore
如果不行 就使用
C:\Program Files\Java\jdk1.8.0_151\bin>keytool -list -v -keystore F:\Company_TS\Other\Demo_AMapLocation\Assets\KeySore\AMapLocation.keystore
说明:C:\Program Files\Java\jdk1.8.0_151\bin>是需要进入到你的Android studio所使用的Java的jdk目录中,然后keytool -list -v -keystore是指令,F:\Company_TS\Other\Demo_AMapLocation\Assets\KeySore\AMapLocation.keystore是你使用unity创建的keystore的文件
这样就可以获取到你的sha1码,网上都有很多教程,可以去看看。申请成功后即可替换掉AndroidManifest中的sha1码。
高德部分也到此为止。
都配置好之后,就可以运行刚刚打出来的apk包,这里给出展示:
笔者在这片博客中,总结了网上很多的教程最终踩坑成功,在此记录下来,各位小伙伴觉得有用可以收藏下。
最后附上使用Android Studio 导Jar包的教程(笔者朋友手打):链接:
https://pan.baidu.com/s/1pPaRH0N4IXZUShOkgXhi_Q 密码:8yt1
如果侵权,请及时联系!