Unity Android Plugin开发指南

下面是一份Unity Android Plugin开发指南,涵盖你关心的所有要点,包括如何在Unity工程中集成Android/Java库、双向调用、接口设计、混合项目构建、调试方法以及跨虚拟机调用的原理和实践。


Unity Android Plugin开发指南

一、如何在Unity项目中使用Android Plugin

1. 插件文件的准备

  • Java代码:编写Android原生功能(如支付、分享、推送等)相关的Java代码。
  • 打包为AAR/JAR:用Android Studio将Java代码打包成.aar.jar文件。
  • JNI接口:如需C/C++,可用NDK编写so库。

2. 插件文件的导入

  • .aar.jar.so文件放入Unity工程的Assets/Plugins/Android/目录下。
  • 若有AndroidManifest.xml,也放在此目录,Unity会自动合并。

3. 插件的自动集成

  • Unity构建Android包时,会自动将Plugins/Android下的内容合并进最终APK/AAB。

二、Unity-Android相互调用

1. Unity调用Android(C#→Java)

基本用法
#if UNITY_ANDROID && !UNITY_EDITOR
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject plugin = new AndroidJavaObject("com.yourcompany.plugin.YourPluginClass");
plugin.Call("yourJavaMethod", "参数1", 123);
#endif
传递参数和返回值
  • 支持基本类型、String、数组、Java对象等。
  • 返回值用Call<T>()泛型方法获取。

2. Android调用Unity(Java→C#)

步骤
  1. 在Unity C#中定义一个GameObject和方法:
    public void OnPluginCallback(string message) {
        Debug.Log("收到Java回调: " + message);
    }
    
  2. 在Java代码中调用Unity方法:
    UnityPlayer.UnitySendMessage("GameObjectName", "OnPluginCallback", "Hello from Java");
    
    • GameObjectName为场景中对象名,OnPluginCallback为C#方法名。
注意事项
  • UnitySendMessage只能传递字符串参数。
  • 回调方法需为public,且参数为string。

三、Unity接口设计的最佳实践

  1. 单例管理:用C#单例类统一管理所有Android交互,便于维护。
  2. 异步回调:Java侧操作完成后用UnitySendMessage回调C#,避免阻塞主线程。
  3. 参数封装:复杂参数用JSON序列化传递,C#和Java都易于解析。
  4. 错误处理:Java侧catch异常后回调Unity,C#侧做好异常兜底。
  5. 接口文档:约定好C#和Java的接口、参数、回调格式,便于多人协作。

四、如何构建Unity-Android混合项目

  1. Android Studio开发插件:用Android Studio开发和调试Java代码,打包成AAR/JAR。
  2. Unity集成插件:将AAR/JAR放入Plugins/Android,如需资源(res/、assets/)也一并打包。
  3. Gradle自定义:如需自定义依赖、Manifest等,可启用Custom Gradle Template(mainTemplate.gradle)。
  4. 多渠道/多包名:可用Gradle脚本或第三方工具自动化多渠道打包。
  5. 资源合并冲突:多个插件有资源/Manifest冲突时,需手动合并。

五、如何调试Unity和Android代码

1. 日志调试

  • C#用Debug.Log,Java用Log.d
  • adb logcat查看Android日志。

2. 断点调试

  • Java代码可用Android Studio直接断点调试。
  • Unity C#可用Visual Studio/VSCode调试。
  • 可用Attach to Process连接到Unity进程。

3. 插件热更新

  • 修改Java代码后,重新打包AAR/JAR并替换到Unity工程,无需重启Unity。

4. 日志桥接

  • 可将Java日志通过UnitySendMessage回传到C#,便于统一查看。

六、跨虚拟机调用的实现(JNI原理)

1. Unity的C#和Android的Java运行在不同虚拟机

  • Unity C#运行在Mono/IL2CPP虚拟机。
  • Android Java运行在ART/Dalvik虚拟机。

2. Unity通过JNI桥接

  • Unity内置AndroidJavaObjectAndroidJavaClass等C#类,底层通过JNI与Java通信。
  • C#调用Java时,Unity自动生成JNI调用代码。
  • Java调用C#时,需通过UnityPlayer.UnitySendMessage,底层通过JNI回调C#。

3. 性能与注意事项

  • JNI调用有一定性能开销,频繁调用需谨慎。
  • 复杂数据建议用JSON等序列化方式传递。

七、实用代码模板

1. C#单例管理Android插件

public class AndroidPluginManager : MonoBehaviour
{
    private static AndroidPluginManager _instance;
    public static AndroidPluginManager Instance => _instance;

    private AndroidJavaObject _plugin;

    void Awake()
    {
        _instance = this;
#if UNITY_ANDROID && !UNITY_EDITOR
        using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
        {
            var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
            _plugin = new AndroidJavaObject("com.yourcompany.plugin.YourPluginClass", activity);
        }
#endif
    }

    public void CallJavaMethod(string param)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        _plugin.Call("yourJavaMethod", param);
#endif
    }

    public void OnPluginCallback(string message)
    {
        Debug.Log("Java回调: " + message);
    }
}

2. Java侧回调Unity

import com.unity3d.player.UnityPlayer;

public void sendCallbackToUnity(String message) {
    UnityPlayer.UnitySendMessage("AndroidPluginManager", "OnPluginCallback", message);
}

八、常见问题与建议

  • 包名/类名要一致,否则C#找不到Java类。
  • UnitySendMessage只能传字符串,复杂数据用JSON。
  • AndroidManifest冲突,需手动合并。
  • 多线程问题,Java侧UI操作需在主线程(runOnUiThread)。
  • 权限申请,Android 6.0+需动态申请权限。

九、参考资料


下面继续深入讲解Unity Android Plugin开发的进阶内容,包括AAR/JAR打包流程、复杂数据交互、原生UI嵌入、NDK调用、常见问题排查等。


十、AAR/JAR打包与集成流程

1. 用Android Studio创建插件工程

  1. 新建Android Library项目

    • 在Android Studio选择File > New > New Module > Android Library,填写包名、类名等。
  2. 编写Java代码

    • 例如:
      package com.yourcompany.plugin;
      public class MyPlugin {
          public String getMessage(String name) {
              return "Hello, " + name;
          }
      }
      
  3. 打包AAR/JAR

    • Build > Make Module ‘yourlibrary’
    • 输出文件在yourlibrary/build/outputs/aar/yourlibrary-release.aar
  4. 拷贝到Unity

    • 将AAR/JAR文件放入Assets/Plugins/Android/目录。

2. 集成第三方SDK(如微信、支付宝等)

  • 通常SDK提供AAR/JAR和文档,按文档放入Plugins/Android,如有依赖需一并拷贝。
  • 检查AndroidManifest.xml,如有冲突需合并。

十一、复杂数据交互(如对象、数组、JSON)

1. C#传递复杂数据到Java

  • 推荐将复杂对象序列化为JSON字符串传递。
  • C#端:
    var data = new { id = 1, name = "test" };
    string json = JsonUtility.ToJson(data);
    plugin.Call("receiveJson", json);
    
  • Java端:
    public void receiveJson(String json) {
        JSONObject obj = new JSONObject(json);
        // 解析数据
    }
    

2. Java回调复杂数据到Unity

  • Java端将对象转为JSON字符串,通过UnitySendMessage回调。
  • C#端用JsonUtilityNewtonsoft.Json解析。

十二、原生UI嵌入与交互

1. 显示原生Dialog/Toast

  • Java端实现弹窗方法,C#调用即可。
  • 例如:
    public void showToast(final String msg) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
            }
        });
    }
    

2. 原生Activity/Fragment嵌入

  • 可启动自定义Activity,或用Fragment嵌入Unity界面。
  • 复杂UI建议用Activity/Fragment,Unity与原生通过Intent、Broadcast、文件等通信。

3. Unity与原生UI通信

  • 原生UI操作完成后用UnitySendMessage通知Unity。
  • Unity可通过C#调用Java方法控制原生UI。

十三、NDK(C/C++)调用

1. 编写C/C++代码

  • 用Android Studio或CMake编写so库,导出JNI接口。

2. Java调用C/C++(JNI)

  • Java端用System.loadLibrary加载so库,声明native方法。

3. Unity调用C/C++

  • Unity可通过C#的[DllImport]直接调用so库(需ABI匹配)。
  • 或通过Java中转,C#→Java→JNI→C/C++。

4. so库集成

  • 将so库放入Assets/Plugins/Android/libs/armeabi-v7a/等对应ABI目录。

十四、常见问题排查

1. 插件找不到类/方法

  • 检查包名、类名、方法名是否一致。
  • 检查AAR/JAR是否正确放入Plugins/Android

2. AndroidManifest冲突

  • 多个插件有<application><activity>等重复声明时,需手动合并Manifest。

3. 资源冲突

  • 多个AAR有同名资源时,需合并或重命名。

4. 权限问题

  • Android 6.0+需动态申请权限,C#用Permission.RequestUserPermission

5. 64位兼容

  • so库需同时提供armeabi-v7aarm64-v8a版本。

十五、进阶技巧与建议

  1. 多渠道打包:用Gradle脚本或第三方工具自动化多渠道包名、签名、资源替换。
  2. 热更新:插件功能可通过AssetBundle、Lua、ILRuntime等实现热更新。
  3. 混淆与安全:发布前用Proguard混淆Java代码,保护核心逻辑。
  4. 性能优化:JNI调用有开销,频繁调用建议合并为批量操作。
  5. 文档与注释:接口、参数、回调格式要有详细文档,便于团队协作。

十六、参考项目结构

Assets/
  Plugins/
    Android/
      myplugin.aar
      myplugin.jar
      AndroidManifest.xml
      libs/
        armeabi-v7a/
          libnative.so
        arm64-v8a/
          libnative.so

十七、常用调试命令

  • 查看日志:adb logcat | findstr Unity
  • 安装APK:adb install -r your.apk
  • 查看设备:adb devices
  • 远程调试:Android Studio Attach Debugger,Unity Profiler远程连接

十八、官方文档与社区


好的,下面继续补充更具体的实战案例和进阶细节,包括AAR/JAR打包详细步骤、NDK调用示例、原生UI与Unity混合界面Demo、复杂数据交互代码等内容。


十九、AAR/JAR打包详细步骤(Android Studio)

1. 新建Android Library项目

  • 打开Android Studio,选择File > New > New Module > Android Library
  • 填写Module name(如:myplugin),Package name(如:com.example.myplugin)。

2. 编写Java代码

package com.example.myplugin;

import android.app.Activity;
import android.widget.Toast;

public class MyPlugin {
    private Activity activity;

    public MyPlugin(Activity activity) {
        this.activity = activity;
    }

    public String getMessage(String name) {
        return "Hello, " + name;
    }

    public void showToast(final String msg) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

3. 打包AAR

  • 在Android Studio菜单栏选择Build > Make Module 'myplugin'
  • 打包完成后,AAR文件在myplugin/build/outputs/aar/myplugin-release.aar

4. 集成到Unity

  • 将AAR文件拷贝到Unity项目的Assets/Plugins/Android/目录下。
  • 若有依赖(如support库),也需一并拷贝。

二十、Unity调用AAR插件示例

1. C#代码调用

#if UNITY_ANDROID && !UNITY_EDITOR
public class MyPluginWrapper
{
    private AndroidJavaObject plugin;

    public MyPluginWrapper()
    {
        using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
        {
            var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
            plugin = new AndroidJavaObject("com.example.myplugin.MyPlugin", activity);
        }
    }

    public string GetMessage(string name)
    {
        return plugin.Call<string>("getMessage", name);
    }

    public void ShowToast(string msg)
    {
        plugin.Call("showToast", msg);
    }
}
#endif

2. 使用

MyPluginWrapper plugin = new MyPluginWrapper();
string msg = plugin.GetMessage("Unity");
plugin.ShowToast(msg);

二十一、NDK调用(C/C++与Unity交互)

1. 编写C/C++代码(JNI接口)

// native-lib.cpp
#include <jni.h>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_myplugin_MyPlugin_nativeHello(JNIEnv *env, jobject /* this */) {
    return env->NewStringUTF("Hello from C++");
}

2. Java调用C/C++

public native String nativeHello();
static {
    System.loadLibrary("native-lib");
}

3. Unity调用C/C++

  • 方式一:通过Java中转(C#→Java→JNI→C/C++)。
  • 方式二:直接用C#的[DllImport]调用so库(需ABI匹配)。
[DllImport("native-lib")]
private static extern IntPtr Java_com_example_myplugin_MyPlugin_nativeHello(IntPtr env, IntPtr thiz);
  • so库放到Assets/Plugins/Android/libs/armeabi-v7a/arm64-v8a/

二十二、原生UI与Unity混合界面Demo

1. 启动原生Activity

  • Java端新建Activity(如:MyNativeActivity),在Manifest注册。
  • C#调用Java方法启动Activity。
// Java
public void startNativeActivity() {
    Intent intent = new Intent(activity, MyNativeActivity.class);
    activity.startActivity(intent);
}
// C#
plugin.Call("startNativeActivity");

2. 原生Activity与Unity通信

  • 在MyNativeActivity中,操作完成后用UnityPlayer.UnitySendMessage回调Unity。
UnityPlayer.UnitySendMessage("GameObjectName", "OnNativeResult", "result data");

二十三、复杂数据交互代码(JSON)

1. C#传递JSON到Java

[System.Serializable]
public class UserData
{
    public int id;
    public string name;
}
UserData data = new UserData { id = 1, name = "Unity" };
string json = JsonUtility.ToJson(data);
plugin.Call("receiveJson", json);

2. Java解析JSON

public void receiveJson(String json) {
    try {
        JSONObject obj = new JSONObject(json);
        int id = obj.getInt("id");
        String name = obj.getString("name");
        // 处理数据
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

3. Java回调JSON到Unity

JSONObject obj = new JSONObject();
obj.put("result", "ok");
obj.put("score", 100);
UnityPlayer.UnitySendMessage("GameObjectName", "OnPluginCallback", obj.toString());
public void OnPluginCallback(string json)
{
    Debug.Log("收到回调: " + json);
    // 解析json
}

二十四、常见问题与调试技巧

  1. AAR/JAR未生效
    • 检查是否放在Assets/Plugins/Android/,包名、类名是否一致。
  2. Manifest冲突
    • 手动合并Manifest,保留必要的权限、Activity、Service等声明。
  3. so库未加载
    • 检查ABI目录,确保与Unity Player设置一致(armeabi-v7a/arm64-v8a)。
  4. UnitySendMessage无效
    • 检查GameObject名称、方法名、参数类型(必须是string)。
  5. 调试日志
    • adb logcat | findstr Unity(Windows)或adb logcat | grep Unity(Mac/Linux)过滤Unity日志。
  6. 断点调试
    • Android Studio可Attach到Unity进程,调试Java代码。

二十五、进阶建议

  • 接口文档:建议用Markdown或Swagger记录C#与Java的接口、参数、回调格式。
  • 自动化打包:用Gradle脚本、Jenkins等实现自动化构建和多渠道打包。
  • 代码热更新:如需热更,建议用ILRuntime、XLua等方案,插件接口保持稳定。
  • 安全性:发布前用Proguard混淆Java代码,防止反编译。
  • 团队协作:插件开发与Unity主工程分离,接口通过文档和Demo验证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值