返回

接入QQSDK

申请QQ开发者账号

网址:https://connect.qq.com/index.html

登录后点击个人头像,会进入资料填写注册界面

注册完毕后并没有提交审核,是无法使用的

注册完毕后,退回首页,重新点击自己头像,可以看到自己的基本信息,然后点击右上角的修改,这时候我们可在下方看见提交审核按钮,点击后才算真正的提交完毕

创建Android项目,导出Jar

  1. 打开AndroidStudio,创建空项目(Empty Activity);

    然后修改PackageName与Unity中的打包包名相对应;

    设置Language为Java。

  2. 等待编译结束。(右下角加载进图条消失,且Sync窗口中没有红色错误)

  3. 修改App文件夹下的Build.gradle文件,注释打包方式与包名设置,并添加打包方式为library(如果没有修改打包方式,生成的将为APK,在此我们需要将工厂编译生成lib文件到Unity中使用,所以需要修改打包方式)

    //apply plugin: 'com.android.application'
    apply plugin:'com.android.library'
    
    android {
        compileSdkVersion 29
        buildToolsVersion "29.0.3"
    
        defaultConfig {
            //applicationId "com.Company.ETGame"
            minSdkVersion 16
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
        ...
    
  4. 点击Build菜单栏下的Rebuild Project,编译项目。编译完成后可以在App目录下看见新增加的build文件夹。

  5. 删除目录下的xml文件,并修改删除产生的MainActivity文件错误,将其注释掉

  6. 添加Unity的classes.jar文件到工程中

    打开Unity安装目录,搜索classes.jar(搜索结果会有四个文件,复制一个即可)

    粘贴到工程目录app/libs下,将其改名为unity-classes.jar

    右击粘贴的包,选择Add as library,引用到项目中

  7. 下载Android_SDK

    进入QQ开放平台,下载SDKhttps://wiki.connect.qq.com/sdk%E4%B8%8B%E8%BD%BD

    将其压缩包内lib文件夹下的jar复制到项目中,并重复第6步的引入工作

  8. 修改MainActivity文件(如果出现unity3d包名报红,则是上一步引用Unity的jar出错)

    package com.Company.ETGame;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Intent;
    import android.os.Bundle;
    import com.unity3d.player.*;
    
    public class MainActivity extends UnityPlayerActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //setContentView(R.layout.activity_main);
    
            GameHelper.Init(this);
            TencentQQ.Init(this);
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode,resultCode,data);
            TencentQQ.OnActivityResult(requestCode,resultCode,data);
        }
    }
    
  9. 在MainActivity的同级目录中创建以下文件:BaseUiListener、GameHelper、TencentQQ

    package com.Company.ETGame;
    
    import android.util.Log;
    
    import com.tencent.tauth.IUiListener;
    import com.tencent.tauth.Tencent;
    import com.tencent.tauth.UiError;
    
    import org.json.JSONObject;
    
    public class BaseUiListener implements IUiListener
    {
        @Override
        public void onComplete(Object o) {
            if (o==null)return;
    
            JSONObject jsonObject = (JSONObject) o;
            if (jsonObject!=null && jsonObject.length()==0)
            {
                return;
            }
            Log.d(TencentQQ.TAG, "登录成功");
            TencentQQ.LogInCallBack(jsonObject);
        }
    
        @Override
        public void onError(UiError uiError) {
            Log.d(TencentQQ.TAG, "登录失败");
            GameHelper.SendPlatformMessageToUnity(GameHelper.PLATFORM_MSG_QQLOGIN,1,0,0,"","","");
        }
    
        @Override
        public void onCancel() {
            Log.d(TencentQQ.TAG, "登录取消");
            GameHelper.SendPlatformMessageToUnity(GameHelper.PLATFORM_MSG_QQLOGIN,2,0,0,"","","");
        }
    }
    
    
    package com.Company.ETGame;
    
    import android.app.ActivityManager;
    import android.app.ActivityManager.MemoryInfo;
    import android.content.Context;
    import android.nfc.Tag;
    import android.os.Debug;
    import android.util.Log;
    
    import com.unity3d.player.UnityPlayer;
    
    import org.json.JSONException;
    import org.json.JSONObject;
    import org.json.JSONStringer;
    
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.util.jar.JarEntry;
    
    public class GameHelper {
        private static MainActivity m_Activity = null;
    
        private static String m_PlatformObject = "PlatformObject"; //Unity用于通信的物体
        private static String m_MethodName = "OnMessage"; //Unity用于接收通信的方法名
    
        public static String TAG = "GameHelper";
    
        public final static int PLATFORM_MSG_QQLOGINCALLBACK = 1;//QQ登录回调
        public final static int PLATFORM_MSG_WXLOGINCALLBACK = 1;//WX登录回调
    
        //初始化方法
        public static void Init(MainActivity activity) {
            m_Activity = activity;
        }
    
        //android发送消息到 unity
        public static void SendPlatformMessageToUnity(int iMsgId, int iParam1, int iParam2, int iParam3, String strParam1, String strParam2, String strParam3) {
            String jsonString = GetJsonStr(iMsgId, iParam1, iParam2, iParam3, strParam1, strParam2, strParam3);
            UnityPlayer.UnitySendMessage(m_PlatformObject, m_MethodName, jsonString);
        }
    
        public final static int PLATFORM_MSG_QQLOGIN = 1;//QQ登录
        public final static int PLATFORM_MSG_QQLOGOUT = 2;//QQ注销
        public final static int PLATFORM_MSG_WXLOGIN = 3;//WX登录
        public final static int PLATFORM_MSG_WXLOGOUT = 4;//WX注销
    
        //unity发送消息到 android
        public static void SendUnityMessageToPlatform(int iMsgId, int iParam1, int iParam2, int iParam3, int iParam4, String strParam1, String strParam2, String strParam3, String strParam4) {
            Log.d(TAG, "SendUnityMessageToPlatform:iMsgId:" + iMsgId + "iParaml:" + iParam1 + "iParam1:" + iParam2 + "iParam3:" + iParam3 + "iParam4:" + iParam4 + "strParam1:" + strParam1 + "strParam2:" + strParam2 + "strParam3" + strParam3 + "strParam4" + strParam4);
    
            if (m_Activity == null) {
                Log.e(TAG, "m_Activity is null");
            }
    
            switch (iMsgId) {
                case PLATFORM_MSG_QQLOGIN:
                    TencentQQ.Login();
                    break;
                case PLATFORM_MSG_QQLOGOUT:
                    TencentQQ.Logout();
                    break;
                case PLATFORM_MSG_WXLOGIN:
                    break;
                case PLATFORM_MSG_WXLOGOUT:
                    break;
            }
        }
    
        //从android获取Int类型
        public static int GetIntFromPlatform(int type) {
            switch (type) {
    
            }
            return 0;
        }
    
        //从android获取String类型
        public static String GetStringFromPlatform(int type) {
            switch (type) {
                case 1://QQ授权是否过期
                    return String.valueOf(TencentQQ.CheckAutorVaild());
                case 2://刷新QQ票据
                    return TencentQQ.RefreshSession().toString();
                case 3:
                    break;
                case 4:
                    break;
            }
            return "";
        }
    
        //从android获取Long类型
        public static long GetlongFromPlatform(int type) {
            switch (type) {
    
            }
            return 0;
        }
    
        //从android获取Long类型
        public static long GetlongFromPlatform2(int type, int iParam1, int iParam2, int iParam3, int iParam4, String strParam1, String strParam2, String strParam3, String strParam4) {
            switch (type) {
                case 1://当前系统可用内存
                    ActivityManager am = (ActivityManager) m_Activity.getSystemService(Context.ACTIVITY_SERVICE);
                    MemoryInfo mi = new MemoryInfo();
                    am.getMemoryInfo(mi);
                    return mi.availMem;
                case 2://总内存
                    return GetTotalMemory();
                case 3://应用内存
                    Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
                    Debug.getMemoryInfo(memoryInfo);
                    return memoryInfo.getTotalPss() * 1024;
            }
            return 0;
        }
    
        //获取总内存
        protected static long GetTotalMemory() {
            long tm = 0;
            try {
                RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
                String load = reader.readLine();
                reader.close();
    
                String[] totrm = load.split("kB");
                String[] trm = totrm[0].split("");
                tm = Long.parseLong(trm[trm.length - 1]) * 1024;
                return tm;
            } catch (IOException ex) {
                ex.printStackTrace();
                return 0;
            }
        }
    
    
        //通过Json对象构造字符串
        public static String GetJsonStr(int iMsgId, int iParam1, int iParam2, int iParam3, String strParam1, String strParam2, String strParam3) {
            try {
                JSONObject object = new JSONObject();
                object.put("iMsgId", iMsgId);
                object.put("iParam1", iParam1);
                object.put("iParam2", iParam2);
                object.put("iParam3", iParam3);
                object.put("strParam1", strParam1);
                object.put("strParam2", strParam2);
                object.put("strParam3", strParam3);
                return object.toString();
            } catch (JSONException e) {
                Log.e(TAG, "Json error: " + e.toString());
                return "";
            }
        }
    }
    
    
    package com.Company.ETGame;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.nfc.Tag;
    import android.text.TextUtils;
    import android.util.Log;
    
    import com.tencent.connect.common.Constants;
    import com.tencent.tauth.Tencent;
    
    import org.json.JSONObject;
    
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.net.HttpCookie;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class TencentQQ {
        private static Tencent m_Tencent;
        private static Activity m_MainActivity;
    
        public static String TAG = "TencentQQ";
    
        //需要替换成自己的APPID
        private static String APP_ID = "123456789";
    
        private static BaseUiListener m_LoginCallBack = new BaseUiListener();
    
        public static void Init(Activity activity) {
            Log.d(TAG, "TencentQQ Init");
            m_Tencent = Tencent.createInstance(APP_ID, activity.getApplicationContext());
            m_MainActivity = activity;
        }
    
        //处理低端机内存紧张可能无回调
        public static void OnActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == Constants.REQUEST_API) {
                if (requestCode == Constants.REQUEST_LOGIN) {
                    m_Tencent.handleResultData(data, m_LoginCallBack);
                }
                m_Tencent.onActivityResultData(requestCode, resultCode, data, m_LoginCallBack);
            }
        }
    
        //登录
        public static void Login() {
            Log.d(TAG, "QQLogin");
            m_Tencent.login(m_MainActivity, "all", m_LoginCallBack);
        }
    
        //注销
        public static void Logout() {
            Log.d(TAG, "QQLogout");
            m_Tencent.logout(m_MainActivity);
        }
    
        //检测登录授权是否过期
        public static boolean CheckAutorVaild()
        {
            return  m_Tencent.isSessionValid();
        }
    
        //刷新票据
        public static  JSONObject RefreshSession()
        {
            JSONObject jsonObject =m_Tencent.loadSession(APP_ID);
            if (jsonObject==null)
            {
                Login();
            }
            else
            {
                m_Tencent.initSessionCache(jsonObject);
            }
            Log.d(TAG,"RefreshSession:"+jsonObject.toString());
            return  SetSlefData(jsonObject);
        }
    
        //登录成功回调
        public static void LogInCallBack(final JSONObject jsonObject) {
            Log.d(TAG, "LogInCallBack" + jsonObject.toString());
            //开启线程用于http请求
            new Thread(new Runnable() {
                @Override
                public void run() {
                    initOpenidAndToken(jsonObject);
                    JSONObject data = SetSlefData(jsonObject);
                    GameHelper.SendPlatformMessageToUnity(GameHelper.PLATFORM_MSG_QQLOGINCALLBACK, 0, 0, 0, data.toString(), "", "");
                }
            }).start();
    
        }
    
        //设置自己的Json格式
        public static JSONObject SetSlefData(JSONObject data) {
            JSONObject jsonObject = new JSONObject();
            try {
                //令牌
                String token = data.getString(Constants.PARAM_ACCESS_TOKEN);
                //有效期
                String expires = data.getString(Constants.PARAM_EXPIRES_IN);
                //OpenID
                String openId = data.getString(Constants.PARAM_OPEN_ID);
    
                String paytoken = data.getString("pay_token");
                String pf = data.getString("pf");
                String pfkey = data.getString("pfkey");
                String expirestime = data.getString(Constants.PARAM_EXPIRES_TIME);
                String unionid = getUnionid(token);
    
                jsonObject.put("openId", openId);
                jsonObject.put("token", token);
                jsonObject.put("unionid", unionid);
                jsonObject.put("refreshtoke", "");
                jsonObject.put("expires", expires);
                jsonObject.put("paytoken", paytoken);
                jsonObject.put("pf", pf);
                jsonObject.put("pfkey", pfkey);
                jsonObject.put("expirestime", expirestime);
            } catch (Exception e) {
                Log.e(TAG, "SetSlefData:设置统一QQ票据失败!");
            }
            return jsonObject;
        }
    
        public static String getUnionid(String token) {
            String unionid = "";
            try {
                //该网址来源:https://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D
                URL url = new URL("https://graph.qq.com/oauth2.0/me?access_token=" + token + "&unionid=1");
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(5000);
                connection.setReadTimeout(5000);
    
                int code = connection.getResponseCode();
                if (code == HttpURLConnection.HTTP_OK) {
                    InputStream is = connection.getInputStream();
                    byte[] data = readStream(is);
                    String json = new String(data);
                    json = json.replace("(", "").replace(")", "").replace("callback", "");
                    JSONObject jsonObject = new JSONObject(json);
                    unionid = jsonObject.getString("unionid");
                }
    
            } catch (Exception e) {
                Log.e(TAG, "getUniodid:获取unionid错误:" + e.toString());
            }
            return unionid;
        }
    
        public static void initOpenidAndToken(JSONObject jsonObject) {
            try {
                //令牌
                String token = jsonObject.getString(Constants.PARAM_ACCESS_TOKEN);
                //有效期
                String expires = jsonObject.getString(Constants.PARAM_EXPIRES_IN);
                //OpenID
                String openId = jsonObject.getString(Constants.PARAM_OPEN_ID);
    
                if (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(expires) && !TextUtils.isEmpty(openId)) {
                    m_Tencent.setAccessToken(token, expires);
                    m_Tencent.setOpenId(openId);
                }
            } catch (Exception e) {
    
            }
        }
    
        private static byte[] readStream(InputStream inputStream) throws Exception {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(buff)) != -1) {
                bout.write(buff, 0, len);
            }
            bout.close();
            inputStream.close();
            return bout.toByteArray();
        }
    }
    
    
  10. 生成Jar包

在第3步的Build.gradle文件中添加下列脚本,用于删减复制重命名jar文件

 ......
 androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

task makeJar(type:Copy) {
 delete 'build/libs/etgame.jar'
 from('build/intermediates/aar_main_jar/debug/')
 into('build/libs/')
 include('classes.jar')
 rename('classes.jar', 'etgame.jar')
}

执行第4步的Rebuild指令

然后在Local窗口执行下列指令,然后回车:gradlew makejar

执行完毕后,我们可以在build文件夹下找到生成的libs文件夹,里面就有我们刚刚生成的jar文件

复制jar文件到Unity项目目录下

配置AndroidManifest

  1. 使用Unity的Gradle构建Android工程

    1. 将构建完成的构建工程目录\src\main\AndroidManifest.xml文件复制到Unity项目工程中

    2. 修改AndroidManifest.xml文件

      更具官方文档中需求,添加以下配置https://wiki.connect.qq.com/qq%E7%99%BB%E5%BD%95

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.Company.ETGame" xmlns:tools="http://schemas.android.com/tools" android:installLocation="preferExternal">
        <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
      
        <application android:theme="@style/UnityThemeSelector" android:icon="@mipmap/app_icon" android:label="@string/app_name" android:isGame="true" android:banner="@drawable/app_banner">
          <!--修改最后的UnityPlayerActivity为Android工程的MainActivity-->
          <activity android:label="@string/app_name" android:screenOrientation="fullSensor" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" android:hardwareAccelerated="false"
                    android:name="com.Company.ETGame.MainActivity">
            <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
              <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
          </activity>
      
          <!--添加QQ登录配置-->
            <activity
            android:name="com.tencent.tauth.AuthActivity"
            android:noHistory="true"
            android:launchMode="singleTask" >
            <intent-filter>
              <action android:name="android.intent.action.VIEW" />
              <category android:name="android.intent.category.DEFAULT" />
              <category android:name="android.intent.category.BROWSABLE" />
              <data android:scheme="tencent123456789" />
            </intent-filter>
          </activity>    
          <activity
             android:name="com.tencent.connect.common.AssistActivity"
             android:configChanges="orientation|keyboardHidden"
             android:screenOrientation="behind"
             android:theme="@android:style/Theme.Translucent.NoTitleBar" />
          <!--QQ登录-->
      
          <meta-data android:name="unity.build-id" android:value="163ac688-e1a9-43dc-8b05-954cda86df8f" />
          <meta-data android:name="unity.splash-mode" android:value="0" />
          <meta-data android:name="unity.splash-enable" android:value="True" />
        </application>
        <uses-feature android:glEsVersion="0x00020000" />
        <!--添加权限-->
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      
        <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
        <uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
        <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
      </manifest>
      

创建Unity项目

  1. PlatformScript(用于绑定在物体上,接收Android发送过来的消息,解析后发送给其他脚本),需要用到LitJson插件

    using LitJson;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace ETModel
    {
    #if !UNITY_IOS || UNITY_ANDROID
        public class PlatformScript : MonoBehaviour
        {
            private struct PlatformMsg
            {
                public int iMsgId;
                public int iPararm1;
                public int iPararm2;
                public int iPararm3;
                public string strParam1;
                public string strParam2;
                public string strParam3;
            }
    
            public const int PLATFORM_MSG_QQLOGINCALLBACK = 1;//QQ登录回调
            public const int PLATFORM_MSG_WXLOGINCALLBACK = 2;//WX登录回调
    
            private Queue<PlatformMsg> megQueue = new Queue<PlatformMsg>();
    
            protected void OnMessage(string param)
            {
                JsonData jd = JsonMapper.ToObject(param);
                PlatformMsg msg;
                msg.iMsgId = (int)jd["imegId"];
                msg.iPararm1 = (int)jd["iPararm1"];
                msg.iPararm2 = (int)jd["iPararm2"];
                msg.iPararm3 = (int)jd["iPararm3"];
                msg.strParam1 = (string)jd["strParam1"];
                msg.strParam2 = (string)jd["strParam2"];
                msg.strParam3 = (string)jd["strParam3"];
    
                megQueue.Enqueue(msg);
            }
    
            public void Update()
            {
                while (megQueue.Count > 0)
                {
                    PlatformMsg msg = megQueue.Dequeue();
                    switch (msg.iMsgId)
                    {
                        case PLATFORM_MSG_QQLOGINCALLBACK:
                            JsonData qqjd = JsonMapper.ToObject(msg.strParam1);
                            Game.Scene.GetComponent<LoginManagerComponent>().LoginCallBack(qqjd, PlatEnum.QQ, msg.iPararm1);
                            break;
                        case PLATFORM_MSG_WXLOGINCALLBACK:
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    #endif
    }
    
  2. LoginManagerComponent 登录回调管理组件

    using LitJson;
    using System;
    
    namespace ETModel
    {
        public enum PlatEnum
        {
            None,
            QQ = 1,
            WX = 2
        }
        public class LoginManagerComponent : Component
        {
            public bool IsLogin { get; set; } = false;
    
            public Action<PlatEnum> LoginSuccess;
            public Action<PlatEnum> LoginFail;
            public Action<PlatEnum> LoginCanacle;
    
            //从底层获取String
            public const int UNITY_GET_STRING_QQAUTORVAILD = 1;//QQ票据是否有效
            public const int UNITY_GET_STRING_QQREFRESHSESSION = 2;//QQ刷新票据
    
            /// <summary>
            /// QQ授权是否有效
            /// </summary>
            /// <returns></returns>
            public bool QQAuthorvaild()
            {
                return Convert.ToBoolean(Game.Scene.GetComponent<PlatMsgComponent>().GetStringFromPlatform(UNITY_GET_STRING_QQAUTORVAILD));
            }
            /// <summary>
            /// 刷新获取票据
            /// </summary>
            /// <returns></returns>
            public JsonData GetQQSession()
            {
                JsonData jd = JsonMapper.ToObject(Game.Scene.GetComponent<PlatMsgComponent>().GetStringFromPlatform(UNITY_GET_STRING_QQREFRESHSESSION));
                return jd;
            }
    
            /// <summary>
            /// 自动登录
            /// </summary>
            public void AutoLogin()
            {
                if (QQAuthorvaild())
                {
                    JsonData jd = GetQQSession();
                    LoginCallBack(jd, PlatEnum.QQ);
                }
            }
    
            /// <summary>
            /// 登录回调
            /// </summary>
            /// <param name="jd">数据</param>
            /// <param name="plat">平台类型</param>
            /// <param name="result">登录结果 0=成功,1=失败,2=取消</param>
            public void LoginCallBack(JsonData jd, PlatEnum plat, int result = 0)
            {
                if (result == 0)
                {
                    Log.Debug($"票据获取:{jd.ToJson().ToString()}");
                    string openid = (string)jd["openid"];
                    string unionid = (string)jd["unionid"];
                    string token = (string)jd["token"];
                    IsLogin = true;
                    if (LoginSuccess != null)
                    {
                        LoginSuccess(plat);
                    }
                }
                else if (result == 1)
                {
                    if (LoginFail != null)
                    {
                        LoginFail(plat);
                    }
                }
                else if (result == 2)
                {
                    if (LoginCanacle != null)
                    {
                        LoginCanacle(plat);
                    }
                }
            }
        }
    }
    
  3. PlatMsgComponent平台消息传递组件

    using LitJson;
    using System;
    using System.Runtime.InteropServices;
    using UnityEngine;
    
    namespace ETModel
    {
        [ObjectSystem]
        public class PlatMsgComponentAwakeSystem : AwakeSystem<PlatMsgComponent>
        {
            public override void Awake(PlatMsgComponent self)
            {
                self.Awake();
            }
        }
    
        public class PlatMsgComponent : Component
        {
            GameObject platformObject = null;
            public PlatformScript platformScript = null;
    
            public void Awake()
            {
                if (platformObject == null)
                {
                    platformObject = new GameObject("PlatformObject");
                    //隐藏对象且不保存
                    platformObject.hideFlags = HideFlags.HideAndDontSave;
    
                    platformScript = platformObject.AddComponent<PlatformScript>();
    
    #if UNITY_EDITOR
                if (!Application.isPlaying)
                {
                    return;
                }
    #endif
                    //不删除
                    GameObject.DontDestroyOnLoad(platformObject);
                }
    #if !UNITY_EDITOR && UNITY_ANDROID
                androidJavaClass = new AndroidJavaClass("com.Company.ETGame.GameHelper");//该包名可以通过压缩包查看jar目录得到
                Debug.Log("Platform Init com.Company.ETGame.GameHelper");
    #endif
            }
    
            //发送消息到平台
            public const int PLATFORM_MSG_QQLOGIN = 1;//QQ登录
            public const int PLATFORM_MSG_QQLOGOUT = 2;//QQ注销
            public const int PLATFORM_MSG_WXLOGIN = 3;//WX登录
            public const int PLATFORM_MSG_WXLOGOUT = 4;//WX注销
    
            //从底层获取long
            public const int UNITY_GET_LONG_AVAILABLEMEMORY = 1;//可用内存
            public const int UNITY_GET_LONG_TOTALMEMORY = 2;//总共内存大小
            public const int UNITY_GET_LONG_USEDMEMORY = 3;//可用运行内存大小
    
            //从底层获取String
            public const int UNITY_GET_STRING_QQAUTORVAILD = 1;//QQ票据是否有效
            public const int UNITY_GET_STRING_QQREFRESHSESSION = 2;//QQ刷新票据
    
            /// <summary>
            /// QQ授权是否有效
            /// </summary>
            /// <returns></returns>
            public bool QQAuthorvaild()
            {
                return Convert.ToBoolean(GetStringFromPlatform(UNITY_GET_STRING_QQAUTORVAILD));
            }
            /// <summary>
            /// 刷新获取票据
            /// </summary>
            /// <returns></returns>
            public JsonData GetQQSession()
            {
                JsonData jd = JsonMapper.ToObject(GetStringFromPlatform(UNITY_GET_STRING_QQREFRESHSESSION));
                return jd;
            }
    
    #if !UNITY_EDITOR && UNITY_ANDROID
            AndroidJavaClass androidJavaClass = null;
    
            /// <summary>
            /// 从Unity发送消息到android平台
            /// </summary>
            public void SendUnityMessageToPlatform(int iMsgId, int iParam1 = 0, int iParam2 = 0, int iParam3 = 0, int iParam4 = 0,
       string strParam1 = "", string strParam2 = "", string strParam3 = "", string strParam4 = "")
            {
                if (androidJavaClass == null) return;
    
                androidJavaClass.CallStatic("SendUnityMessageToPlatform", iMsgId, iParam1, iParam2, iParam3, iParam4,
                    strParam1, strParam2, strParam3, strParam4);
            }
    
            /// <summary>
            /// 从平台获取整形数据
            /// </summary>
            /// <param name="type"></param>
            /// <returns></returns>
            public int GetIntFromPlatform(int type)
            {
                if (androidJavaClass == null) return 0;
    
                return androidJavaClass.CallStatic<int>("GetIntFromPlatform", type);
            }
    
            public long GetLongFromPlatform(int type)
            {
                if (androidJavaClass == null) return 0;
    
                return androidJavaClass.CallStatic<long>("GetLongFromPlatform", type);
            }
    
            public long GetLongFromPlatform2(int type, int iParam1 = 0, int iParam2 = 0, int iParam3 = 0, int iParam4 = 0,
       string strParam1 = "", string strParam2 = "", string strParam3 = "", string strParam4 = "")
            {
                if (androidJavaClass == null) return 0;
    
                return androidJavaClass.CallStatic<long>("GetLongFromPlatform2", type, iParam1, iParam2, iParam3, iParam4,
                    strParam1, strParam2, strParam3, strParam4);
            }
    
            public string GetStringFromPlatform(int type)
            {
                if (androidJavaClass == null) return string.Empty;
    
                return androidJavaClass.CallStatic<string>("GetStringFromPlatform", type);
            }
    
    #else
            /// <summary>
            /// 从Unity发送消息到android平台
            /// </summary>
            public void SendUnityMessageToPlatform(int iMsgId, int iParam1 = 0, int iParam2 = 0, int iParam3 = 0, int iParam4 = 0,
       string strParam1 = "", string strParam2 = "", string strParam3 = "", string strParam4 = "")
            {
                return;
            }
    
            /// <summary>
            /// 从平台获取整形数据
            /// </summary>
            /// <param name="type"></param>
            /// <returns></returns>
            public int GetIntFromPlatform(int type)
            {
                return 0;
            }
    
            public long GetLongFromPlatform(int type)
            {
                switch (type)
                {
                    case UNITY_GET_LONG_AVAILABLEMEMORY:
                        return (long)GetWinAvailMemory();
                    case UNITY_GET_LONG_TOTALMEMORY:
                        return (long)GetWinTotalMemory();
                    case UNITY_GET_LONG_USEDMEMORY:
                        return GetWinUsedMemory();
                    default:
                        break;
                }
                return 0;
            }
    
            public long GetLongFromPlatform2(int type, int iParam1 = 0, int iParam2 = 0, int iParam3 = 0, int iParam4 = 0,
       string strParam1 = "", string strParam2 = "", string strParam3 = "", string strParam4 = "")
            {
                return 0;
            }
    
            public string GetStringFromPlatform(int type)
            {
                return string.Empty;
            }
    #endif
            //获取Windows内存
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct MEMORYSTATUSEX
            {
                public uint dwLength;
                public uint dwMemoryLoad;
                public uint ullTotalPhys;
                public uint ullAvailPhys;
                public uint ullTotalPageFile;
                public uint ullAvailPageFile;
                public uint ullTotalVirtual;
                public uint ullAvailVirtual;
                public uint ullAvailExtendedVirtual;
            }
    
            [DllImport("kernel32.dll")]
            protected static extern void GlobalMemoryStatus(ref MEMORYSTATUSEX lpBuff);
    
            /// <summary>
            /// 获取可用内存
            /// </summary>
            /// <returns></returns>
            protected ulong GetWinAvailMemory()
            {
                MEMORYSTATUSEX ms = new MEMORYSTATUSEX();
                ms.dwLength = 64;
                GlobalMemoryStatus(ref ms);
                return ms.ullAvailPhys;
            }
            /// <summary>
            /// 获取总内存
            /// </summary>
            /// <returns></returns>
            protected ulong GetWinTotalMemory()
            {
                MEMORYSTATUSEX ms = new MEMORYSTATUSEX();
                ms.dwLength = 64;
                GlobalMemoryStatus(ref ms);
                return ms.ullTotalPhys;
            }
            /// <summary>
            /// 获取已使用内存
            /// </summary>
            /// <returns></returns>
            protected long GetWinUsedMemory()
            {
                return UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong();
            }
        }
    }
    
  4. UI链接示例

    using ETModel;
    using UnityEngine;
    using UnityEngine.UI;
    
    namespace ETHotfix
    {
    	public class UILoginComponent: Component
    	{
         private GameObject qqLogin;
         private GameObject qqLogout;
         private Text text;
    
         public void Awake()
         {
             ReferenceCollector rc = this.GetParent<UI>().GameObject.GetComponent<ReferenceCollector>();
    
                qqLogin = rc.Get<GameObject>("QQLogin");
             qqLogout = rc.Get<GameObject>("QQLogout");
             text = rc.Get<GameObject>("Text").GetComponent<Text>();
    
                qqLogin.GetComponent<Button>().interactable = true;
                qqLogout.GetComponent<Button>().interactable = false;
    
    #if UNITY_ANDROID || UNITY_IOS
             LoginManagerComponent loginManagerComponent = ETModel.Game.Scene.GetComponent<LoginManagerComponent>();
                //绑定回调事件
             loginManagerComponent.LoginSuccess += LoginSuccess;
             loginManagerComponent.LoginFail += LoginFail;
             loginManagerComponent.LoginCanacle += LoginCanacle;
    
             //自动登录
                if (!loginManagerComponent.IsLogin)
                {
                 loginManagerComponent.AutoLogin();
             }
    
                qqLogin.GetComponent<Button>().onClick.Add(OnClickQQ);
                qqLogout.GetComponent<Button>().onClick.Add(OnClickLogout);
    #endif
         }
    
         //--消息回调
         void LoginSuccess(PlatEnum plat)
            {
                if (plat ==PlatEnum.QQ)
                {
                 text.text = "QQ登录成功!";
             }
             qqLogin.GetComponent<Button>().interactable = false;
             qqLogout.GetComponent<Button>().interactable = true;
         }
    
         void LoginFail(PlatEnum plat)
            {
             text.text = "QQ登录失败!";
         }
    
            void LoginCanacle(PlatEnum plat)
            {
                text.text = "QQ取消登录!";
            }
         //--消息回调
    
    
         //登录QQ
         void OnClickQQ()
            {
             PlatMsgComponent platMsgComponent = ETModel.Game.Scene.GetComponent<PlatMsgComponent>();
             platMsgComponent.SendUnityMessageToPlatform(PlatMsgComponent.PLATFORM_MSG_QQLOGIN) ;
            }
         //注销
         void OnClickLogout()
            {
                PlatMsgComponent platMsgComponent = ETModel.Game.Scene.GetComponent<PlatMsgComponent>();
                platMsgComponent.SendUnityMessageToPlatform(PlatMsgComponent.PLATFORM_MSG_QQLOGOUT);
            }
        }
    }
    
    
Licensed under CC BY-NC-SA 4.0
0