Unity与Android交互开发指南:JNI通信与插件实现
1. Unity与Android交互的核心原理Unity调用Android接口的本质是通过JNIJava Native Interface实现跨语言通信。当Unity项目打包为Android应用时会自动生成一个基础的UnityPlayerActivity类作为应用入口。我们需要通过继承和扩展这个类来实现自定义功能。关键点UnityPlayerActivity是Unity在Android平台上的主入口类类似于iOS上的AppController.mm文件Android插件开发的核心步骤包括创建继承自UnityPlayerActivity的自定义Activity类实现所需的Android原生功能修改AndroidManifest.xml指定新的Activity为入口将编译后的代码集成到Unity项目中2. 环境准备与基础配置2.1 开发环境要求Unity 2019.4或更高版本推荐2021 LTSAndroid Studio 4.0JDK 11或更高版本Android SDK Platform 302.2 项目结构规划建议的插件目录结构Assets/ └── Plugins/ └── Android/ ├── libs/ # 存放.jar/.aar文件 ├── res/ # Android资源文件 └── AndroidManifest.xml3. 创建自定义Activity3.1 基础Activity实现package com.example.unityplugin; import com.unity3d.player.UnityPlayerActivity; import android.os.Bundle; import android.util.Log; public class CustomUnityActivity extends UnityPlayerActivity { private static final String TAG CustomUnityActivity; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, Custom activity initialized); } // 示例添加原生Toast功能 public void showToast(final String message) { runOnUiThread(new Runnable() { Override public void run() { Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); } }); } }3.2 AndroidManifest配置?xml version1.0 encodingutf-8? manifest xmlns:androidhttp://schemas.android.com/apk/res/android packagecom.example.unityplugin application android:icondrawable/app_icon android:labelstring/app_name activity android:namecom.example.unityplugin.CustomUnityActivity android:labelstring/app_name android:configChangesfontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen intent-filter action android:nameandroid.intent.action.MAIN / category android:nameandroid.intent.category.LAUNCHER / /intent-filter /activity /application /manifest4. Unity端调用实现4.1 C#桥接类设计using UnityEngine; public class AndroidNativeBridge : MonoBehaviour { private static AndroidJavaClass unityPlayer; private static AndroidJavaObject currentActivity; public static void CallAndroidMethod(string methodName, params object[] args) { if (Application.platform ! RuntimePlatform.Android) return; if (unityPlayer null) unityPlayer new AndroidJavaClass(com.unity3d.player.UnityPlayer); if (currentActivity null) currentActivity unityPlayer.GetStaticAndroidJavaObject(currentActivity); currentActivity.Call(methodName, args); } // 封装Toast调用 public static void ShowToast(string message) { CallAndroidMethod(showToast, message); } }4.2 调用示例// 在Unity C#脚本中调用 public class ExampleUsage : MonoBehaviour { void Start() { AndroidNativeBridge.ShowToast(Hello from Unity!); } }5. 高级功能实现5.1 双向通信机制Android端添加回调接口// 在CustomUnityActivity中添加 private static UnityPlayerActivity instance; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); instance this; } public static void sendMessageToUnity(String gameObject, String method, String message) { UnityPlayer.UnitySendMessage(gameObject, method, message); }Unity端接收消息// 挂载到接收消息的GameObject上 public class AndroidMessageReceiver : MonoBehaviour { void OnMessageReceived(string message) { Debug.Log(Received from Android: message); } }5.2 处理Activity生命周期Override protected void onPause() { super.onPause(); // 处理暂停逻辑 } Override protected void onResume() { super.onResume(); // 处理恢复逻辑 }6. 常见问题与解决方案6.1 编译问题排查问题现象可能原因解决方案ClassNotFoundException类名/包名不匹配检查AndroidManifest中的activity声明MethodNotFoundException方法未声明为public确保Java方法为publicUnitySendMessage不生效GameObject名称错误检查场景中的对象名称和脚本方法名6.2 性能优化建议减少JNI调用频率批量处理数据在主线程之外执行耗时操作使用Android Profiler监控性能考虑使用Unity的AndroidJavaProxy进行回调7. 实战案例获取设备信息7.1 Android端实现public String getDeviceInfo() { JSONObject info new JSONObject(); try { info.put(model, Build.MODEL); info.put(sdk, Build.VERSION.SDK_INT); info.put(manufacturer, Build.MANUFACTURER); } catch (JSONException e) { e.printStackTrace(); } return info.toString(); }7.2 Unity端封装public static string GetDeviceInfo() { if (Application.platform ! RuntimePlatform.Android) return {}; using (AndroidJavaClass pluginClass new AndroidJavaClass(com.example.unityplugin.CustomUnityActivity)) { return pluginClass.CallStaticstring(getDeviceInfo); } }8. 插件打包与发布8.1 AAR打包配置在Android Studio中新建Android Library模块在build.gradle中添加android { compileSdkVersion 30 defaultConfig { minSdkVersion 21 targetSdkVersion 30 } }8.2 Unity导入设置将生成的.aar文件放入Assets/Plugins/Android在Player Settings中设置Minimum API Level启用Custom Gradle Template如需高级配置处理依赖冲突如有9. 调试技巧使用Android Studio的Logcat查看日志在Unity中使用adb命令adb logcat -s Unity启用Unity的Development Build获取详细日志使用Android Profiler分析性能10. 安全注意事项敏感操作添加权限检查关键数据通信使用加密验证传入参数的合法性避免在Java层存储敏感信息在实现一个跨平台的Unity-Android通信系统时我发现最关键的挑战是保持两端数据格式的一致性。特别是在处理复杂数据结构时建议使用JSON作为中间格式既保证可读性又便于扩展。实际项目中建议先建立完善的日志系统这对后期调试会有极大帮助。