1. 为什么Unity开发者需要了解Android开发作为一名长期使用Unity引擎的游戏开发者我最初也和很多人一样认为掌握了Unity就足够应对所有平台的需求。直到第一次遇到需要接入第三方Android SDK时才意识到原生开发知识的重要性。Unity虽然提供了跨平台的能力但在实际项目开发中特别是涉及到平台特定功能时Android原生开发知识往往能帮助我们解决很多棘手问题。Android开发对Unity程序员的价值主要体现在以下几个方面首先当我们需要接入各种第三方服务时如支付SDK、广告SDK、社交分享等这些SDK通常都是以Android原生库的形式提供。虽然有些服务提供了Unity插件但往往功能不完整或更新滞后。掌握Android开发知识可以让我们直接使用原生SDK的全部功能。其次性能优化方面了解Android原生开发可以帮助我们更好地管理内存、优化渲染效率。比如通过原生代码实现某些计算密集型任务可以显著提升性能。我曾经在一个项目中通过将部分物理计算移到原生层使帧率提升了近30%。再者当我们需要实现一些Unity未提供的平台特性时如后台服务、通知管理、传感器深度使用等原生开发知识就变得不可或缺。特别是在开发AR应用时往往需要直接调用Android的Camera2 API来获取更精细的相机控制。最后调试和问题排查能力也会大幅提升。当游戏在Android设备上出现崩溃或异常行为时能够读懂logcat日志、理解Android系统机制可以快速定位问题根源。记得有一次我们的游戏在某些设备上启动即崩溃通过分析原生堆栈信息发现是缺少必要的权限声明这个问题在Unity日志中完全没有体现。2. Android开发环境快速搭建2.1 Android Studio安装与配置对于Unity开发者来说Android Studio是必不可少的工具。虽然Unity内置了Android打包功能但当我们涉及到原生代码开发或调试时Android Studio提供的完整工具链会大大提升效率。安装Android Studio的第一步是前往官网下载适合自己操作系统的版本。安装过程中有几个关键点需要注意确保勾选Android Virtual Device选项虽然我们主要做Unity开发可能用不上模拟器但完整安装可以避免后续可能出现的问题。SDK组件选择上建议至少安装以下版本Android SDK Platform 29对应Android 10Android SDK Build-Tools 29.0.3NDK最新稳定版CMake如果涉及原生代码安装路径最好选择没有空格和特殊字符的目录比如直接放在C:\Android\这样的路径下。我曾经遇到因为路径包含空格导致gradle构建失败的问题。安装完成后首次启动Android Studio会进行一些初始化设置。这里有几个实用建议在Preferences Appearance Behavior System Settings Android SDK中添加一个国内镜像源如腾讯或阿里云的镜像可以显著加快SDK下载速度。在Preferences Editor Code Style中将Java和XML的代码风格设置为Project这样与Unity生成的代码风格保持一致。建议安装以下插件ADB Idea简化ADB操作.ignore管理.gitignore文件Gradle Dependencies Helper可视化查看依赖关系2.2 Unity与Android Studio的协作配置要让Unity和Android Studio良好协作需要进行一些配置在Unity的Preferences External Tools中设置Android SDK和JDK的路径。这里要特别注意Unity对JDK版本有一定要求通常Java 8是最兼容的选择。如果项目中使用NDK比如有C插件也需要在这里指定NDK路径。建议使用Unity Hub安装的NDK版本以确保兼容性。创建一个简单的批处理脚本或shell脚本用于在Unity和Android Studio之间同步代码。基本思路是将Unity项目的Assets/Plugins/Android目录同步到Android Studio项目构建完成后将生成的aar/jar文件复制回Unity项目我曾经写过一个简单的Python脚本实现这个功能大大提升了开发效率。关键代码如下import shutil import os # 配置路径 unity_project path/to/unity/Assets/Plugins/Android android_studio_project path/to/androidstudio/app # 同步文件 def sync_files(): # 复制Android Studio输出到Unity for file in os.listdir(os.path.join(android_studio_project, build/outputs/aar)): if file.endswith(.aar): shutil.copy( os.path.join(android_studio_project, build/outputs/aar, file), os.path.join(unity_project, libs) ) # 复制其他必要文件 # ...3. Unity与Android交互的核心机制3.1 Unity调用Android原生代码Unity提供了AndroidJavaClass和AndroidJavaObject这两个类来实现与Android原生代码的交互。这种机制本质上是通过JNIJava Native Interface实现的。基本调用模式如下// 调用静态方法 using (AndroidJavaClass jc new AndroidJavaClass(com.example.MyClass)) { jc.CallStatic(staticMethodName, parameter); } // 调用实例方法 using (AndroidJavaObject jo new AndroidJavaObject(com.example.MyClass)) { jo.Call(instanceMethodName, parameter); }在实际项目中有几点需要特别注意方法签名必须完全匹配。Android是强类型语言如果参数类型不匹配会导致调用失败。我曾经因为传递了一个int参数而Java端期望的是long调试了很久才发现问题。复杂数据类型的传递需要使用AndroidJavaProxy或实现特定的接口。比如要传递一个回调函数可以这样实现public class MyCallback : AndroidJavaProxy { public MyCallback() : base(com.example.CallbackInterface) {} public void onResult(string result) { // 处理回调 } } // 使用回调 jo.Call(setCallback, new MyCallback());线程安全问题。Unity的主线程和Android的UI线程是不同的如果需要在Android端更新UI必须确保代码运行在UI线程上。可以通过runOnUiThread实现// Android端代码 public void showToast(final String message) { runOnUiThread(new Runnable() { Override public void run() { Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); } }); }3.2 Android调用Unity代码Android原生代码也可以调用Unity中的方法这主要通过UnityPlayer.UnitySendMessage实现。在Unity中需要有一个GameObject挂载接收消息的脚本public class NativeMessageReceiver : MonoBehaviour { void OnMessage(string message) { Debug.Log(Received from native: message); } }然后在Android端可以这样调用UnityPlayer.UnitySendMessage(GameObjectName, OnMessage, Hello from Android);这种通信方式有几个限制需要注意只能传递字符串参数。如果需要传递复杂数据需要序列化为JSON字符串。性能开销较大。频繁调用会影响游戏性能建议将多次调用合并为一次。不是实时调用。消息会被放入队列Unity在主线程的下一个更新周期处理。在实际项目中我通常会建立一个消息总线系统来处理原生调用基本结构如下public class NativeMessageBus : MonoBehaviour { private static NativeMessageBus _instance; public static NativeMessageBus Instance { get { if (_instance null) { GameObject go new GameObject(NativeMessageBus); _instance go.AddComponentNativeMessageBus(); DontDestroyOnLoad(go); } return _instance; } } private Dictionarystring, Actionstring _handlers new Dictionarystring, Actionstring(); public void RegisterHandler(string messageType, Actionstring handler) { _handlers[messageType] handler; } // 由Android原生调用 private void OnNativeMessage(string json) { NativeMessage msg JsonUtility.FromJsonNativeMessage(json); if (_handlers.TryGetValue(msg.type, out Actionstring handler)) { handler.Invoke(msg.data); } } [System.Serializable] private class NativeMessage { public string type; public string data; } }4. 常见问题与解决方案4.1 插件集成问题排查在集成Android插件到Unity项目时经常会遇到各种问题。根据我的经验90%的问题都集中在以下几个方面Manifest合并冲突当多个插件都修改AndroidManifest.xml时可能会出现属性冲突。解决方法包括使用tools:replace属性明确指定要替换的属性在Unity的Assets/Plugins/Android下创建manifest-merger.properties文件配置合并规则手动合并所有插件的Manifest文件重复类定义当不同插件包含相同的类时会导致冲突。可以通过以下方式解决使用proguard规则排除重复类修改插件代码改变包名联系插件提供商获取兼容版本资源冲突当不同插件使用相同的资源ID时会出现问题。解决方法在build.gradle中启用资源前缀android { resourcePrefix plugin1_ }手动修改资源文件名添加前缀Native库冲突特别是当多个插件提供相同架构的.so文件时。可以只保留需要的架构如只保留armeabi-v7a合并.so文件需要一定技术能力4.2 性能优化建议在Unity和Android混合开发中性能优化需要特别注意以下几点JNI调用优化减少跨语言调用次数批量处理数据缓存Java类和方法IDprivate static AndroidJavaClass _utilityClass; private static IntPtr _methodID; [RuntimeInitializeOnLoadMethod] private static void Initialize() { _utilityClass new AndroidJavaClass(com.example.Utility); _methodID AndroidJNIHelper.GetMethodID(_utilityClass.GetRawClass(), expensiveMethod, ()V); } public static void CallExpensiveMethod() { IntPtr args IntPtr.Zero; AndroidJNI.CallStaticVoidMethod(_utilityClass.GetRawClass(), _methodID, args); }内存管理及时释放AndroidJavaObject和AndroidJavaClass实例避免在频繁调用的方法中创建临时Java对象使用AndroidJNI直接调用替代高级封装减少开销线程管理耗时原生操作放在后台线程UI更新确保在主线程执行使用Android的Handler或Unity的MainThreadDispatcher协调线程渲染性能合理设置SurfaceView的格式和参数避免频繁切换GL上下文使用多线程渲染如果设备支持4.3 调试技巧有效的调试可以节省大量开发时间。以下是我总结的一些实用技巧Logcat过滤adb logcat -s Unity DEBUG AndroidRuntime这个命令可以只显示Unity、DEBUG标签和崩溃日志。符号化原生崩溃 当发生原生崩溃时需要使用ndk-stack工具解析堆栈adb logcat | ndk-stack -sym path/to/symbolsUnity-Android双向调试在Android Studio中调试Java代码在Visual Studio中调试C#代码使用LLDB调试原生代码内存分析Android Studio的Profiler工具Unity的Memory Profileradb shell dumpsys meminfo自动化测试 编写简单的UI自动化测试可以快速验证基本功能Test public void testUnityActivityLaunch() { ActivityScenarioUnityPlayerActivity scenario ActivityScenario.launch(UnityPlayerActivity.class); onView(withId(R.id.unitySurfaceView)).check(matches(isDisplayed())); }5. 实战案例接入支付SDK让我们通过一个实际案例 - 接入支付宝SDK来综合运用前面介绍的知识。5.1 准备工作从支付宝开放平台下载最新的SDK通常包含alipaySdk.aar核心库AndroidManifest.xml声明必要的组件和权限说明文档在Android Studio中创建新模块选择Import .JAR/.AAR Package指定alipaySdk.aar文件位置模块名设置为alipay配置依赖 在app模块的build.gradle中添加dependencies { implementation project(:alipay) }5.2 实现支付功能创建支付服务类public class AlipayService { private Activity mActivity; public AlipayService(Activity activity) { this.mActivity activity; } public void pay(String orderInfo, final AlipayCallback callback) { Runnable payRunnable new Runnable() { Override public void run() { PayTask alipay new PayTask(mActivity); MapString, String result alipay.payV2(orderInfo, true); Message msg new Message(); msg.what SDK_PAY_FLAG; msg.obj result; mHandler.sendMessage(msg); } }; Thread payThread new Thread(payRunnable); payThread.start(); } private static final int SDK_PAY_FLAG 1; private Handler mHandler new Handler(Looper.getMainLooper()) { Override public void handleMessage(Message msg) { if (msg.what SDK_PAY_FLAG) { SuppressWarnings(unchecked) PayResult payResult new PayResult((MapString, String) msg.obj); String resultInfo payResult.getResult(); String resultStatus payResult.getResultStatus(); if (TextUtils.equals(resultStatus, 9000)) { callback.onSuccess(resultInfo); } else { callback.onFailure(resultStatus, resultInfo); } } } }; public interface AlipayCallback { void onSuccess(String result); void onFailure(String code, String message); } }5.3 Unity集成创建C#桥接类public class AlipayWrapper : MonoBehaviour { private static AlipayWrapper _instance; public static AlipayWrapper Instance { get { if (_instance null) { GameObject go new GameObject(AlipayWrapper); _instance go.AddComponentAlipayWrapper(); DontDestroyOnLoad(go); } return _instance; } } public void Pay(string orderInfo, Actionstring onSuccess, Actionstring, string onFailure) { #if UNITY_ANDROID !UNITY_EDITOR using (AndroidJavaClass unityPlayer new AndroidJavaClass(com.unity3d.player.UnityPlayer)) { using (AndroidJavaObject currentActivity unityPlayer.GetStaticAndroidJavaObject(currentActivity)) { using (AndroidJavaObject alipayService new AndroidJavaObject(com.example.AlipayService, currentActivity)) { alipayService.Call(pay, orderInfo, new AlipayCallbackProxy(onSuccess, onFailure)); } } } #endif } private class AlipayCallbackProxy : AndroidJavaProxy { private Actionstring _onSuccess; private Actionstring, string _onFailure; public AlipayCallbackProxy(Actionstring onSuccess, Actionstring, string onFailure) : base(com.example.AlipayService$AlipayCallback) { _onSuccess onSuccess; _onFailure onFailure; } public void onSuccess(string result) { UnityMainThreadDispatcher.Instance.Enqueue(() _onSuccess?.Invoke(result)); } public void onFailure(string code, string message) { UnityMainThreadDispatcher.Instance.Enqueue(() _onFailure?.Invoke(code, message)); } } }在Unity中使用public class PaymentManager : MonoBehaviour { public void StartPayment() { string orderInfo GenerateOrderInfo(); AlipayWrapper.Instance.Pay( orderInfo, result { Debug.Log(Payment success: result); // 处理支付成功逻辑 }, (code, message) { Debug.LogError($Payment failed: {code} - {message}); // 处理支付失败逻辑 } ); } private string GenerateOrderInfo() { // 生成订单信息 return ...; } }5.4 注意事项Proguard配置 在proguard-rules.pro中添加规则防止支付SDK被混淆-keep class com.alipay.** { *; } -dontwarn com.alipay.**多渠道打包 如果游戏需要发布到多个渠道每个渠道可能有不同的支付配置可以通过gradle的productFlavors实现android { flavorDimensions channel productFlavors { googleplay { dimension channel // Google Play特定配置 } huawei { dimension channel // 华为渠道特定配置 } } }签名验证 支付结果需要做签名验证防止伪造支付结果public boolean verifyResult(String signedData, String sign) { try { PublicKey publicKey getPublicKey(); Signature signature Signature.getInstance(SHA1WithRSA); signature.initVerify(publicKey); signature.update(signedData.getBytes(UTF-8)); return signature.verify(Base64.decode(sign, Base64.DEFAULT)); } catch (Exception e) { e.printStackTrace(); } return false; }通过这个完整案例我们可以看到Unity与Android原生代码如何协同工作实现复杂的平台特定功能。掌握这些技能后Unity开发者将不再受限于引擎提供的功能能够自由扩展应用的能力边界。
Unity开发者必备的Android原生开发指南
发布时间:2026/7/16 14:06:21
1. 为什么Unity开发者需要了解Android开发作为一名长期使用Unity引擎的游戏开发者我最初也和很多人一样认为掌握了Unity就足够应对所有平台的需求。直到第一次遇到需要接入第三方Android SDK时才意识到原生开发知识的重要性。Unity虽然提供了跨平台的能力但在实际项目开发中特别是涉及到平台特定功能时Android原生开发知识往往能帮助我们解决很多棘手问题。Android开发对Unity程序员的价值主要体现在以下几个方面首先当我们需要接入各种第三方服务时如支付SDK、广告SDK、社交分享等这些SDK通常都是以Android原生库的形式提供。虽然有些服务提供了Unity插件但往往功能不完整或更新滞后。掌握Android开发知识可以让我们直接使用原生SDK的全部功能。其次性能优化方面了解Android原生开发可以帮助我们更好地管理内存、优化渲染效率。比如通过原生代码实现某些计算密集型任务可以显著提升性能。我曾经在一个项目中通过将部分物理计算移到原生层使帧率提升了近30%。再者当我们需要实现一些Unity未提供的平台特性时如后台服务、通知管理、传感器深度使用等原生开发知识就变得不可或缺。特别是在开发AR应用时往往需要直接调用Android的Camera2 API来获取更精细的相机控制。最后调试和问题排查能力也会大幅提升。当游戏在Android设备上出现崩溃或异常行为时能够读懂logcat日志、理解Android系统机制可以快速定位问题根源。记得有一次我们的游戏在某些设备上启动即崩溃通过分析原生堆栈信息发现是缺少必要的权限声明这个问题在Unity日志中完全没有体现。2. Android开发环境快速搭建2.1 Android Studio安装与配置对于Unity开发者来说Android Studio是必不可少的工具。虽然Unity内置了Android打包功能但当我们涉及到原生代码开发或调试时Android Studio提供的完整工具链会大大提升效率。安装Android Studio的第一步是前往官网下载适合自己操作系统的版本。安装过程中有几个关键点需要注意确保勾选Android Virtual Device选项虽然我们主要做Unity开发可能用不上模拟器但完整安装可以避免后续可能出现的问题。SDK组件选择上建议至少安装以下版本Android SDK Platform 29对应Android 10Android SDK Build-Tools 29.0.3NDK最新稳定版CMake如果涉及原生代码安装路径最好选择没有空格和特殊字符的目录比如直接放在C:\Android\这样的路径下。我曾经遇到因为路径包含空格导致gradle构建失败的问题。安装完成后首次启动Android Studio会进行一些初始化设置。这里有几个实用建议在Preferences Appearance Behavior System Settings Android SDK中添加一个国内镜像源如腾讯或阿里云的镜像可以显著加快SDK下载速度。在Preferences Editor Code Style中将Java和XML的代码风格设置为Project这样与Unity生成的代码风格保持一致。建议安装以下插件ADB Idea简化ADB操作.ignore管理.gitignore文件Gradle Dependencies Helper可视化查看依赖关系2.2 Unity与Android Studio的协作配置要让Unity和Android Studio良好协作需要进行一些配置在Unity的Preferences External Tools中设置Android SDK和JDK的路径。这里要特别注意Unity对JDK版本有一定要求通常Java 8是最兼容的选择。如果项目中使用NDK比如有C插件也需要在这里指定NDK路径。建议使用Unity Hub安装的NDK版本以确保兼容性。创建一个简单的批处理脚本或shell脚本用于在Unity和Android Studio之间同步代码。基本思路是将Unity项目的Assets/Plugins/Android目录同步到Android Studio项目构建完成后将生成的aar/jar文件复制回Unity项目我曾经写过一个简单的Python脚本实现这个功能大大提升了开发效率。关键代码如下import shutil import os # 配置路径 unity_project path/to/unity/Assets/Plugins/Android android_studio_project path/to/androidstudio/app # 同步文件 def sync_files(): # 复制Android Studio输出到Unity for file in os.listdir(os.path.join(android_studio_project, build/outputs/aar)): if file.endswith(.aar): shutil.copy( os.path.join(android_studio_project, build/outputs/aar, file), os.path.join(unity_project, libs) ) # 复制其他必要文件 # ...3. Unity与Android交互的核心机制3.1 Unity调用Android原生代码Unity提供了AndroidJavaClass和AndroidJavaObject这两个类来实现与Android原生代码的交互。这种机制本质上是通过JNIJava Native Interface实现的。基本调用模式如下// 调用静态方法 using (AndroidJavaClass jc new AndroidJavaClass(com.example.MyClass)) { jc.CallStatic(staticMethodName, parameter); } // 调用实例方法 using (AndroidJavaObject jo new AndroidJavaObject(com.example.MyClass)) { jo.Call(instanceMethodName, parameter); }在实际项目中有几点需要特别注意方法签名必须完全匹配。Android是强类型语言如果参数类型不匹配会导致调用失败。我曾经因为传递了一个int参数而Java端期望的是long调试了很久才发现问题。复杂数据类型的传递需要使用AndroidJavaProxy或实现特定的接口。比如要传递一个回调函数可以这样实现public class MyCallback : AndroidJavaProxy { public MyCallback() : base(com.example.CallbackInterface) {} public void onResult(string result) { // 处理回调 } } // 使用回调 jo.Call(setCallback, new MyCallback());线程安全问题。Unity的主线程和Android的UI线程是不同的如果需要在Android端更新UI必须确保代码运行在UI线程上。可以通过runOnUiThread实现// Android端代码 public void showToast(final String message) { runOnUiThread(new Runnable() { Override public void run() { Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); } }); }3.2 Android调用Unity代码Android原生代码也可以调用Unity中的方法这主要通过UnityPlayer.UnitySendMessage实现。在Unity中需要有一个GameObject挂载接收消息的脚本public class NativeMessageReceiver : MonoBehaviour { void OnMessage(string message) { Debug.Log(Received from native: message); } }然后在Android端可以这样调用UnityPlayer.UnitySendMessage(GameObjectName, OnMessage, Hello from Android);这种通信方式有几个限制需要注意只能传递字符串参数。如果需要传递复杂数据需要序列化为JSON字符串。性能开销较大。频繁调用会影响游戏性能建议将多次调用合并为一次。不是实时调用。消息会被放入队列Unity在主线程的下一个更新周期处理。在实际项目中我通常会建立一个消息总线系统来处理原生调用基本结构如下public class NativeMessageBus : MonoBehaviour { private static NativeMessageBus _instance; public static NativeMessageBus Instance { get { if (_instance null) { GameObject go new GameObject(NativeMessageBus); _instance go.AddComponentNativeMessageBus(); DontDestroyOnLoad(go); } return _instance; } } private Dictionarystring, Actionstring _handlers new Dictionarystring, Actionstring(); public void RegisterHandler(string messageType, Actionstring handler) { _handlers[messageType] handler; } // 由Android原生调用 private void OnNativeMessage(string json) { NativeMessage msg JsonUtility.FromJsonNativeMessage(json); if (_handlers.TryGetValue(msg.type, out Actionstring handler)) { handler.Invoke(msg.data); } } [System.Serializable] private class NativeMessage { public string type; public string data; } }4. 常见问题与解决方案4.1 插件集成问题排查在集成Android插件到Unity项目时经常会遇到各种问题。根据我的经验90%的问题都集中在以下几个方面Manifest合并冲突当多个插件都修改AndroidManifest.xml时可能会出现属性冲突。解决方法包括使用tools:replace属性明确指定要替换的属性在Unity的Assets/Plugins/Android下创建manifest-merger.properties文件配置合并规则手动合并所有插件的Manifest文件重复类定义当不同插件包含相同的类时会导致冲突。可以通过以下方式解决使用proguard规则排除重复类修改插件代码改变包名联系插件提供商获取兼容版本资源冲突当不同插件使用相同的资源ID时会出现问题。解决方法在build.gradle中启用资源前缀android { resourcePrefix plugin1_ }手动修改资源文件名添加前缀Native库冲突特别是当多个插件提供相同架构的.so文件时。可以只保留需要的架构如只保留armeabi-v7a合并.so文件需要一定技术能力4.2 性能优化建议在Unity和Android混合开发中性能优化需要特别注意以下几点JNI调用优化减少跨语言调用次数批量处理数据缓存Java类和方法IDprivate static AndroidJavaClass _utilityClass; private static IntPtr _methodID; [RuntimeInitializeOnLoadMethod] private static void Initialize() { _utilityClass new AndroidJavaClass(com.example.Utility); _methodID AndroidJNIHelper.GetMethodID(_utilityClass.GetRawClass(), expensiveMethod, ()V); } public static void CallExpensiveMethod() { IntPtr args IntPtr.Zero; AndroidJNI.CallStaticVoidMethod(_utilityClass.GetRawClass(), _methodID, args); }内存管理及时释放AndroidJavaObject和AndroidJavaClass实例避免在频繁调用的方法中创建临时Java对象使用AndroidJNI直接调用替代高级封装减少开销线程管理耗时原生操作放在后台线程UI更新确保在主线程执行使用Android的Handler或Unity的MainThreadDispatcher协调线程渲染性能合理设置SurfaceView的格式和参数避免频繁切换GL上下文使用多线程渲染如果设备支持4.3 调试技巧有效的调试可以节省大量开发时间。以下是我总结的一些实用技巧Logcat过滤adb logcat -s Unity DEBUG AndroidRuntime这个命令可以只显示Unity、DEBUG标签和崩溃日志。符号化原生崩溃 当发生原生崩溃时需要使用ndk-stack工具解析堆栈adb logcat | ndk-stack -sym path/to/symbolsUnity-Android双向调试在Android Studio中调试Java代码在Visual Studio中调试C#代码使用LLDB调试原生代码内存分析Android Studio的Profiler工具Unity的Memory Profileradb shell dumpsys meminfo自动化测试 编写简单的UI自动化测试可以快速验证基本功能Test public void testUnityActivityLaunch() { ActivityScenarioUnityPlayerActivity scenario ActivityScenario.launch(UnityPlayerActivity.class); onView(withId(R.id.unitySurfaceView)).check(matches(isDisplayed())); }5. 实战案例接入支付SDK让我们通过一个实际案例 - 接入支付宝SDK来综合运用前面介绍的知识。5.1 准备工作从支付宝开放平台下载最新的SDK通常包含alipaySdk.aar核心库AndroidManifest.xml声明必要的组件和权限说明文档在Android Studio中创建新模块选择Import .JAR/.AAR Package指定alipaySdk.aar文件位置模块名设置为alipay配置依赖 在app模块的build.gradle中添加dependencies { implementation project(:alipay) }5.2 实现支付功能创建支付服务类public class AlipayService { private Activity mActivity; public AlipayService(Activity activity) { this.mActivity activity; } public void pay(String orderInfo, final AlipayCallback callback) { Runnable payRunnable new Runnable() { Override public void run() { PayTask alipay new PayTask(mActivity); MapString, String result alipay.payV2(orderInfo, true); Message msg new Message(); msg.what SDK_PAY_FLAG; msg.obj result; mHandler.sendMessage(msg); } }; Thread payThread new Thread(payRunnable); payThread.start(); } private static final int SDK_PAY_FLAG 1; private Handler mHandler new Handler(Looper.getMainLooper()) { Override public void handleMessage(Message msg) { if (msg.what SDK_PAY_FLAG) { SuppressWarnings(unchecked) PayResult payResult new PayResult((MapString, String) msg.obj); String resultInfo payResult.getResult(); String resultStatus payResult.getResultStatus(); if (TextUtils.equals(resultStatus, 9000)) { callback.onSuccess(resultInfo); } else { callback.onFailure(resultStatus, resultInfo); } } } }; public interface AlipayCallback { void onSuccess(String result); void onFailure(String code, String message); } }5.3 Unity集成创建C#桥接类public class AlipayWrapper : MonoBehaviour { private static AlipayWrapper _instance; public static AlipayWrapper Instance { get { if (_instance null) { GameObject go new GameObject(AlipayWrapper); _instance go.AddComponentAlipayWrapper(); DontDestroyOnLoad(go); } return _instance; } } public void Pay(string orderInfo, Actionstring onSuccess, Actionstring, string onFailure) { #if UNITY_ANDROID !UNITY_EDITOR using (AndroidJavaClass unityPlayer new AndroidJavaClass(com.unity3d.player.UnityPlayer)) { using (AndroidJavaObject currentActivity unityPlayer.GetStaticAndroidJavaObject(currentActivity)) { using (AndroidJavaObject alipayService new AndroidJavaObject(com.example.AlipayService, currentActivity)) { alipayService.Call(pay, orderInfo, new AlipayCallbackProxy(onSuccess, onFailure)); } } } #endif } private class AlipayCallbackProxy : AndroidJavaProxy { private Actionstring _onSuccess; private Actionstring, string _onFailure; public AlipayCallbackProxy(Actionstring onSuccess, Actionstring, string onFailure) : base(com.example.AlipayService$AlipayCallback) { _onSuccess onSuccess; _onFailure onFailure; } public void onSuccess(string result) { UnityMainThreadDispatcher.Instance.Enqueue(() _onSuccess?.Invoke(result)); } public void onFailure(string code, string message) { UnityMainThreadDispatcher.Instance.Enqueue(() _onFailure?.Invoke(code, message)); } } }在Unity中使用public class PaymentManager : MonoBehaviour { public void StartPayment() { string orderInfo GenerateOrderInfo(); AlipayWrapper.Instance.Pay( orderInfo, result { Debug.Log(Payment success: result); // 处理支付成功逻辑 }, (code, message) { Debug.LogError($Payment failed: {code} - {message}); // 处理支付失败逻辑 } ); } private string GenerateOrderInfo() { // 生成订单信息 return ...; } }5.4 注意事项Proguard配置 在proguard-rules.pro中添加规则防止支付SDK被混淆-keep class com.alipay.** { *; } -dontwarn com.alipay.**多渠道打包 如果游戏需要发布到多个渠道每个渠道可能有不同的支付配置可以通过gradle的productFlavors实现android { flavorDimensions channel productFlavors { googleplay { dimension channel // Google Play特定配置 } huawei { dimension channel // 华为渠道特定配置 } } }签名验证 支付结果需要做签名验证防止伪造支付结果public boolean verifyResult(String signedData, String sign) { try { PublicKey publicKey getPublicKey(); Signature signature Signature.getInstance(SHA1WithRSA); signature.initVerify(publicKey); signature.update(signedData.getBytes(UTF-8)); return signature.verify(Base64.decode(sign, Base64.DEFAULT)); } catch (Exception e) { e.printStackTrace(); } return false; }通过这个完整案例我们可以看到Unity与Android原生代码如何协同工作实现复杂的平台特定功能。掌握这些技能后Unity开发者将不再受限于引擎提供的功能能够自由扩展应用的能力边界。