# Unity3d使用BaiduAndroidSDK
Unity3d自身的定位服务不太稳定,想到使用百度的定位服务,但是百度只提供AndroidSDK和IOS的SDK,这个时候就需要:
- Android开发接入百度SDK。
- 让Android开发的定位打包放入Unity3d。
- Unity3d使用Android模块中的定位服务。
# 基本环境
- Android开发使用Android Studio 4.1。
- Unity3d版本是2019.4.13f1c1。
# 操作步骤
# Android接入百度SDK
新建一个工程,注意MinimumSDK选择最小的。
因为我们后面是要把定位服务作为模块打包到Unity3d,所以我们需要创建一个module,具体操作是File->New->New Module->Android Library,同样MinimumSDK选择最小的。
准备工作做好了,就开始在Android Studio接入百度SDK了,这里参考的是百度地图AndroidStudio配置 (opens new window)。
在百度开放平台SDK (opens new window)下载相应SDK,并拷贝到模块下的libs目录中。
配置模块中的AndroidManifest.xml为:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.defaultcompany.mylibrary"> <!-- 这个权限用于进行网络定位--> <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.WRITE_EXTERNAL_STORAGE"></uses-permission> <!-- 访问网络,网络定位需要上网--> <uses-permission android:name="android.permission.INTERNET"></uses-permission> <application> <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"> </service> <meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="开发者的API_Key" > </meta-data> <activity android:name="com.defaultcompany.mylibrary.unityPlugin"> </activity> </application> </manifest>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31在模块中的build.gradle中的android{}添加:
sourceSets{ main{ jniLibs.srcDir 'libs' jni.srcDirs = [] //disable automatic ndk-build } }
1
2
3
4
5
6在dependencies中添加:
implementation files('libs/BaiduLBS_Android.jar')
1最后效果为:
# Android接入Unity3d
这部分参考内容为:Android接入Untiy3d (opens new window)。
当我们想把Android模块打包放入Unity3d中时,需要一套中间层,是Unity3d给Android留的接口:
导入Unity3d的包:复制下面目录中的classes.jar文件到模块中的libs目录下:
Unity3d\engines\2019.4.13f1c1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes
注意Variations目录下有mono和il2cpp,具体选用哪个,可以看Unity3d PlayerSetting中其他设置->脚本后端->mono还是il2cpp。
注意从Unity3d 2019.3后,UnityPlayerActivity.java被从classes包单独拿出来,需要单独导入,并修改文件名称,其所在目录如下:
Unity3d\engines\2019.4.13f1c1\Editor\Data\PlaybackEngines\AndroidPlayer\Source\com\unity3d\player
在build.gradle的dependencies中包含进去:
compileOnly files('libs/classes.jar')//只在编译的时候用到
1添加获取定位的核心类:
MyUnityPlayerActivity是由UnityPlayerActivity.java改名的。
unityPlugin.java为初始化类,文件内容为:
package com.defaultcompany.mylibrary; import android.os.Bundle; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.unity3d.player.UnityPlayer; import com.unity3d.player.MyUnityPlayerActivity; public class unityPlugin extends MyUnityPlayerActivity { public LocationClient mLocationClient = null; private MyLocationListener myListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); myListener = new MyLocationListener(); mLocationClient = new LocationClient(getApplicationContext()); //声明LocationClient类 mLocationClient.registerLocationListener(myListener); //注册监听函数 LocationClientOption option = new LocationClientOption(); option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy); //可选,设置定位模式,默认高精度 //LocationMode.Hight_Accuracy:高精度; //LocationMode. Battery_Saving:低功耗; //LocationMode. Device_Sensors:仅使用设备; option.setCoorType("bd09ll"); //可选,设置返回经纬度坐标类型,默认GCJ02 //GCJ02:国测局坐标; //BD09ll:百度经纬度坐标; //BD09:百度墨卡托坐标; //海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标 option.setScanSpan(1000); //可选,设置发起定位请求的间隔,int类型,单位ms //如果设置为0,则代表单次定位,即仅定位一次,默认为0 //如果设置非0,需设置1000ms以上才有效 option.setOpenGps(true); //可选,设置是否使用gps,默认false //使用高精度和仅用设备两种定位模式的,参数必须设置为true option.setLocationNotify(true); //可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false option.setIgnoreKillProcess(false); //可选,定位SDK内部是一个service,并放到了独立进程。 //设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true) option.SetIgnoreCacheException(false); //可选,设置是否收集Crash信息,默认收集,即参数为false option.setWifiCacheTimeOut(5 * 60 * 1000); //可选,V7.2版本新增能力 //如果设置了该接口,首次启动定位时,会先判断当前Wi-Fi是否超出有效期,若超出有效期,会先重新扫描Wi-Fi,然后定位 option.setEnableSimulateGps(false); //可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false option.setNeedNewVersionRgc(true); //可选,设置是否需要最新版本的地址信息。默认需要,即参数为true mLocationClient.setLocOption(option); //mLocationClient为第二步初始化过的LocationClient对象 //需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用 //更多LocationClientOption的配置,请参照类参考中LocationClientOption类的详细说明 mLocationClient.start(); } public static void SendMessageToUnity(String info){ UnityPlayer.UnitySendMessage("BaiduAndriodReceiveObj","receiveInfo",info); } public String getinfo(String a){ return a; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80MyLocationListener.java为定时获取位置信息类,文件内容为:
package com.defaultcompany.mylibrary; import com.baidu.location.BDAbstractLocationListener; import com.baidu.location.BDLocation; public class MyLocationListener extends BDAbstractLocationListener { @Override public void onReceiveLocation(BDLocation location) { //此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果 //以下只列举部分获取经纬度相关(常用)的结果信息 //更多结果信息获取说明,请参照类参考中BDLocation类中的说明 String sendInfo; sendInfo = String.valueOf(location.getLatitude()) + ";" + //获取纬度信息 String.valueOf(location.getLongitude()) + ";" +//获取经度信息 String.valueOf(location.getRadius()) + ";" +//获取定位精度,默认值为0.0f String.valueOf(location.getCoorType()) + ";" +//获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准 String.valueOf(location.getLocType()) + ";" +//获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明 location.getLocTypeDescription(); unityPlugin.SendMessageToUnity(sendInfo); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Android打包进Unity3d
上面Android Studio中整合进Unity3d的包后就可以进行构建,构建完了会得到一个aar文件,参考创建Android库 (opens new window),aar文件本身是一个zip文件,它必须包含的条目有:
- /AndroidManifest.xml
- /classes.jar
- /res/
- /R.txt
- /public.txt
包含的可选条目有:
- /assets/
- /libs/name.jar
- /jni/abi_name/name.so(其中 abi_name 是 Android 支持的 ABI 之一)
- /proguard.txt
- /lint.jar
- /api.jar
将上面的aar文件放入Unity3d工程中的Assets/Plugins/Android目录下,这里参考的有:Building and using plug-ins for Android (opens new window),Unity与安卓aar 包交互 (opens new window),安卓开发工具创建Module库 (opens new window)。根据Extending the UnityPlayerActivity Java Code (opens new window)在Unity3d中引入Android模块,需要在Assets/Plugins/Android目录下创建AndroidManifest.xml来为你的应用设置新的Activity作为程序入口。有两种方式:
- 到Unity3d\engines\2019.4.13f1c1\Editor\Data\PlaybackEngines\AndroidPlayer\Apk中复制UnityManifest.xml到Asset/Plugins/Android/目录下,进行修改。
- 在玩家设置中Player->发布设置->生成->CustomMainManifest打上对勾,会自动生成AndroidManifest.xml。
这里贴出所使用的AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN--> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.defaultcompany.mylibrary" xmlns:tools="http://schemas.android.com/tools"> <application> <activity android:name="com.defaultcompany.mylibrary.unityPlugin" android:theme="@style/UnityThemeSelector"> <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> </manifest>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17在Untiy3d中写Android会调用Unity3d的代码,在Untiy3d场景中有BaiduAndriodReceiveObj对象,在上面挂脚本AndroidBaiduGPS.cs:
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class AndroidBaiduGPS : MonoBehaviour { AndroidJavaObject jo; string lastLocInfo=""; // Start is called before the first frame update void Start() { jo = new AndroidJavaObject("com.defaultcompany.mylibrary.unityPlugin"); Debug.Log(jo.Call<string>("getinfo", "hi")); } // Update is called once per frame void Update() { } public void receiveInfo(string info) { if (!lastLocInfo.Equals(info)) { lastLocInfo = info; Debug.Log(info); } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31注意AndroidJavaClass和AndroidJavaObject,前面是得到一个类对象,只能获取类中静态成员,后面相当于把类实例化,能获取类中的所有成员变量。
在Unity3d中打包apk,放到手机或者模拟器上进行测试,注意直接在PC上运行是不行的。