# Unity3d使用BaiduAndroidSDK

Unity3d自身的定位服务不太稳定,想到使用百度的定位服务,但是百度只提供AndroidSDK和IOS的SDK,这个时候就需要:

  1. Android开发接入百度SDK。
  2. 让Android开发的定位打包放入Unity3d。
  3. Unity3d使用Android模块中的定位服务。

# 基本环境

  1. Android开发使用Android Studio 4.1。
  2. Unity3d版本是2019.4.13f1c1。

# 操作步骤

# Android接入百度SDK

  1. 新建一个工程,注意MinimumSDK选择最小的。

    AndroidCreateProject

  2. 因为我们后面是要把定位服务作为模块打包到Unity3d,所以我们需要创建一个module,具体操作是File->New->New Module->Android Library,同样MinimumSDK选择最小的。

    NewModule

  3. 准备工作做好了,就开始在Android Studio接入百度SDK了,这里参考的是百度地图AndroidStudio配置 (opens new window)

  4. 百度开放平台SDK (opens new window)下载相应SDK,并拷贝到模块下的libs目录中。

    AndroidSDKLib

  5. 配置模块中的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
  6. 在模块中的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

    最后效果为:

    BuildGradle1

# Android接入Unity3d

这部分参考内容为:Android接入Untiy3d (opens new window)

当我们想把Android模块打包放入Unity3d中时,需要一套中间层,是Unity3d给Android留的接口:

  1. 导入Unity3d的包:复制下面目录中的classes.jar文件到模块中的libs目录下:

    Unity3d\engines\2019.4.13f1c1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes

    Unity3dClasses

    注意Variations目录下有mono和il2cpp,具体选用哪个,可以看Unity3d PlayerSetting中其他设置->脚本后端->mono还是il2cpp。

  2. 注意从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
  3. 添加获取定位的核心类:

    mainClass

    1. MyUnityPlayerActivity是由UnityPlayerActivity.java改名的。

    2. 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
      80
    3. MyLocationListener.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

  1. 上面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
  2. 将上面的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作为程序入口。有两种方式:

    1. 到Unity3d\engines\2019.4.13f1c1\Editor\Data\PlaybackEngines\AndroidPlayer\Apk中复制UnityManifest.xml到Asset/Plugins/Android/目录下,进行修改。
    2. 在玩家设置中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
  3. 在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,前面是得到一个类对象,只能获取类中静态成员,后面相当于把类实例化,能获取类中的所有成员变量。

  4. 在Unity3d中打包apk,放到手机或者模拟器上进行测试,注意直接在PC上运行是不行的。