Unity与 Android交互通信 之OPPO篇

前言

  本人是Android SDK方向的开发者,在游戏发行公司工作,因公司业务需求经常与Unity进行交互,借此机会让大家伙了解下Unity与Android交互的一些基础知识。

1.开发环境说明

  Unity和Android Studio所涉及到的SDK、JDK、NDK安装步骤新建工程等操作的不做说明

  Android Studio(AS)版本: 3.2.1

  Unity版本: 2018.2.0f2 破解版

2.实现效果

 Unity调用Andoroid网游OPPO SDK API 实现 登录 支付 退出 等交互 效果如下图

oppo_login.png

oppo_pay.png
oppo_exit.png

3.Android篇

要在Unity游戏项目中调用安卓API,有两种方式:

  1. Unity项目导出为Android工程(Build System选择Gradle),然后在AS中进行二次开发,添加交互功能。这样的方式开发起来很灵活,改动起来也很方便,但是就是很麻烦,因为每次改动都要打一回安卓工程。

  2. 将扩展功能打成jar包,然后将jar包导入到Unity中,直接使用。这样的方式,一次性写好通用交互层 ,不用频繁打安卓工程。

下面给大家说下第二种方式

3.1Android 工程

1.既然要和Android oppo SDK交互 ,需要去开发者申请对应参数和 SDK资源文档

 OPPO开发者网游SDK下载地址:https://open.oppomobile.com/wiki/doc#id=10470

2.AS新建一个工程,因为需要和Unity交互(用到其中的类),因此需要把它提供的class.jar包放到AS工程libs下
我Unity安装默认路径在D盘 D:\Unity 所以下面路径取决你Unity安装路径

 D:\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Development\Classes\class.jar

3.需要按oppo 开发者文档要求 放入oppo资源(assets、libs和AndroidManifest.xml),然后可以按文档接口接入


androidPro.png

3.2 AS清单文件配置注意点

清单文件配置一定要有,
不然会有莫名其妙的奇怪问题

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.unity.demo">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round">
        <activity
            android:name="com.unity.demo.MainActivity"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.Translucent.NoTitleBar"
            android:configChanges="orientation|keyboardHidden|screenSize|screenSize|navigation">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
       
        <!--oppo配置开始-->
        <meta-data
            android:name="debug_mode"
            android:value="false"/>
        <!--  日志开关,发布时候设置为false  -->
        <meta-data
            android:name="is_offline_game"
            android:value="false"/>
        <!--  true:单机游戏   false:网游  -->
        <meta-data
            android:name="app_key"
            android:value=""/>
        <!-- appKey,游戏上线时请务必替换成游戏自身的appkey -->
        <uses-library android:name="org.apache.http.legacy" android:required="false" />
        <!--oppo配置结束-->
    </application>
</manifest>

3.3Android 交互层代码编写

  首先需要让MainActivity继承UnityPlayerActivity,因为Unity导出的app的视图展示需要在UnityPlayerActivity下。

import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
import com.nearme.game.sdk.GameCenterSDK;
import com.nearme.game.sdk.callback.ApiCallback;
import com.nearme.game.sdk.callback.GameExitCallback;
import com.nearme.game.sdk.common.model.biz.PayInfo;
import com.nearme.game.sdk.common.model.biz.ReportUserGameInfoParam;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
  *android 与Unity交互层  数据均为模拟游戏数据
  */
public class MainActivity extends UnityPlayerActivity {
    private static String appSecret = ""; //此处应该填写 oppo后台申请下来的appSecret参数
    public final  String TAG="UnityForOppo";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        doInit();  
    }
    /**
     * 初始化
     */
    public void doInit(){
        Log.i(TAG,"doInit");
        GameCenterSDK.init(appSecret, this);
        Toast.makeText(MainActivity.this,"初始化成功",Toast.LENGTH_LONG).show();
    }

    /**
     * 登录
     */
    public void doLogin(){
        Log.i(TAG,"doLogin");
        GameCenterSDK.getInstance().doLogin(this, new ApiCallback() {
            //登录成功的回调
            @Override
            public void onSuccess(String msg) {
                Toast.makeText(MainActivity.this,"获取登录状态:====="+msg.toString(),Toast.LENGTH_LONG).show();
                GameCenterSDK.getInstance().doGetTokenAndSsoid(new ApiCallback() {
                    @Override
                    public void onSuccess(String resultMsg) {
                        Log.i(TAG,"登录成功获取的msg:====="+resultMsg.toString());
                        String jsonString = "";
                        try {
                            JSONObject   json = new JSONObject(resultMsg);
                            String token = json.getString("token");
                            String ssoid = json.getString("ssoid");
                            json.put("token", URLEncoder.encode(token, "UTF-8"));
                            json.put("ssoid",json.getString("ssoid"));
                       
                            jsonString=json.toString();
                            Log.i(TAG,"登录成功向Unity发送消息:====="+jsonString);
                            /**
                             * 向Unity传递消息
                             * 第1个参数为Unity场景中用于接收android消息的对象名称
                             * 第2个参数为对象上的脚本的一个成员方法名称(脚本名称不限制)
                             * 第3个参数为Unity方法的参数
                             */
                            UnityPlayer.UnitySendMessage("AndroidSDKListener", "LoginCallback", jsonString);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onFailure(String resultMsg, int code) {
                        UnityPlayer.UnitySendMessage("AndroidSDKListener", "LoginCallback", resultMsg);
                    }
                });

            }
            //登录失败的回调
            @Override
            public void onFailure(String msg, int code) {
                //回调oppo登录失败,把失败的消息发给Unity
                UnityPlayer.UnitySendMessage("AndroidSDKListener", "LoginCallback", msg);
            }
        });
    }

    /**
     * 支付(唤起支付参数为模拟数据 真实应该由游戏服务器端传入)
     */
    public void doPay(){
        Log.i(TAG,"doPay");
        String orderId=System.currentTimeMillis()+"";//订单号 建议由游戏服务器提供
        String productDesc="优惠月礼包"; //商品描述
        String  productName="钻石"; //商品名称
        String  GAME_OPPO_URL="http://192.168.1.1:8080/order/oppo";//支付回调地址,由服务器提供
        //参数1  游戏订单号  参数2 附加参数 传什么都可以 这里传入订单号  参数3 为支付金额 单位分
        PayInfo payInfo = new PayInfo(orderId, orderId, 1);
        payInfo.setProductDesc(productDesc);
        payInfo.setProductName(productName);
        payInfo.setCallbackUrl(GAME_OPPO_URL);
        GameCenterSDK.getInstance().doPay(this, payInfo, new ApiCallback() {

            @Override
            public void onSuccess(String msg) {
                Log.i(TAG,"PAY SUC");
            }

            @Override
            public void onFailure(String msg, int code) {
                Log.i(TAG,"PAY Fail========"+msg);
            }
        });
    }

    /**
     * 上报游戏数据 给OPPO
     */
    public  void doSubUserInfo (){
        Map<String, String> mRoleInfo =new HashMap<String, String>();
        mRoleInfo.put("type", "createRole");// 以下场景必传[enterServer(登录),levelUp(升级),createRole(创建角色),exitServer(退出)]
        mRoleInfo.put("roleId", "123456");// 当前登录的玩家角色ID,若无,可传入userid
        mRoleInfo.put("roleName", "天下第一");// 当前登录的玩家角色名,不能空
        mRoleInfo.put("roleLevel", "10");// 当前登录的玩家角色等级,不能为空,必须为数字,且不能为null,若无,传入0
        mRoleInfo.put("serverId", "1001");// 当前登录的游戏区服ID,不能为空,必须为数字,若无,传入0
        mRoleInfo.put("serverName", "Oppo32服");// 当前登录的游戏区服名称,不能为空,长度不超过50,不能为null,若无,传入“无”

        if (mRoleInfo != null && "createRole".equals(mRoleInfo.get("type")) || ("enterServer".equals(mRoleInfo.get("type"))) || ("levelUp".equals(mRoleInfo.get("type")))) {
            String serverId = mRoleInfo.get("serverId");
            String serverName = mRoleInfo.get("serverName");
            String roleId = mRoleInfo.get("roleId");
            String roleName = mRoleInfo.get("roleName");
            String roleLevel = mRoleInfo.get("roleLevel");
            GameCenterSDK.getInstance().doReportUserGameInfoData(new ReportUserGameInfoParam(roleId, roleName, Integer.valueOf(roleLevel), roleId, roleName, "", new TreeMap<String, Number>()), new ApiCallback() {
                @Override
                public void onSuccess(String msg) {
                }
                @Override
                public void onFailure(String msg, int code) {

                }
            });
        }

    }
    /**
     * 退出游戏
     */
    public void  doExitGame(){
        Log.i(TAG,"DoExitGame");
        GameCenterSDK.getInstance().onExit(this,new GameExitCallback() {
            @Override
            public void exitGame() {
                finish();
                System.exit(0);
                android.os.Process.killProcess(android.os.Process.myPid());
            }
        });
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.i(TAG, "onKeyDown");
        if ((keyCode == KeyEvent.KEYCODE_BACK)) {
            Log.i(TAG, "DoExitGameDoExitGameDoExitGame");
            doExitGame();
            return false;
        } else {
            return super.onKeyDown(keyCode, event);
        }
    }

3.4AS生成JAR包

 app/build.gradle 下加入生成jar包Task

task makeJar(type: Copy) {
    def jarPath = 'build/intermediates/packaged-classes/debug/'  
    def jarName = 'classes.jar'
    from(jarPath)
    into('build/outputs/')  //输出路径为outputs/
    include(jarName)
    rename(jarName, 'unityPlug-1.4.jar') //重名为xxx.jar
}

建议: 先Rebuild Project一下生成packaged-classes文件,然后在Gradle \other下能看到makeJar 点击执行Task

makeJar.png

4.Unity篇

  1. 新建一个Unity工程,在Assets目录下新建Plugins/Android/ 目录
  2. 将Android中的assets、res、AndroidManifest.xml 、libs下的gamesdk-20190910.aar还有生成的unityPlug-1.4.jar 放入Assets/Plugins/Android目录下(在Unity这些东西都会被当做资源处理)
  3. 在Assets/Scenes/ 建立一个场景,在场景上创建一个Canvas,并创建一个名为"AndroidSDKListener"的对象,在AndroidSDKListener之下再放三个按钮触发安卓 登录 支付 退出游戏
  4. 创建一个btnClick.cs文件,将脚本挂载在AndroidSDKListener对象 如图所示

android.png

scenes.png

unityPro.png


4.1 Unity中C#代码实现

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class btnClick : MonoBehaviour
{

    private AndroidJavaClass jc;
    private AndroidJavaObject jo;
    private Button btnLogin;
    private Button btnPay;
    private Button btnExitGame;
   
    public void Start()
    {   
        //固定写法
        jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
        btnLogin = transform.Find("BtnLogin").GetComponent<Button>(); //登录
        btnPay= transform.Find("BtnPay").GetComponent<Button>();   //支付
        btnExitGame = transform.Find("BtnExit").GetComponent<Button>();   //退出游戏
        btnLogin.onClick.AddListener(OnBtnLoginClickHandler);
        btnPay.onClick.AddListener(OnBtnPayClickHandler);
        btnExitGame.onClick.AddListener(OnBtnExitGameClickHandler);
    }
  
    /**
      * 登录调用
     */
    private void OnBtnLoginClickHandler()
    {
        jo.Call("doLogin");
    }
   
  /**
      * 支付调用
     */
     private void OnBtnPayClickHandler()
     {
         jo.Call("doPay");
     }

    /**
     * 退出游戏点击调用
     */
    private void OnBtnExitGameClickHandler()
    {
        jo.Call("doExitGame");
       // Application.Quit();//调用C#退出应用
    }
 
    /**
      *接收从安卓端传过来消息
      *方法体 UnityPlayer.UnitySendMessage("AndroidSDKListener", "LoginCallback", msg);和参数2对应
     */
    public  void LoginCallback(string msg)
    {
        Debug.Log("Login_with_msg : " + msg);
    }
}

4.2 打包测试

File ----Build Settings----Android----Player Settings -----Build System-----选择Internal (直接生成APK整包)
配置好签名(jdk sdk ndk均早配置好了) 选择bulid 静候几秒 完整的APK就搞定了
登录、支付、 退出效果 上面已经展示了,看下安卓登录回调成功后向Unity发送的消息

login_msg.png

结语

  记录下自己的学习和工作经验,分享给有需要的人。如果有那里写的不对或者不理解,欢迎大家的指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: AndroidUnity之间的交互可以实现在Unity运行时,调用Android原生代码来实现一些功能。在Android端可以使用 Android Java API 调用 Unity 的代码。而在Unity端,可以使用 C# 代码来调用 AndroidJava API。这种双向调用可以实现一些比较复杂的跨平台应用,例如在Unity中展示Android硬件设备的信息或者调用相机、传感器等硬件设备来实现某些功能。 例如,在Android端上获取某个传感器的数据,然后传到Unity中,就可以借助Java Native Interface(JNI)来实现。具体实现方式如下: 1. Android端: * 创建一个Native方法,在其中读取传感器数据; * 创建一个Java类,将该Native方法和Unity相关的方法绑定; * 在Unity中调用Java类中的方法,以获取传感器数据。 2. Unity端: * 在C#代码中,调用AndroidJava API,以实现数据传输; * 实现Unity的渲染逻辑,以展示从Android端传输过来的数据。 需要注意的是,为了确保代码的正确性和稳定性,一定要在调用之前做好详细的测试工作。 ### 回答2: AndroidUnity是两个流行的软件开发平台,它们都具有广泛的应用。将它们结合起来,可以为应用开发者带来无限的可能性。 在androidunity交互过程中,最主要的问题是如何将android中的数据传递到unity中。这主要分为两种情况:一种是在Unity中使用安卓API(Java代码),另一种是安卓使用Unity中的可编程元素(C#代码)。 在第一种情况下,可以使用UnityJava接口来实现,编写类似于以下的Java代码: ``` UnityPlayer.UnitySendMessage("GameObjectName", "MethodName", "Message"); ``` 其中,UnitySendMessage方法将消息发送给Unity中的一个GameObject,它接受两个参数,分别是接受消息的对象名和它上面的方法名。 在第二种情况下,可以使用UnityC#接口来实现。我们可以使用Unity中的SendMessage或BroadcastMessage方法来向Unity对象发送消息(这些对象必须具有MonoBehaviour脚本,否则将不会工作)。 在Android中使用Unity对象也同样简单。我们需要做的就是在Android项目中添加UnityPlayerActivity类,在此类中使用UnityPlayer类的相关方法调用Unity导出的API。 综上所述,将安卓与Unity结合起来,可以极大地扩展应用的功能性,并为用户提供更好的体验。通过上述方法可以轻松实现androidunity交互。 ### 回答3: AndroidUnity交互是现在游戏开发中非常常见的一种技术,Android作为手机操作系统的代表,提供了丰富多彩的开发接口,而Unity作为一款游戏引擎,具有着强大的游戏制作功能。两者合作可以大大提高游戏交互性和玩法。下面我们来分别了解一下AndroidUnity之间的交互方式。 首先是从AndroidUnity交互。由于Android系统是Java语言开发的,而Unity则是C#开发的,所以两者之间实现交互还需要一些中间的桥梁。目前比较常用的方式是通过JNI接口,将Java层面的信息传递到C#层面的Unity中。在Java中,你需要先获取UnityPlayer的实例,然后就可以通过UnityPlayer的方法来调用C#端的函数。具体流程如下: 1. 在Unity中编写对应的C#函数,该函数必须使用静态修饰符(static)。例如: public static void UnityMethod(string str){ Debug.Log("接收到的数据为:" + str); } 2. 在Java中,使用JNI接口调用C#函数。例如: // 获取UnityPlayer实例 UnityPlayer player = new UnityPlayer(); // 调用C#函数 player.UnitySendMessage("GameObject名字", "函数名字", "传递的参数"); UnitySendMessage方法中,第一个参数表示的是GameObject的名字,第二个参数表示的是C#函数的名字,第三个参数就是传递的参数。 其次是从UnityAndroid交互。在Unity中,通过AndroidJavaClass和AndroidJavaObject等API,可以实现调用Java层面的方法。具体流程如下: 1. 在Java中,编写需要调用的方法,这里的方法必须是public静态的。例如: public static void showAndroidToast(String msg){ Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } 2. 在Unity中,使用AndroidJavaClass和AndroidJavaObject等API来调用Java方法。例如: // 设置Context AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); // 调用Java方法 AndroidJavaClass cls = new AndroidJavaClass("com.example.androidTest.MainActivity"); cls.CallStatic("showAndroidToast", currentActivity, "传递的参数"); CallStatic方法中,第一个参数表示要调用的Java层面类的名称,第二个参数表示要调用的Java方法名称,接下来的参数就是要传递的参数。 综上所述,通过JNI和AndroidJavaClass等API,AndroidUnity之间可以很方便地进行交互,相互传递数据和调用各自的方法。这样就能够更好地完成游戏逻辑和UI界面的制作。同时,这种交互方式也为跨平台的开发提供了很好的经验和方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值