Unity3D接入Android第三方SDK流程

一、本例子中使用的Android Studio为3.2.0版本,Unity为2018.3.12版本

二、Unity3D调用SDK

1、一般第三方SDK都会有一个暴露给接入方(即Unity3D)的一个接口类,该类中包含了一些SDK功能的各个调用方法,例如下面这个SDK接口类中包含了初始化、登录、登出三个功能的接入类,里面的每个方法跟参数都加了注释;

先看SDK库工程目录,mysdk是SDK库工程,app是一个依赖于SDK库工程的demo,其中只有一个MainActivity类,便于开发时进行测试,mysdk中只有一个MySDkPlatform类,这个类就是unity接入需要调用的接口类;

        Unity3D接入Android第三方SDK流程

/**
 * 类说明:unity接入SDK的接口类
 */
public class MySDkPlatform {
    
    private static String gameObjectName;//unity传过来的接收SDK回调的类名,SDK根据此类名调用unity类中的方法
    private static String unityInitCallbackName;//unity传过来的接收SDK回调的类中的方法,SDK根据此方法名调用unity中的方法
    private String unityLoginCallbackName;//同上
    private String unityLogoutCallbackName;//同上
    
    //单例模式
    public static MySDkPlatform mySDkPlatform;
    public static MySDkPlatform getInstance(){
        if (mySDkPlatform == null) {
            mySDkPlatform = new MySDkPlatform();
        }
        return mySDkPlatform;
    }

    //初始化
    public void init(Activity activity){
        System.out.println("调用了mysdk的初始化方法");
        //该方法的三个参数
        //gameObjectName:unity中的gameObject的类名
        //unityInitCallbackName:unity中gameObject绑定的c#脚本里的方法名
        //第三个参数:SDK向unity传递的字符串
        UnityPlayer.UnitySendMessage(gameObjectName,unityInitCallbackName,"这是SDK初始化结果回调");
    }

    //登录
    public void login(String arg1){
        System.out.println("调用了mysdk的登录方法;arg1 = "+arg1);
        UnityPlayer.UnitySendMessage(gameObjectName,unityInitCallbackName,"这是SDK登录结果回调");
    }

    //登出,静态,跟以上非静态方法做不同例子演示
    public static void logout(String arg1){
        System.out.println("调用了mysdk的登出方法");
        UnityPlayer.UnitySendMessage(gameObjectName,unityInitCallbackName,"这是SDK登出结果回调");
    }

    //拿到unity的类名
    public void setGameObjectName(String gameObjectName){
        this.gameObjectName = gameObjectName;
    }
    //拿到unity接收SDK初始化结果的方法名
    public void setUnityInitCallbackName(String unityInitCallbackName) {
        this.unityInitCallbackName = unityInitCallbackName;
    }
    //拿到unity接收SDK登录结果的方法名
    public void setUnityLoginCallbackName(String unityLoginCallbackName) {
        this.unityLoginCallbackName = unityLoginCallbackName;
    }
    //拿到unity接收SDK登出结果的方法名
    public void setUnityLogoutCallbackName(String unityLogoutCallbackName) {
        this.unityLogoutCallbackName = unityLogoutCallbackName;
    }
}

2、类中的UnityPlayer.UnitySendMessage(gameObjectName,callbackName,arg1)方法是Unity中的一个unity-classes.jar包下的方法,SDK需要引入该包才能编译,在引入过程中需要注意,因为unity中已经有这个jar包,SDK库工程只在编译的时候需要用到,真正接入的时候,只需要拷贝SDK库工程生成的aar包即可,不需要把unity-classes.jar编译进去,否则会报异常,引入unity-classes.jar方法如下:

(1)新建一个unity3dlibs文件夹,保证与工程中的libs不重名,将unity-classes.jar放入该文件夹下

Unity3D接入Android第三方SDK流程

(2)在工程的build.gradle中加入依赖

//添加一个本地仓库,并将unity3dlibs目录作为仓库地址
repositories{
    flatDir {
        dirs 'unity3dlibs'
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    testImplementation 'junit:junit:4.12'

    compileOnly files('unity3dlibs/unity-classes.jar')//只在编译的时候用到
}

(3)清单文件;如果SDK中需要在manifest中application根节点**册信息,在清单文件中需要编写以下代码:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sdk.mysdk">

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        //Unity启动入口activity
        <activity android:name="com.unity3d.player.UnityPlayerActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

清单文件中注册UnityPlayerActivity是为了将SDK做成符合Unity接入的plugins,Unity编译时会将自身生成的manifest和SDK的manifest进行合并,但SDK的manifest优先级比较高,所以需要SDK在manifest中注册启动的UnityPlayerActivity。                     (注:如果SDK中有Activity并且继承了UnityPlayerActivity,则启动应用的main入口需要改为SDK的Activity)

三、SDK调用Unity3D

1、在Unity中新建一个脚本,调用MySDkPlatform中的方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class NewBehaviourScript : MonoBehaviour
{

    AndroidJavaClass unityPlayer;
    AndroidJavaObject currentActivity;

    AndroidJavaClass androidJavaClass;
    AndroidJavaObject androidJavaObject;

    // Start is called before the first frame update
    void Start()
    {
        //通过包名获取UnityPlayer,目的为了获取下面当前activity对象用(固定写法,不用修改);
        //如果SDK的activity继承了UnityPlayerActivity,这里填写activity的包名路径,然后通过
        //unityPlayer即可获取activity中的静态方法,
        unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        //通过unityPlayer获取当前的activity (注:固定写法,不用修改,如果SDK不需要获取当前的 
        //activity实例,则这两行代码可以省去)
        currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

        //获取SDK的MySDkPlatform类,静态方法可以直接使用该对象调用方法
        androidJavaClass = new AndroidJavaClass("com.sdk.mysdk.MySDkPlatform");
        //拿到MySDkPlatform类中的单例对象,调用MySDkPlatform中的非静态方法,如果调用静态方
        //法,可以直接使用androidJavaClass.call(“方法名”)来获取
        androidJavaObject = androidJavaClass.CallStatic<AndroidJavaObject>("getInstance");

        //将当前脚本所绑定的类名、SDK调用unity中的初始化回调方法名、登录回调方法名、登出回调方法名传递给SDK,
        //SDK通过UnityPlayer.UnitySendMessage(Object, Method, str)方法调用unity对应的方法;
        androidJavaObject.Call("setGameObjectName", "Main Camera");
        androidJavaObject.Call("setUnityInitCallbackName", "initCallback");
        androidJavaObject.Call("setUnityLoginCallbackName", "showAdGifCallback");
        androidJavaObject.Call("setUnityLogoutCallbackName", "showAdGifCallback");

        //SDK初始化
        Button btn = GameObject.Find("Button").GetComponent<Button>();
        btn.onClick.AddListener(() => 
        {
            Debug.Log("-->初始化");
            //调用初始化方法,传入当前activity对象
            androidJavaObject.Call("init", currentActivity);
        });

        //登录
        Button btn2 = GameObject.Find("Button2").GetComponent<Button>();
        btn2.onClick.AddListener(() =>
        {
            androidJavaObject.Call("login", "unity调用了SDK的登录");
        });

        //登出
        Button btn3 = GameObject.Find("Button3").GetComponent<Button>();
        btn3.onClick.AddListener(() =>
        {
            //这里使用的是androidJavaClass调用的SDK的登出,在SDK接口类中logout方法为静态的,                
            //所以这里可以使用androidJavaClass类直接调用
            androidJavaClass.Call("logout", "unity调用了SDK的登出");
        });

    }

    //SDK初始化后,会调用该方法,参数为回调结果
    void initCallback(string callback)
    {
        Debug.Log("-->收到SDK初始化的回调:"+callback);
    }

    //SDK登录后,会回调该方法,参数为回调结果
    void loginCallback(string callback)
    {
        Debug.Log("-->收到SDK登录的回调:" + callback);
    }

    //SDK登出后,会回调该方法,参数为回调结果
    void logoutCallback(string callback)
    {
        Debug.Log("-->收到SDK登出的回调:" + callback);
    }

    // Update is called once per frame
    void Update()
    {

    }
}

四、打包

1、方式一:SDK打成plugins给Unity

把SDK编译成aar,以及manifest放入Unity对应的Assets文件夹下的plugins下的Android下,以及libs下,没有的文件夹自己新建一个,目录对应如下:

Unity3D接入Android第三方SDK流程

Manifest放入Android文件夹下(如上图)

Unity3D接入Android第三方SDK流程

SDK的aar包放入libs文件夹下(如上图)

配置好以上步骤即可开始打包编译;

2、方式二:Unity导出安卓工程接入SDK(studio版)

这种方式接入更为简单,将SDK的aar包拷贝到游戏工程下的libs下,并在gradle中添加aar依赖,在Manifest清单文件中,将自己的注册信息拷贝到游戏工程中直接打包即可;(注:SDK工程中unity-classes.jar不需要拷贝进去,导出的安卓游戏工程中已经有了这个jar包)