美文网首页
Unity 与 Android交互通信 之OPPO篇

Unity 与 Android交互通信 之OPPO篇

作者: 北京朝阳区精神病院院长 | 来源:发表于2020-07-09 19:07 被阅读0次

    前言

      本人是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

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

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


      androidPro.png

    3.2AS清单文件配置注意点

    清单文件配置一定要有<meta-data android:name="unityplayer.UnityActivity" android:value="true" />,
    不然会有莫名其妙的奇怪问题

    <?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

    结语

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

    相关文章

      网友评论

          本文标题:Unity 与 Android交互通信 之OPPO篇

          本文链接:https://www.haomeiwen.com/subject/xfcwqktx.html